All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opengamma.strata.math.impl.linearalgebra.CholeskyDecompositionOpenGamma Maven / Gradle / Ivy

/*
 * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.strata.math.impl.linearalgebra;

import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.array.DoubleMatrix;
import com.opengamma.strata.math.linearalgebra.Decomposition;

/**
 * OpenGamma implementation of the Cholesky decomposition and its differentiation.
 */
public class CholeskyDecompositionOpenGamma implements Decomposition {

  /**
   * The input matrix symmetry is checked. If the relative difference abs(Aij-Aji) > max(abs(Aij), abs(Aji)) * e_sym, the matrix is considered non-symmetric.
   * The default value for the threshold e_sym.
   */
  public static final double DEFAULT_SYMMETRY_THRESHOLD = 1.0E-10;
  /**
   * In the decomposition, the positivity of the matrix is checked. If the absolute value Lii < e_pos the matrix is considered non-positive.
   * The default value for the threshold e_pos.
   */
  public static final double DEFAULT_POSITIVITY_THRESHOLD = 1.0E-10;

  /**
   * {@inheritDoc}
   */
  @Override
  public CholeskyDecompositionResult apply(DoubleMatrix x) {
    return evaluate(x, DEFAULT_SYMMETRY_THRESHOLD, DEFAULT_POSITIVITY_THRESHOLD);
  }

  /**
   * Perform the decomposition with a given symmetry and positivity threshold.
   * @param matrix The matrix to decompose.
   * @param symmetryThreshold The symmetry threshold.
   * @param positivityThreshold The positivity threshold.
   * @return The Cholesky decomposition.
   */
  public CholeskyDecompositionResult evaluate(DoubleMatrix matrix, double symmetryThreshold, double positivityThreshold) {
    ArgChecker.notNull(matrix, "Matrix null");
    int nbRow = matrix.rowCount();
    int nbCol = matrix.columnCount();
    ArgChecker.isTrue(nbRow == nbCol, "Matrix not square");
    double[][] l = new double[nbRow][nbRow];
    // Check symmetry and initial fill of _lTArray
    for (int looprow = 0; looprow < nbRow; looprow++) {
      for (int loopcol = 0; loopcol <= looprow; loopcol++) {
        double rowcol = matrix.get(looprow, loopcol);
        double colrow = matrix.get(loopcol, looprow);
        double maxValue = Math.max(Math.abs(rowcol), Math.abs(colrow));
        double diff = Math.abs(rowcol - colrow);
        ArgChecker.isTrue(diff <= maxValue * symmetryThreshold, "Matrix not symmetrical");
        l[looprow][loopcol] = rowcol;
      }
    }
    // The decomposition
    for (int loopcol = 0; loopcol < nbCol; loopcol++) {
      ArgChecker.isTrue(l[loopcol][loopcol] > positivityThreshold, "Matrix not positive");
      l[loopcol][loopcol] = Math.sqrt(l[loopcol][loopcol]); // Pivot
      double lInverse = 1.0 / l[loopcol][loopcol];
      for (int looprow = loopcol + 1; looprow < nbRow; looprow++) { // Current column
        l[looprow][loopcol] *= lInverse;
      }
      for (int j = loopcol + 1; j < nbRow; j++) { // Other columns
        for (int i = j; i < nbRow; i++) {
          l[i][j] -= l[i][loopcol] * l[j][loopcol];
        }
      }
    }
    return new CholeskyDecompositionOpenGammaResult(l);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy