/**
   * @param pp PiecewisePolynomialResult
   * @param xKey
   * @return Values of piecewise polynomial functions at xKey When _dim in PiecewisePolynomialResult
   *     is greater than 1, i.e., the struct contains multiple splines, an element in the return
   *     values corresponds to each spline
   */
  public DoubleMatrix1D evaluate(final PiecewisePolynomialResult pp, final double xKey) {
    ArgumentChecker.notNull(pp, "pp");

    ArgumentChecker.isFalse(Double.isNaN(xKey), "xKey containing NaN");
    ArgumentChecker.isFalse(Double.isInfinite(xKey), "xKey containing Infinity");

    final double[] knots = pp.getKnots().getData();
    final int nKnots = knots.length;
    final DoubleMatrix2D coefMatrix = pp.getCoefMatrix();
    final int dim = pp.getDimensions();

    double[] res = new double[dim];

    int indicator = FunctionUtils.getLowerBoundIndex(knots, xKey);
    if (indicator == nKnots - 1) {
      indicator--; // there is 1 less interval that knots
    }

    for (int j = 0; j < dim; ++j) {
      final double[] coefs = coefMatrix.getRowVector(dim * indicator + j, false).getData();
      res[j] = getValue(coefs, xKey, knots[indicator]);

      ArgumentChecker.isFalse(Double.isInfinite(res[j]), "Too large input");
      ArgumentChecker.isFalse(Double.isNaN(res[j]), "Too large input");
    }

    return new DoubleMatrix1D(res, false);
  }
 /**
  * Calculate the instrument sensitivity from the yield sensitivity, the jacobian matrix and the
  * coupon sensitivity.
  *
  * @param curveSensitivities The sensitivity to points of the yield curve.
  * @param curves The curve bundle.
  * @param couponSensitivity The sensitivity
  * @param jacobian The present value coupon sensitivity.
  * @return The instrument quote/rate sensitivity.
  */
 public DoubleMatrix1D calculateFromPresentValue(
     final Map<String, List<DoublesPair>> curveSensitivities,
     final YieldCurveBundle curves,
     final DoubleMatrix1D couponSensitivity,
     final DoubleMatrix2D jacobian) {
   final DoubleArrayList resultList = new DoubleArrayList();
   for (final String curveName : curves.getAllNames()) {
     final DoubleMatrix1D nodeSensitivity =
         new DoubleMatrix1D(
             (_parameterSensitivityCalculator.pointToParameterSensitivity(
                     curveSensitivities.get(curveName), curves.getCurve(curveName)))
                 .toArray(new Double[0]));
     final int n = nodeSensitivity.getNumberOfElements();
     final DoubleMatrix2D inverseJacobian = MATRIX_ALGEBRA.getInverse(jacobian);
     for (int i = 0; i < n; i++) {
       double sum = 0;
       for (int j = 0; j < n; j++) {
         sum +=
             -couponSensitivity.getEntry(i)
                 * inverseJacobian.getEntry(j, i)
                 * nodeSensitivity.getEntry(j);
       }
       resultList.add(sum);
     }
   }
   return new DoubleMatrix1D(resultList.toDoubleArray());
 }
 /** Tests solve AX = B from A and B. */
 public void solveMatrix() {
   final CholeskyDecompositionResult result = CDOG.evaluate(A5);
   double[][] b = new double[][] {{1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0}, {4.0, -2.0}, {-1.0, -1.0}};
   DoubleMatrix2D x = result.solve(new DoubleMatrix2D(b));
   DoubleMatrix2D ax = (DoubleMatrix2D) ALGEBRA.multiply(A5, x);
   ArrayAsserts.assertArrayEquals(
       "Cholesky decomposition OpenGamma - solve", b[0], ax.getData()[0], 1.0E-10);
   ArrayAsserts.assertArrayEquals(
       "Cholesky decomposition OpenGamma - solve", b[1], ax.getData()[1], 1.0E-10);
 }
 @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);
 }
  /**
   * @param pp PiecewisePolynomialResult
   * @param xKeys
   * @return Values of piecewise polynomial functions at xKeys When _dim in
   *     PiecewisePolynomialResult is greater than 1, i.e., the struct contains multiple piecewise
   *     polynomials, one element of return vector of DoubleMatrix2D corresponds to each piecewise
   *     polynomial
   */
  public DoubleMatrix2D[] evaluate(final PiecewisePolynomialResult pp, final double[][] xKeys) {
    ArgumentChecker.notNull(pp, "pp");
    ArgumentChecker.notNull(xKeys, "xKeys");

    final int keyLength = xKeys[0].length;
    final int keyDim = xKeys.length;
    for (int j = 0; j < keyDim; ++j) {
      for (int i = 0; i < keyLength; ++i) {
        ArgumentChecker.isFalse(Double.isNaN(xKeys[j][i]), "xKeys containing NaN");
        ArgumentChecker.isFalse(Double.isInfinite(xKeys[j][i]), "xKeys containing Infinity");
      }
    }

    final double[] knots = pp.getKnots().getData();
    final int nKnots = knots.length;
    final DoubleMatrix2D coefMatrix = pp.getCoefMatrix();
    final int dim = pp.getDimensions();

    double[][][] res = new double[dim][keyDim][keyLength];

    for (int k = 0; k < dim; ++k) {
      for (int l = 0; l < keyDim; ++l) {
        for (int j = 0; j < keyLength; ++j) {
          int indicator = 0;
          if (xKeys[l][j] < knots[1]) {
            indicator = 0;
          } else {
            for (int i = 1; i < nKnots - 1; ++i) {
              if (knots[i] <= xKeys[l][j]) {
                indicator = i;
              }
            }
          }

          final double[] coefs = coefMatrix.getRowVector(dim * indicator + k, false).getData();
          res[k][l][j] = getValue(coefs, xKeys[l][j], knots[indicator]);
          ArgumentChecker.isFalse(Double.isInfinite(res[k][l][j]), "Too large input");
          ArgumentChecker.isFalse(Double.isNaN(res[k][l][j]), "Too large input");
        }
      }
    }

    DoubleMatrix2D[] resMat = new DoubleMatrix2D[dim];
    for (int i = 0; i < dim; ++i) {
      resMat[i] = DoubleMatrix2D.noCopy(res[i]);
    }

    return resMat;
  }
Esempio n. 6
0
 @Override
 protected void buildMessage(
     final FudgeSerializer serializer,
     final MutableFudgeMsg message,
     final DoubleMatrix2D object) {
   serializer.addToMessage(message, DATA_FIELD_NAME, null, object.getData());
 }
  /**
   * @param pp
   * @param xKeys
   * @return Second derivatives of piecewise polynomial functions at xKeys When _dim in
   *     PiecewisePolynomialResult is greater than 1, i.e., the struct contains multiple piecewise
   *     polynomials, a row vector of return value corresponds to each piecewise polynomial
   */
  public DoubleMatrix2D differentiateTwice(
      final PiecewisePolynomialResult pp, final double[] xKeys) {
    ArgumentChecker.notNull(pp, "pp");
    ArgumentChecker.isFalse(pp.getOrder() < 3, "polynomial degree < 2");

    final double[][] coefs = pp.getCoefMatrix().getData();
    final double[] knots = pp.getKnots().getData();

    final int nKnots = pp.getNumberOfIntervals() + 1;
    final int nCoefs = pp.getOrder();
    final int dim = pp.getDimensions();

    double[][] res = new double[dim * (nKnots - 1)][nCoefs - 2];
    for (int i = 0; i < dim * (nKnots - 1); ++i) {
      Arrays.fill(res[i], 0.);
    }

    for (int i = 0; i < dim * (nKnots - 1); ++i) {
      for (int j = 0; j < nCoefs - 2; ++j) {
        res[i][j] = coefs[i][j] * (nCoefs - j - 1) * (nCoefs - j - 2);
      }
    }

    PiecewisePolynomialResult ppDiff =
        new PiecewisePolynomialResult(
            new DoubleMatrix1D(knots), DoubleMatrix2D.noCopy(res), nCoefs - 1, pp.getDimensions());

    return evaluate(ppDiff, xKeys);
  }
  /**
   * @param pp PiecewisePolynomialResult
   * @param initialKey
   * @param xKeys
   * @return Integral of piecewise polynomial between initialKey and xKeys
   */
  public DoubleMatrix1D integrate(
      final PiecewisePolynomialResult pp, final double initialKey, final double[] xKeys) {
    ArgumentChecker.notNull(pp, "pp");
    ArgumentChecker.notNull(xKeys, "xKeys");

    ArgumentChecker.isFalse(Double.isNaN(initialKey), "initialKey containing NaN");
    ArgumentChecker.isFalse(Double.isInfinite(initialKey), "initialKey containing Infinity");
    ArgumentChecker.isTrue(pp.getDimensions() == 1, "Dimension should be 1");

    final double[] knots = pp.getKnots().getData();
    final int nCoefs = pp.getOrder();
    final int nKnots = pp.getNumberOfIntervals() + 1;
    final double[][] coefMatrix = pp.getCoefMatrix().getData();

    double[][] res = new double[nKnots - 1][nCoefs + 1];
    for (int i = 0; i < nKnots - 1; ++i) {
      Arrays.fill(res[i], 0.);
    }

    for (int i = 0; i < nKnots - 1; ++i) {
      for (int j = 0; j < nCoefs; ++j) {
        res[i][j] = coefMatrix[i][j] / (nCoefs - j);
      }
    }

    double[] constTerms = new double[nKnots - 1];
    Arrays.fill(constTerms, 0.);

    int indicator = 0;
    if (initialKey <= knots[1]) {
      indicator = 0;
    } else {
      for (int i = 1; i < nKnots - 1; ++i) {
        if (knots[i] < initialKey) {
          indicator = i;
        }
      }
    }

    double sum = getValue(res[indicator], initialKey, knots[indicator]);
    for (int i = indicator; i < nKnots - 2; ++i) {
      constTerms[i + 1] = constTerms[i] + getValue(res[i], knots[i + 1], knots[i]) - sum;
      sum = 0.;
    }

    constTerms[indicator] = -getValue(res[indicator], initialKey, knots[indicator]);
    for (int i = indicator - 1; i > -1; --i) {
      constTerms[i] = constTerms[i + 1] - getValue(res[i], knots[i + 1], knots[i]);
    }
    for (int i = 0; i < nKnots - 1; ++i) {
      res[i][nCoefs] = constTerms[i];
    }

    final PiecewisePolynomialResult ppInt =
        new PiecewisePolynomialResult(
            new DoubleMatrix1D(knots), DoubleMatrix2D.noCopy(res), nCoefs + 1, 1);

    return new DoubleMatrix1D(evaluate(ppInt, xKeys).getData()[0]);
  }
 private void checkEquals(final DoubleMatrix2D x, final DoubleMatrix2D y) {
   final int n = x.getNumberOfRows();
   final int m = x.getNumberOfColumns();
   assertEquals(n, y.getNumberOfRows());
   assertEquals(m, y.getNumberOfColumns());
   for (int i = 0; i < n; i++) {
     for (int j = 0; j < m; j++) {
       assertEquals(x.getEntry(i, j), y.getEntry(i, j), EPS);
     }
   }
 }
Esempio n. 10
0
  /**
   * Construct from DoubleMatrix2D type
   *
   * @param aMatrix is a DoubleMatrix2D
   */
  public SparseCoordinateFormatMatrix(final DoubleMatrix2D aMatrix) {
    Validate.notNull(aMatrix);

    // get number of elements
    _els = aMatrix.getNumberOfElements();

    // tmp arrays, in case we get in a fully populated matrix, intelligent design upstream should
    // ensure that this is overkill!
    double[] valuesTmp = new double[_els];
    int[] xTmp = new int[_els];
    int[] yTmp = new int[_els];

    // we need unwind the array aMatrix into coordinate form
    int localmaxEntriesInARow;
    _maxEntriesInARow = -1; // set max entries in a column negative, so that maximiser will work
    int ptr = 0;
    for (int i = 0; i < aMatrix.getNumberOfRows(); i++) {
      localmaxEntriesInARow = 0;
      for (int j = 0; j < aMatrix.getNumberOfColumns(); j++) {
        if (Double.doubleToLongBits(aMatrix.getEntry(i, j)) != 0L) {
          xTmp[ptr] = j;
          yTmp[ptr] = i;
          valuesTmp[ptr] = aMatrix.getEntry(i, j);
          ptr++;
          localmaxEntriesInARow++;
        }
      }
      if (localmaxEntriesInARow > _maxEntriesInARow) {
        _maxEntriesInARow = localmaxEntriesInARow;
      }
    }

    _values = Arrays.copyOfRange(valuesTmp, 0, ptr);
    _x = Arrays.copyOfRange(xTmp, 0, ptr);
    _y = Arrays.copyOfRange(yTmp, 0, ptr);
    _rows = aMatrix.getNumberOfRows();
    _cols = aMatrix.getNumberOfColumns();
  }
 /**
  * The method calibrates a LMM on a set of vanilla swaption priced with SABR. The set of vanilla
  * swaptions is given by the CalibrationType. The curve and SABR sensitivities of the original
  * swaption are calculated with LMM re-calibration. Used mainly for performance test purposes as
  * the output is hybrid list.
  *
  * @param swaption The swaption.
  * @param curves The curves and SABR data.
  * @return The results (returned as a list of objects) [0] the present value, [1] the present
  *     curve sensitivity, [2] the present value SABR sensitivity.
  */
 public List<Object> presentValueCurveSABRSensitivity(
     final SwaptionPhysicalFixedIbor swaption, final SABRInterestRateDataBundle curves) {
   ArgumentChecker.notNull(swaption, "swaption");
   ArgumentChecker.notNull(curves, "curves");
   // TODO: Create a way to chose the LMM base parameters (displacement, mean reversion,
   // volatility).
   final LiborMarketModelDisplacedDiffusionParameters lmmParameters =
       LiborMarketModelDisplacedDiffusionParameters.from(
           swaption,
           DEFAULT_DISPLACEMENT,
           DEFAULT_MEAN_REVERSION,
           new VolatilityLMMAngle(DEFAULT_ANGLE, DEFAULT_DISPLACEMENT));
   final SwaptionPhysicalLMMDDSuccessiveRootFinderCalibrationObjective objective =
       new SwaptionPhysicalLMMDDSuccessiveRootFinderCalibrationObjective(lmmParameters);
   final SwaptionPhysicalLMMDDSuccessiveRootFinderCalibrationEngine calibrationEngine =
       new SwaptionPhysicalLMMDDSuccessiveRootFinderCalibrationEngine(objective);
   final SwaptionPhysicalFixedIbor[] swaptionCalibration =
       METHOD_BASKET.calibrationBasketFixedLegPeriod(swaption);
   calibrationEngine.addInstrument(swaptionCalibration, METHOD_SWAPTION_SABR);
   calibrationEngine.calibrate(curves);
   final LiborMarketModelDisplacedDiffusionDataBundle lmmBundle =
       new LiborMarketModelDisplacedDiffusionDataBundle(lmmParameters, curves);
   // Risks
   final int nbCal = swaptionCalibration.length;
   final int nbFact = lmmParameters.getNbFactor();
   final List<Integer> instrumentIndex = calibrationEngine.getInstrumentIndex();
   final double[] dPvAmdLambda = new double[nbCal];
   final double[][][] dPvCaldGamma = new double[nbCal][][];
   final double[][] dPvCaldLambda = new double[nbCal][nbCal];
   final PresentValueSABRSensitivityDataBundle[] dPvCaldSABR =
       new PresentValueSABRSensitivityDataBundle[nbCal];
   InterestRateCurveSensitivity pvcsCal =
       METHOD_SWAPTION_LMM.presentValueCurveSensitivity(swaption, lmmBundle);
   pvcsCal = pvcsCal.cleaned();
   final double[][] dPvAmdGamma =
       METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaption, lmmBundle);
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     dPvCaldGamma[loopcal] =
         METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaptionCalibration[loopcal], lmmBundle);
   }
   // Multiplicative-factor sensitivity
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     for (int loopperiod = instrumentIndex.get(loopcal);
         loopperiod < instrumentIndex.get(loopcal + 1);
         loopperiod++) {
       for (int loopfact = 0; loopfact < nbFact; loopfact++) {
         dPvAmdLambda[loopcal] +=
             dPvAmdGamma[loopperiod][loopfact]
                 * lmmParameters.getVolatility()[loopperiod][loopfact];
       }
     }
   }
   for (int loopcal1 = 0; loopcal1 < nbCal; loopcal1++) {
     for (int loopcal2 = 0; loopcal2 < nbCal; loopcal2++) {
       for (int loopperiod = instrumentIndex.get(loopcal2);
           loopperiod < instrumentIndex.get(loopcal2 + 1);
           loopperiod++) {
         for (int loopfact = 0; loopfact < nbFact; loopfact++) {
           dPvCaldLambda[loopcal1][loopcal2] +=
               dPvCaldGamma[loopcal1][loopperiod][loopfact]
                   * lmmParameters.getVolatility()[loopperiod][loopfact];
         }
       }
     }
   }
   final InterestRateCurveSensitivity[] pvcsCalBase = new InterestRateCurveSensitivity[nbCal];
   final InterestRateCurveSensitivity[] pvcsCalCal = new InterestRateCurveSensitivity[nbCal];
   final InterestRateCurveSensitivity[] pvcsCalDiff = new InterestRateCurveSensitivity[nbCal];
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     pvcsCalBase[loopcal] =
         METHOD_SWAPTION_SABR.presentValueCurveSensitivity(swaptionCalibration[loopcal], curves);
     pvcsCalBase[loopcal] = pvcsCalBase[loopcal].cleaned();
     pvcsCalCal[loopcal] =
         METHOD_SWAPTION_LMM.presentValueCurveSensitivity(swaptionCalibration[loopcal], lmmBundle);
     pvcsCalCal[loopcal] = pvcsCalCal[loopcal].cleaned();
     pvcsCalDiff[loopcal] = pvcsCalBase[loopcal].plus(pvcsCalCal[loopcal].multipliedBy(-1));
     pvcsCalDiff[loopcal] = pvcsCalDiff[loopcal].cleaned();
   }
   final CommonsMatrixAlgebra matrix = new CommonsMatrixAlgebra();
   final DoubleMatrix2D dPvCaldLambdaMatrix = new DoubleMatrix2D(dPvCaldLambda);
   final DoubleMatrix2D dPvCaldLambdaMatrixInverse = matrix.getInverse(dPvCaldLambdaMatrix);
   // SABR sensitivity
   final double[][] dPvCaldAlpha = new double[nbCal][nbCal];
   final double[][] dPvCaldRho = new double[nbCal][nbCal];
   final double[][] dPvCaldNu = new double[nbCal][nbCal];
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     dPvCaldSABR[loopcal] =
         METHOD_SWAPTION_SABR.presentValueSABRSensitivity(swaptionCalibration[loopcal], curves);
     final Set<DoublesPair> keySet = dPvCaldSABR[loopcal].getAlpha().getMap().keySet();
     final DoublesPair[] keys = keySet.toArray(new DoublesPair[keySet.size()]);
     dPvCaldAlpha[loopcal][loopcal] = dPvCaldSABR[loopcal].getAlpha().getMap().get(keys[0]);
     dPvCaldRho[loopcal][loopcal] = dPvCaldSABR[loopcal].getRho().getMap().get(keys[0]);
     dPvCaldNu[loopcal][loopcal] = dPvCaldSABR[loopcal].getNu().getMap().get(keys[0]);
   }
   final DoubleMatrix1D dPvAmdLambdaMatrix = new DoubleMatrix1D(dPvAmdLambda);
   final DoubleMatrix2D dPvCaldAlphaMatrix = new DoubleMatrix2D(dPvCaldAlpha);
   final DoubleMatrix2D dLambdadAlphaMatrix =
       (DoubleMatrix2D) matrix.multiply(dPvCaldLambdaMatrixInverse, dPvCaldAlphaMatrix);
   final DoubleMatrix2D dPvAmdAlphaMatrix =
       (DoubleMatrix2D)
           matrix.multiply(matrix.getTranspose(dLambdadAlphaMatrix), dPvAmdLambdaMatrix);
   final DoubleMatrix2D dPvCaldRhoMatrix = new DoubleMatrix2D(dPvCaldRho);
   final DoubleMatrix2D dLambdadRhoMatrix =
       (DoubleMatrix2D) matrix.multiply(dPvCaldLambdaMatrixInverse, dPvCaldRhoMatrix);
   final DoubleMatrix2D dPvAmdRhoMatrix =
       (DoubleMatrix2D)
           matrix.multiply(matrix.getTranspose(dLambdadRhoMatrix), dPvAmdLambdaMatrix);
   final DoubleMatrix2D dPvCaldNuMatrix = new DoubleMatrix2D(dPvCaldNu);
   final DoubleMatrix2D dLambdadNuMatrix =
       (DoubleMatrix2D) matrix.multiply(dPvCaldLambdaMatrixInverse, dPvCaldNuMatrix);
   final DoubleMatrix2D dPvAmdNuMatrix =
       (DoubleMatrix2D) matrix.multiply(matrix.getTranspose(dLambdadNuMatrix), dPvAmdLambdaMatrix);
   final double[] dPvAmdAlpha = matrix.getTranspose(dPvAmdAlphaMatrix).getData()[0];
   final double[] dPvAmdRho = matrix.getTranspose(dPvAmdRhoMatrix).getData()[0];
   final double[] dPvAmdNu = matrix.getTranspose(dPvAmdNuMatrix).getData()[0];
   // Storage in PresentValueSABRSensitivityDataBundle
   final PresentValueSABRSensitivityDataBundle pvss = new PresentValueSABRSensitivityDataBundle();
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     final DoublesPair expiryMaturity =
         DoublesPair.of(
             swaptionCalibration[loopcal].getTimeToExpiry(),
             swaptionCalibration[loopcal].getMaturityTime());
     pvss.addAlpha(expiryMaturity, dPvAmdAlpha[loopcal]);
     pvss.addRho(expiryMaturity, dPvAmdRho[loopcal]);
     pvss.addNu(expiryMaturity, dPvAmdNu[loopcal]);
   }
   // Curve sensitivity
   final InterestRateCurveSensitivity[] dLambdadC = new InterestRateCurveSensitivity[nbCal];
   for (int loopcal1 = 0; loopcal1 < nbCal; loopcal1++) {
     dLambdadC[loopcal1] = new InterestRateCurveSensitivity();
     for (int loopcal2 = 0; loopcal2 <= loopcal1; loopcal2++) {
       dLambdadC[loopcal1] =
           dLambdadC[loopcal1].plus(
               pvcsCalDiff[loopcal2].multipliedBy(
                   dPvCaldLambdaMatrixInverse.getEntry(loopcal1, loopcal2)));
     }
   }
   InterestRateCurveSensitivity pvcs = new InterestRateCurveSensitivity();
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     pvcs = pvcs.plus(dLambdadC[loopcal].multipliedBy(dPvAmdLambda[loopcal]));
   }
   pvcs = pvcs.plus(pvcsCal);
   pvcs = pvcs.cleaned();
   final List<Object> results = new ArrayList<>();
   results.add(
       CurrencyAmount.of(
           swaption.getCurrency(),
           METHOD_SWAPTION_LMM.presentValue(swaption, lmmBundle).getAmount()));
   results.add(pvcs);
   results.add(pvss);
   return results;
 }
 /**
  * The method calibrates a LMM on a set of vanilla swaption priced with SABR. The set of vanilla
  * swaptions is given by the CalibrationType. The curve sensitivities of the original swaption are
  * calculated with LMM re-calibration.
  *
  * @param swaption The swaption.
  * @param curves The curves and SABR data.
  * @return The present value curve sensitivities.
  */
 public InterestRateCurveSensitivity presentValueCurveSensitivity(
     final SwaptionPhysicalFixedIbor swaption, final SABRInterestRateDataBundle curves) {
   ArgumentChecker.notNull(swaption, "swaption");
   ArgumentChecker.notNull(curves, "curves");
   // TODO: Create a way to chose the LMM base parameters (displacement, mean reversion,
   // volatility).
   final LiborMarketModelDisplacedDiffusionParameters lmmParameters =
       LiborMarketModelDisplacedDiffusionParameters.from(
           swaption,
           DEFAULT_DISPLACEMENT,
           DEFAULT_MEAN_REVERSION,
           new VolatilityLMMAngle(DEFAULT_ANGLE, DEFAULT_DISPLACEMENT));
   final SwaptionPhysicalLMMDDSuccessiveRootFinderCalibrationObjective objective =
       new SwaptionPhysicalLMMDDSuccessiveRootFinderCalibrationObjective(lmmParameters);
   final SwaptionPhysicalLMMDDSuccessiveRootFinderCalibrationEngine calibrationEngine =
       new SwaptionPhysicalLMMDDSuccessiveRootFinderCalibrationEngine(objective);
   final SwaptionPhysicalFixedIbor[] swaptionCalibration =
       METHOD_BASKET.calibrationBasketFixedLegPeriod(swaption);
   calibrationEngine.addInstrument(swaptionCalibration, METHOD_SWAPTION_SABR);
   calibrationEngine.calibrate(curves);
   final LiborMarketModelDisplacedDiffusionDataBundle lmmBundle =
       new LiborMarketModelDisplacedDiffusionDataBundle(lmmParameters, curves);
   // Risks
   final int nbCal = swaptionCalibration.length;
   final int nbFact = lmmParameters.getNbFactor();
   final List<Integer> instrumentIndex = calibrationEngine.getInstrumentIndex();
   final double[] dPvAmdLambda = new double[nbCal];
   final double[][][] dPvCaldGamma = new double[nbCal][][];
   final double[][] dPvCaldLambda = new double[nbCal][nbCal];
   InterestRateCurveSensitivity pvcsCal =
       METHOD_SWAPTION_LMM.presentValueCurveSensitivity(swaption, lmmBundle);
   pvcsCal = pvcsCal.cleaned();
   final double[][] dPvAmdGamma =
       METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaption, lmmBundle);
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     dPvCaldGamma[loopcal] =
         METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaptionCalibration[loopcal], lmmBundle);
   }
   // Multiplicative-factor sensitivity
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     for (int loopperiod = instrumentIndex.get(loopcal);
         loopperiod < instrumentIndex.get(loopcal + 1);
         loopperiod++) {
       for (int loopfact = 0; loopfact < nbFact; loopfact++) {
         dPvAmdLambda[loopcal] +=
             dPvAmdGamma[loopperiod][loopfact]
                 * lmmParameters.getVolatility()[loopperiod][loopfact];
       }
     }
   }
   for (int loopcal1 = 0; loopcal1 < nbCal; loopcal1++) {
     for (int loopcal2 = 0; loopcal2 < nbCal; loopcal2++) {
       for (int loopperiod = instrumentIndex.get(loopcal2);
           loopperiod < instrumentIndex.get(loopcal2 + 1);
           loopperiod++) {
         for (int loopfact = 0; loopfact < nbFact; loopfact++) {
           dPvCaldLambda[loopcal1][loopcal2] +=
               dPvCaldGamma[loopcal1][loopperiod][loopfact]
                   * lmmParameters.getVolatility()[loopperiod][loopfact];
         }
       }
     }
   }
   final InterestRateCurveSensitivity[] pvcsCalBase = new InterestRateCurveSensitivity[nbCal];
   final InterestRateCurveSensitivity[] pvcsCalCal = new InterestRateCurveSensitivity[nbCal];
   final InterestRateCurveSensitivity[] pvcsCalDiff = new InterestRateCurveSensitivity[nbCal];
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     pvcsCalBase[loopcal] =
         METHOD_SWAPTION_SABR.presentValueCurveSensitivity(swaptionCalibration[loopcal], curves);
     pvcsCalBase[loopcal] = pvcsCalBase[loopcal].cleaned();
     pvcsCalCal[loopcal] =
         METHOD_SWAPTION_LMM.presentValueCurveSensitivity(swaptionCalibration[loopcal], lmmBundle);
     pvcsCalCal[loopcal] = pvcsCalCal[loopcal].cleaned();
     pvcsCalDiff[loopcal] = pvcsCalBase[loopcal].plus(pvcsCalCal[loopcal].multipliedBy(-1));
     pvcsCalDiff[loopcal] = pvcsCalDiff[loopcal].cleaned();
   }
   final CommonsMatrixAlgebra matrix = new CommonsMatrixAlgebra();
   final DoubleMatrix2D dPvCaldLambdaMatrix = new DoubleMatrix2D(dPvCaldLambda);
   final DoubleMatrix2D dPvCaldLambdaMatrixInverse = matrix.getInverse(dPvCaldLambdaMatrix);
   // Curve sensitivity
   final InterestRateCurveSensitivity[] dLambdadC = new InterestRateCurveSensitivity[nbCal];
   for (int loopcal1 = 0; loopcal1 < nbCal; loopcal1++) {
     dLambdadC[loopcal1] = new InterestRateCurveSensitivity();
     for (int loopcal2 = 0; loopcal2 <= loopcal1; loopcal2++) {
       dLambdadC[loopcal1] =
           dLambdadC[loopcal1].plus(
               pvcsCalDiff[loopcal2].multipliedBy(
                   dPvCaldLambdaMatrixInverse.getEntry(loopcal1, loopcal2)));
     }
   }
   InterestRateCurveSensitivity pvcsAdjust = new InterestRateCurveSensitivity();
   for (int loopcal = 0; loopcal < nbCal; loopcal++) {
     pvcsAdjust = pvcsAdjust.plus(dLambdadC[loopcal].multipliedBy(dPvAmdLambda[loopcal]));
   }
   pvcsAdjust = pvcsAdjust.cleaned();
   InterestRateCurveSensitivity pvcsTot = pvcsCal.plus(pvcsAdjust);
   pvcsTot = pvcsTot.cleaned();
   return pvcsTot;
 }
Esempio n. 13
0
 /**
  * @param x An OG 2D matrix of doubles, not null
  * @return A Colt 2D matrix
  */
 public static cern.colt.matrix.DoubleMatrix2D wrap(final DoubleMatrix2D x) {
   Validate.notNull(x, "x");
   return cern.colt.matrix.DoubleFactory2D.dense.make(x.getData());
 }
  @Override
  public PiecewisePolynomialResultsWithSensitivity interpolateWithSensitivity(
      final double[] xValues, final double[] yValues) {

    ArgumentChecker.notNull(xValues, "xValues");
    ArgumentChecker.notNull(yValues, "yValues");

    ArgumentChecker.isTrue(
        xValues.length == yValues.length | xValues.length + 2 == yValues.length,
        "(xValues length = yValues length) or (xValues length + 2 = yValues length)");
    ArgumentChecker.isTrue(xValues.length > 2, "Data points should be more than 2");

    final int nDataPts = xValues.length;
    final int yValuesLen = yValues.length;

    for (int i = 0; i < nDataPts; ++i) {
      ArgumentChecker.isFalse(Double.isNaN(xValues[i]), "xValues containing NaN");
      ArgumentChecker.isFalse(Double.isInfinite(xValues[i]), "xValues containing Infinity");
    }
    for (int i = 0; i < yValuesLen; ++i) {
      ArgumentChecker.isFalse(Double.isNaN(yValues[i]), "yValues containing NaN");
      ArgumentChecker.isFalse(Double.isInfinite(yValues[i]), "yValues containing Infinity");
    }

    for (int i = 0; i < nDataPts - 1; ++i) {
      for (int j = i + 1; j < nDataPts; ++j) {
        ArgumentChecker.isFalse(xValues[i] == xValues[j], "xValues should be distinct");
      }
    }

    double[] yValuesSrt = new double[nDataPts];
    if (nDataPts == yValuesLen) {
      yValuesSrt = Arrays.copyOf(yValues, nDataPts);
    } else {
      yValuesSrt = Arrays.copyOfRange(yValues, 1, nDataPts + 1);
    }

    final double[] intervals = _solver.intervalsCalculator(xValues);
    final double[] slopes = _solver.slopesCalculator(yValuesSrt, intervals);
    double[][] slopesSensitivity = _solver.slopeSensitivityCalculator(intervals);
    final DoubleMatrix1D[] firstWithSensitivity = new DoubleMatrix1D[nDataPts + 1];
    final DoubleMatrix1D[] secondWithSensitivity = new DoubleMatrix1D[nDataPts + 1];
    final PiecewisePolynomialResult result = _method.interpolate(xValues, yValues);

    ArgumentChecker.isTrue(result.getOrder() >= 3, "Primary interpolant should be degree >= 2");

    final double[] initialFirst = _function.differentiate(result, xValues).getData()[0];
    final double[] initialSecond = _function.differentiateTwice(result, xValues).getData()[0];
    double[] first = firstDerivativeCalculator(yValuesSrt, intervals, slopes, initialFirst);
    boolean modFirst = false;
    int k;
    double[] aValues = aValuesCalculator(slopes, first);
    double[] bValues = bValuesCalculator(slopes, first);
    double[][] intervalsA = getIntervalsA(intervals, slopes, first, bValues);
    double[][] intervalsB = getIntervalsB(intervals, slopes, first, aValues);
    while (modFirst == false) {
      k = 0;
      for (int i = 0; i < nDataPts - 2; ++i) {
        if (first[i + 1] > 0.) {
          if (intervalsA[i + 1][1] + Math.abs(intervalsA[i + 1][1]) * ERROR
                  < intervalsB[i][0] - Math.abs(intervalsB[i][0]) * ERROR
              | intervalsA[i + 1][0] - Math.abs(intervalsA[i + 1][0]) * ERROR
                  > intervalsB[i][1] + Math.abs(intervalsB[i][1]) * ERROR) {
            ++k;
            first[i + 1] = firstDerivativesRecalculator(intervals, slopes, aValues, bValues, i + 1);
          }
        }
      }
      if (k == 0) {
        modFirst = true;
      }
      aValues = aValuesCalculator(slopes, first);
      bValues = bValuesCalculator(slopes, first);
      intervalsA = getIntervalsA(intervals, slopes, first, bValues);
      intervalsB = getIntervalsB(intervals, slopes, first, aValues);
    }
    final double[] second = secondDerivativeCalculator(initialSecond, intervalsA, intervalsB);
    firstWithSensitivity[0] = new DoubleMatrix1D(first);
    secondWithSensitivity[0] = new DoubleMatrix1D(second);

    /*
     * Centered finite difference method is used for computing node sensitivity
     */
    int nExtra = (nDataPts == yValuesLen) ? 0 : 1;
    final double[] yValuesUp = Arrays.copyOf(yValues, nDataPts + 2 * nExtra);
    final double[] yValuesDw = Arrays.copyOf(yValues, nDataPts + 2 * nExtra);
    final double[][] tmpFirst = new double[nDataPts][nDataPts];
    final double[][] tmpSecond = new double[nDataPts][nDataPts];
    for (int l = nExtra; l < nDataPts + nExtra; ++l) {
      final double den = Math.abs(yValues[l]) < SMALL ? EPS : yValues[l] * EPS;
      yValuesUp[l] = Math.abs(yValues[l]) < SMALL ? EPS : yValues[l] * (1. + EPS);
      yValuesDw[l] = Math.abs(yValues[l]) < SMALL ? -EPS : yValues[l] * (1. - EPS);
      final double[] yValuesSrtUp = Arrays.copyOfRange(yValuesUp, nExtra, nDataPts + nExtra);
      final double[] yValuesSrtDw = Arrays.copyOfRange(yValuesDw, nExtra, nDataPts + nExtra);

      final DoubleMatrix1D[] yValuesUpDw =
          new DoubleMatrix1D[] {new DoubleMatrix1D(yValuesUp), new DoubleMatrix1D(yValuesDw)};
      final DoubleMatrix1D[] yValuesSrtUpDw =
          new DoubleMatrix1D[] {new DoubleMatrix1D(yValuesSrtUp), new DoubleMatrix1D(yValuesSrtDw)};
      final DoubleMatrix1D[] firstSecondUpDw = new DoubleMatrix1D[4];
      for (int ii = 0; ii < 2; ++ii) {
        final double[] slopesUpDw =
            _solver.slopesCalculator(yValuesSrtUpDw[ii].getData(), intervals);
        final PiecewisePolynomialResult resultUpDw =
            _method.interpolate(xValues, yValuesUpDw[ii].getData());
        final double[] initialFirstUpDw = _function.differentiate(resultUpDw, xValues).getData()[0];
        final double[] initialSecondUpDw =
            _function.differentiateTwice(resultUpDw, xValues).getData()[0];
        double[] firstUpDw =
            firstDerivativeCalculator(
                yValuesSrtUpDw[ii].getData(), intervals, slopesUpDw, initialFirstUpDw);
        boolean modFirstUpDw = false;
        double[] aValuesUpDw = aValuesCalculator(slopesUpDw, firstUpDw);
        double[] bValuesUpDw = bValuesCalculator(slopesUpDw, firstUpDw);
        double[][] intervalsAUpDw = getIntervalsA(intervals, slopesUpDw, firstUpDw, bValuesUpDw);
        double[][] intervalsBUpDw = getIntervalsB(intervals, slopesUpDw, firstUpDw, aValuesUpDw);
        while (modFirstUpDw == false) {
          k = 0;
          for (int i = 0; i < nDataPts - 2; ++i) {
            if (firstUpDw[i + 1] > 0.) {
              if (intervalsAUpDw[i + 1][1] + Math.abs(intervalsAUpDw[i + 1][1]) * ERROR
                      < intervalsBUpDw[i][0] - Math.abs(intervalsBUpDw[i][0]) * ERROR
                  | intervalsAUpDw[i + 1][0] - Math.abs(intervalsAUpDw[i + 1][0]) * ERROR
                      > intervalsBUpDw[i][1] + Math.abs(intervalsBUpDw[i][1]) * ERROR) {
                ++k;
                firstUpDw[i + 1] =
                    firstDerivativesRecalculator(
                        intervals, slopesUpDw, aValuesUpDw, bValuesUpDw, i + 1);
              }
            }
          }
          if (k == 0) {
            modFirstUpDw = true;
          }
          aValuesUpDw = aValuesCalculator(slopesUpDw, firstUpDw);
          bValuesUpDw = bValuesCalculator(slopesUpDw, firstUpDw);
          intervalsAUpDw = getIntervalsA(intervals, slopesUpDw, firstUpDw, bValuesUpDw);
          intervalsBUpDw = getIntervalsB(intervals, slopesUpDw, firstUpDw, aValuesUpDw);
        }
        final double[] secondUpDw =
            secondDerivativeCalculator(initialSecondUpDw, intervalsAUpDw, intervalsBUpDw);
        firstSecondUpDw[ii] = new DoubleMatrix1D(firstUpDw);
        firstSecondUpDw[2 + ii] = new DoubleMatrix1D(secondUpDw);
      }
      for (int j = 0; j < nDataPts; ++j) {
        tmpFirst[j][l - nExtra] =
            0.5 * (firstSecondUpDw[0].getData()[j] - firstSecondUpDw[1].getData()[j]) / den;
        tmpSecond[j][l - nExtra] =
            0.5 * (firstSecondUpDw[2].getData()[j] - firstSecondUpDw[3].getData()[j]) / den;
      }
      yValuesUp[l] = yValues[l];
      yValuesDw[l] = yValues[l];
    }
    for (int i = 0; i < nDataPts; ++i) {
      firstWithSensitivity[i + 1] = new DoubleMatrix1D(tmpFirst[i]);
      secondWithSensitivity[i + 1] = new DoubleMatrix1D(tmpSecond[i]);
    }

    final DoubleMatrix2D[] resMatrix =
        _solver.solveWithSensitivity(
            yValuesSrt,
            intervals,
            slopes,
            slopesSensitivity,
            firstWithSensitivity,
            secondWithSensitivity);

    for (int l = 0; l < nDataPts; ++l) {
      DoubleMatrix2D m = resMatrix[l];
      final int rows = m.getNumberOfRows();
      final int cols = m.getNumberOfColumns();
      for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
          ArgumentChecker.isTrue(
              Doubles.isFinite(m.getEntry(i, j)), "Matrix contains a NaN or infinite");
        }
      }
    }

    final DoubleMatrix2D coefMatrix = resMatrix[0];
    final DoubleMatrix2D[] coefSenseMatrix = new DoubleMatrix2D[nDataPts - 1];
    System.arraycopy(resMatrix, 1, coefSenseMatrix, 0, nDataPts - 1);
    final int nCoefs = coefMatrix.getNumberOfColumns();

    return new PiecewisePolynomialResultsWithSensitivity(
        new DoubleMatrix1D(xValues), coefMatrix, nCoefs, 1, coefSenseMatrix);
  }
  @Override
  public PiecewisePolynomialResult interpolate(
      final double[] xValues, final double[][] yValuesMatrix) {
    ArgumentChecker.notNull(xValues, "xValues");
    ArgumentChecker.notNull(yValuesMatrix, "yValuesMatrix");

    ArgumentChecker.isTrue(
        xValues.length == yValuesMatrix[0].length | xValues.length + 2 == yValuesMatrix[0].length,
        "(xValues length = yValuesMatrix's row vector length) or (xValues length + 2 = yValuesMatrix's row vector length)");
    ArgumentChecker.isTrue(xValues.length > 2, "Data points should be more than 2");

    final int nDataPts = xValues.length;
    final int yValuesLen = yValuesMatrix[0].length;
    final int dim = yValuesMatrix.length;

    for (int i = 0; i < nDataPts; ++i) {
      ArgumentChecker.isFalse(Double.isNaN(xValues[i]), "xValues containing NaN");
      ArgumentChecker.isFalse(Double.isInfinite(xValues[i]), "xValues containing Infinity");
    }
    for (int i = 0; i < yValuesLen; ++i) {
      for (int j = 0; j < dim; ++j) {
        ArgumentChecker.isFalse(Double.isNaN(yValuesMatrix[j][i]), "yValuesMatrix containing NaN");
        ArgumentChecker.isFalse(
            Double.isInfinite(yValuesMatrix[j][i]), "yValuesMatrix containing Infinity");
      }
    }
    for (int i = 0; i < nDataPts; ++i) {
      for (int j = i + 1; j < nDataPts; ++j) {
        ArgumentChecker.isFalse(xValues[i] == xValues[j], "xValues should be distinct");
      }
    }

    double[] xValuesSrt = new double[nDataPts];
    DoubleMatrix2D[] coefMatrix = new DoubleMatrix2D[dim];

    for (int i = 0; i < dim; ++i) {
      xValuesSrt = Arrays.copyOf(xValues, nDataPts);
      double[] yValuesSrt = new double[nDataPts];
      if (nDataPts == yValuesLen) {
        yValuesSrt = Arrays.copyOf(yValuesMatrix[i], nDataPts);
      } else {
        yValuesSrt = Arrays.copyOfRange(yValuesMatrix[i], 1, nDataPts + 1);
      }
      ParallelArrayBinarySort.parallelBinarySort(xValuesSrt, yValuesSrt);

      final double[] intervals = _solver.intervalsCalculator(xValuesSrt);
      final double[] slopes = _solver.slopesCalculator(yValuesSrt, intervals);
      final PiecewisePolynomialResult result = _method.interpolate(xValues, yValuesMatrix[i]);

      ArgumentChecker.isTrue(result.getOrder() >= 3, "Primary interpolant should be degree >= 2");

      final double[] initialFirst = _function.differentiate(result, xValuesSrt).getData()[0];
      final double[] initialSecond = _function.differentiateTwice(result, xValuesSrt).getData()[0];
      final double[] first = firstDerivativeCalculator(yValuesSrt, intervals, slopes, initialFirst);

      boolean modFirst = false;
      int k;
      double[] aValues = aValuesCalculator(slopes, first);
      double[] bValues = bValuesCalculator(slopes, first);
      double[][] intervalsA = getIntervalsA(intervals, slopes, first, bValues);
      double[][] intervalsB = getIntervalsB(intervals, slopes, first, aValues);
      while (modFirst == false) {
        k = 0;
        for (int j = 0; j < nDataPts - 2; ++j) {
          if (first[j + 1] > 0.) {
            if (intervalsA[j + 1][1] + Math.abs(intervalsA[j + 1][1]) * ERROR
                    < intervalsB[j][0] - Math.abs(intervalsB[j][0]) * ERROR
                | intervalsA[j + 1][0] - Math.abs(intervalsA[j + 1][0]) * ERROR
                    > intervalsB[j][1] + Math.abs(intervalsB[j][1]) * ERROR) {
              ++k;
              first[j + 1] =
                  firstDerivativesRecalculator(intervals, slopes, aValues, bValues, j + 1);
            }
          }
        }
        if (k == 0) {
          modFirst = true;
        }
        aValues = aValuesCalculator(slopes, first);
        bValues = bValuesCalculator(slopes, first);
        intervalsA = getIntervalsA(intervals, slopes, first, bValues);
        intervalsB = getIntervalsB(intervals, slopes, first, aValues);
      }
      final double[] second = secondDerivativeCalculator(initialSecond, intervalsA, intervalsB);

      coefMatrix[i] =
          new DoubleMatrix2D(_solver.solve(yValuesSrt, intervals, slopes, first, second));
    }

    final int nIntervals = coefMatrix[0].getNumberOfRows();
    final int nCoefs = coefMatrix[0].getNumberOfColumns();
    double[][] resMatrix = new double[dim * nIntervals][nCoefs];

    for (int i = 0; i < nIntervals; ++i) {
      for (int j = 0; j < dim; ++j) {
        resMatrix[dim * i + j] = coefMatrix[j].getRowVector(i, false).getData();
      }
    }

    for (int i = 0; i < (nIntervals * dim); ++i) {
      for (int j = 0; j < nCoefs; ++j) {
        ArgumentChecker.isFalse(Double.isNaN(resMatrix[i][j]), "Too large input");
        ArgumentChecker.isFalse(Double.isInfinite(resMatrix[i][j]), "Too large input");
      }
    }

    return new PiecewisePolynomialResult(
        new DoubleMatrix1D(xValuesSrt, false), DoubleMatrix2D.noCopy(resMatrix), nCoefs, dim);
  }