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

net.finmath.functions.LinearAlgebra Maven / Gradle / Ivy

/*
 * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: [email protected].
 * 
 * Created on 23.02.2004
 */

package net.finmath.functions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.ArrayRealVector;
import org.apache.commons.math3.linear.CholeskyDecomposition;
import org.apache.commons.math3.linear.DecompositionSolver;
import org.apache.commons.math3.linear.EigenDecomposition;

import cern.colt.matrix.DoubleMatrix1D;
import cern.colt.matrix.DoubleMatrix2D;
import cern.colt.matrix.impl.DenseDoubleMatrix2D;
import cern.colt.matrix.linalg.EigenvalueDecomposition;

/**
 * This class implements some methods from linear algebra (e.g. solution of a linear equation, PCA).
 * 
 * It is basically a functional wrapper using either the Colt library or Apache commons math.
 * 
 * I am currently preferring to use Colt, due to better performance in some situations, however it allows
 * to easily switch some parts to Apache commons math (this is the motivation for this class).
 * 
 * @author Christian Fries
 * @version 1.4
 */
public class LinearAlgebra {
	
	/**
	 * Find a solution of the linear equation A x = b where
	 * 
    *
  • A is an n x m - matrix given as double[n][m]
  • *
  • b is an m - vector given as double[m],
  • *
  • x is an n - vector given as double[n],
  • *
* * @param A The matrix (left hand side of the linear equation). * @param b The vector (right hand of the linear equation). * @return A solution x to A x = b. */ public static double[] solveLinearEquation(double[][] A, double[] b) { // We use the linear algebra package from cern. cern.colt.matrix.linalg.Algebra linearAlgebra = new cern.colt.matrix.linalg.Algebra(); double[] x = linearAlgebra.solve(new DenseDoubleMatrix2D(A), linearAlgebra.transpose(new DenseDoubleMatrix2D(new double[][] { b }))).viewColumn(0).toArray(); return x; } /** * Returns the inverse of a given matrix. * * @param matrix A matrix given as double[n][n]. * @return The inverse of the given matrix. */ public static double[][] invert(double[][] matrix) { // We use the linear algebra package from cern. cern.colt.matrix.linalg.Algebra linearAlgebra = new cern.colt.matrix.linalg.Algebra(); double [][] matrixInverse = linearAlgebra.inverse(new DenseDoubleMatrix2D(matrix)).toArray(); return matrixInverse; } /** * Find a solution of the linear equation A x = b where *
    *
  • A is an symmetric n x n - matrix given as double[n][n]
  • *
  • b is an n - vector given as double[n],
  • *
  • x is an n - vector given as double[n],
  • *
* * @param matrix The matrix A (left hand side of the linear equation). * @param vector The vector b (right hand of the linear equation). * @return A solution x to A x = b. */ public static double[] solveLinearEquationSymmetric(double[][] matrix, double[] vector) { boolean isUseApacheCommonsMath = false; if(isUseApacheCommonsMath) { // We use the linear algebra package apache commons math DecompositionSolver solver = new CholeskyDecomposition(new Array2DRowRealMatrix(matrix, false)).getSolver(); return solver.solve(new ArrayRealVector(vector)).toArray(); } else { return solveLinearEquation(matrix, vector); } } /** * Returns the matrix of the n Eigenvectors corresponding to the first n largest Eigenvalues of a correlation matrix. * These Eigenvectors can also be interpreted as "principal components" (i.e., the method implements the PCA). * * @param correlationMatrix The given correlation matrix. * @param numberOfFactors The requested number of factors (eigenvectors). * @return Matrix of n Eigenvectors (columns) (matrix is given as double[n][numberOfFactors], where n is the number of rows of the correlationMatrix. */ public static double[][] getFactorMatrix(double[][] correlationMatrix, int numberOfFactors) { boolean isUseApacheCommonsMath = false; if(isUseApacheCommonsMath) { return getFactorMatrixUsingCommonsMath(correlationMatrix, numberOfFactors); } else { return getFactorMatrix(new DenseDoubleMatrix2D(correlationMatrix), numberOfFactors).toArray(); } } /** * Returns a correlation matrix which has rank < n and for which the first n factors agree with the factors of correlationMatrix. * * @param correlationMatrix The given correlation matrix. * @param numberOfFactors The requested number of factors (Eigenvectors). * @return Factor reduced correlation matrix. */ public static double[][] factorReduction(double[][] correlationMatrix, int numberOfFactors) { boolean isUseApacheCommonsMath = false; if(isUseApacheCommonsMath) { return factorReduction2(correlationMatrix, numberOfFactors); } else { return factorReduction(new DenseDoubleMatrix2D(correlationMatrix), numberOfFactors).toArray(); } } /** * Returns the matrix of the n Eigenvectors corresponding to the first n largest Eigenvalues of a correlation matrix. * These eigenvectors can also be interpreted as "principal components" (i.e., the method implements the PCA). * * @param correlationMatrix The given correlation matrix. * @param numberOfFactors The requested number of factors (Eigenvectors). * @return Matrix of n Eigenvectors (columns) (matrix is given as double[n][numberOfFactors], where n is the number of rows of the correlationMatrix. */ private static double[][] getFactorMatrixUsingCommonsMath(double[][] correlationMatrix, int numberOfFactors) { /* * Factor reduction */ // Create an eigen vector decomposition of the correlation matrix EigenDecomposition eigenDecomp = new EigenDecomposition(new Array2DRowRealMatrix(correlationMatrix, false)); double[] eigenValues = eigenDecomp.getRealEigenvalues(); double[][] eigenVectorMatrix = eigenDecomp.getV().getData(); class EigenValueIndex implements Comparable { private int index; Double value; public EigenValueIndex(int index, double value) { this.index = index; this.value = value; } @Override public int compareTo(EigenValueIndex o) { return o.value.compareTo(value); } }; List eigenValueIndices = new ArrayList(); for(int i=0; i 0.0 ? 1.0 : -1.0; // Convention: Have first entry of eigenvector positive. This is to make results more consistent. double eigenVectorNormSquared = 0.0; for (int row = 0; row < eigenValues.length; row++) { eigenVectorNormSquared += eigenVectorMatrix[row][eigenVectorIndex] * eigenVectorMatrix[row][eigenVectorIndex]; } eigenValue = Math.max(eigenValue,0.0); for (int row = 0; row < eigenValues.length; row++) { factorMatrix[row][factor] = signChange * Math.sqrt(eigenValue/eigenVectorNormSquared) * eigenVectorMatrix[row][eigenVectorIndex]; } } return factorMatrix; } /** * Returns the matrix of the n Eigenvectors corresponding to the first n largest Eigenvalues of a correlation matrix. * These eigenvectors can also be interpreted as "principal components" (i.e., the method implements the PCA). * * @param correlationMatrix The given correlation matrix. * @param numberOfFactors The requested number of factors (eigenvectors). * @return Matrix of n Eigenvectors (columns) (matrix is given as double[n][numberOfFactors], where n is the number of rows of the correlationMatrix. */ private static DoubleMatrix2D getFactorMatrix(DoubleMatrix2D correlationMatrix, int numberOfFactors) { /* * Factor reduction */ // Create an eigen vector decomposition of the correlation matrix EigenvalueDecomposition eigenDecomp = new EigenvalueDecomposition(correlationMatrix); DoubleMatrix2D eigenVectorMatrix = eigenDecomp.getV(); DoubleMatrix1D eigenValues = eigenDecomp.getRealEigenvalues(); // Sort eigen vectors (will be sorted ascending) DenseDoubleMatrix2D eigenValuesSortMatrix = new DenseDoubleMatrix2D(eigenValues.size(), 2); for (int row = 0; row < eigenValues.size(); row++) { eigenValuesSortMatrix.set(row, 0, eigenValues.get(row)); eigenValuesSortMatrix.set(row, 1, row); } // Extract factors corresponding to the largest eigenvalues DoubleMatrix2D factorMatrix = new DenseDoubleMatrix2D(eigenVectorMatrix.rows(), numberOfFactors); for (int factor = 0; factor < numberOfFactors; factor++) { double eigenValue = eigenValuesSortMatrix.get(eigenValuesSortMatrix.rows() - 1 - factor, 0); int eigenVectorIndex = (int) eigenValuesSortMatrix.get(eigenValuesSortMatrix.rows() - 1 - factor, 1); double signChange = eigenVectorMatrix.get(0, eigenVectorIndex) > 0 ? 1.0 : -1.0; // Convention: Have first entry of eigenvector positive. This is to make results more consistent. double eigenVectorNormSquared = 0.0; for (int row = 0; row < eigenValuesSortMatrix.rows(); row++) { eigenVectorNormSquared += eigenVectorMatrix.get(row, eigenVectorIndex) * eigenVectorMatrix.get(row, eigenVectorIndex); } eigenValue = Math.max(eigenValue,0.0); for (int row = 0; row < eigenValuesSortMatrix.rows(); row++) { factorMatrix.set(row, factor, signChange * Math.sqrt(eigenValue/eigenVectorNormSquared) * eigenVectorMatrix.get(row, eigenVectorIndex)); } } return factorMatrix; } /** * Returns a correlation matrix which has rank < n and for which the first n factors agree with the factors of correlationMatrix. * * @param correlationMatrix The given correlation matrix. * @param numberOfFactors The requested number of factors (Eigenvectors). * @return Factor reduced correlation matrix. */ public static double[][] factorReduction2(double[][] correlationMatrix, int numberOfFactors) { // Extract factors corresponding to the largest eigenvalues double[][] factorMatrix = getFactorMatrix(correlationMatrix, numberOfFactors); // Renormalized rows for (int row = 0; row < correlationMatrix.length; row++) { double sumSquared = 0; for (int factor = 0; factor < numberOfFactors; factor++) sumSquared += factorMatrix[row][factor] * factorMatrix[row][factor]; if(sumSquared != 0) { for (int factor = 0; factor < numberOfFactors; factor++) factorMatrix[row][factor] = factorMatrix[row][factor] / Math.sqrt(sumSquared); } else { // This is a rare case: The factor reduction of a completely decorrelated system to 1 factor for (int factor = 0; factor < numberOfFactors; factor++) factorMatrix[row][factor] = 1.0; } } // Orthogonalized again double[][] reducedCorrelationMatrix = (new Array2DRowRealMatrix(factorMatrix).multiply(new Array2DRowRealMatrix(factorMatrix).transpose())).getData(); return getFactorMatrix(reducedCorrelationMatrix, numberOfFactors); } /** * Returns a correlation matrix which has rank < n and for which the first n factors agree with the factors of correlationMatrix. * * @param correlationMatrix The given correlation matrix. * @param numberOfFactors The requested number of factors (Eigenvectors). * @return Factor reduced correlation matrix. */ public static DoubleMatrix2D factorReduction(DoubleMatrix2D correlationMatrix, int numberOfFactors) { // Extract factors corresponding to the largest eigenvalues DoubleMatrix2D factorMatrix = getFactorMatrix(correlationMatrix, numberOfFactors); // Renormalized rows for (int row = 0; row < factorMatrix.rows(); row++) { double sumSquared = 0; for (int factor = 0; factor < factorMatrix.columns(); factor++) sumSquared += factorMatrix.get(row, factor) * factorMatrix.get(row, factor); if(sumSquared != 0) { for (int factor = 0; factor < factorMatrix.columns(); factor++) factorMatrix.set(row, factor, factorMatrix.get(row, factor) / Math.sqrt(sumSquared)); } else { // This is a rare case: The factor reduction of a completely decorrelated system to 1 factor for (int factor = 0; factor < factorMatrix.columns(); factor++) factorMatrix.set(row, factor, 1.0); } } // Orthogonalized again cern.colt.matrix.linalg.Algebra alg = new cern.colt.matrix.linalg.Algebra(); DoubleMatrix2D reducedCorrelationMatrix = alg.mult(factorMatrix, alg.transpose(factorMatrix)); return getFactorMatrix(reducedCorrelationMatrix, numberOfFactors); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy