/// <summary> /// Returns the inverse of this lower triangular matrix /// </summary> /// <returns></returns> public new LowerTriangularMatrix Inverse() { LowerTriangularMatrix L = new LowerTriangularMatrix(rows, cols); L.SetToInverse(this); return(L); }
/// <summary> /// Creates a full clone of this instance (including the data) /// </summary> /// <returns></returns> public override object Clone() { LowerTriangularMatrix result = new LowerTriangularMatrix(rows, cols); result.SetTo(this); return(result); }
/// <summary> /// Return the transpose of this upper triangular matrix /// </summary> /// <returns></returns> public new LowerTriangularMatrix Transpose() { LowerTriangularMatrix L = new LowerTriangularMatrix(cols, rows); L.SetToTranspose(this); return(L); }
/// <summary> /// Gets the Cholesky decomposition of the matrix (L*L' = A), replacing its contents. /// </summary> /// <param name="isPosDef">True if <c>this</c> is positive definite, otherwise false.</param> /// <returns>The Cholesky decomposition L. If <c>this</c> is positive semidefinite, /// then L will satisfy L*L' = A. /// Otherwise, L will only approximately satisfy L*L' = A.</returns> /// <remarks> /// <c>this</c> must be symmetric, but need not be positive definite. /// </remarks> public LowerTriangularMatrix CholeskyInPlace(out bool isPosDef) { LowerTriangularMatrix L = new LowerTriangularMatrix(rows, cols, data); #if LAPACK isPosDef = Lapack.CholeskyInPlace(this); #else isPosDef = L.SetToCholesky(this); #endif return(L); }
public static void Normal(Vector mean, PositiveDefiniteMatrix variance, Vector result) { LowerTriangularMatrix L = new LowerTriangularMatrix(variance.Rows, variance.Rows); bool isPosDef = L.SetToCholesky(variance); if (!isPosDef) { throw new ArgumentException("PROB.Random.Normal(Vector,Matrix,Vector): variance must be positive definite", nameof(variance)); } NormalChol(mean, L, result); }
public static void Wishart(double a, LowerTriangularMatrix result) { Assert.IsTrue(result.Rows == result.Cols); for (int i = 0; i < result.Rows; ++i) { for (int j = 0; j < i; ++j) { result[i, j] = Normal() * MMath.SqrtHalf; result[j, i] = 0; } result[i, i] = System.Math.Sqrt(Gamma(a - i * 0.5)); } }
/// <summary> /// Sets b to inv(A)*b. /// </summary> /// <param name="b"></param> /// <param name="A"></param> public static void PredivideBy(DenseVector b, LowerTriangularMatrix A) { Assert.IsTrue(A.Rows == A.Cols); Assert.IsTrue(A.Rows == b.Count); // Lapack is column-major, so we tell it that A is upper triangular and transposed char side = 'L', uplo = 'U', trans = 'T', diag = 'N'; double alpha = 1; ptrdiff_t m = b.Count, n = 1; fixed (double* sA = A.SourceArray, sB = b.SourceArray) { double* pA = sA, pB = sB; dtrsm(&side, &uplo, &trans, &diag, &m, &n, &alpha, pA, &m, pB, &m); } }
public static void NormalP(Vector mean, PositiveDefiniteMatrix precision, Vector result) { LowerTriangularMatrix L = new LowerTriangularMatrix(precision.Rows, precision.Rows); bool isPosDef = L.SetToCholesky(precision); if (!isPosDef) { throw new ArgumentException("PROB.Random.NormalP(Vector,Matrix,Vector): precision must be positive definite", nameof(precision)); } UpperTriangularMatrix U = UpperTriangularMatrix.TransposeInPlace(L); NormalPChol(mean, U, result); }
/// <summary> /// Sets B to A'\B. /// </summary> /// <param name="B"></param> /// <param name="A"></param> public static void PredivideByTranspose(Matrix B, LowerTriangularMatrix A) { Assert.IsTrue(A.Rows == A.Cols); Assert.IsTrue(A.Rows == B.Rows); Assert.IsTrue(!object.ReferenceEquals(B, A)); // Lapack is column-major, so we tell it that A is upper triangular and switch sides: // inv(A)*B = (B'*inv(A'))' char side = 'R', uplo = 'U', trans = 'T', diag = 'N'; double alpha = 1; ptrdiff_t m = B.Cols, n = B.Rows; fixed (double* sA = A.SourceArray, sB = B.SourceArray) { double* pA = sA, pB = sB; dtrsm(&side, &uplo, &trans, &diag, &m, &n, &alpha, pA, &n, pB, &m); } }
public static void NormalChol(Vector mean, LowerTriangularMatrix varChol, Vector result) { if (ReferenceEquals(mean, result)) { throw new ArgumentException("mean and result are the same object"); } Vector temp = Vector.Zero(result.Count); for (int i = 0; i < result.Count; i++) { temp[i] = Normal(); } result.SetToProduct(varChol, temp); result.SetToSum(mean, result); // result = mean + varChol*N(0,1) }
/// <summary> /// Sets this positive-definite matrix to inverse of a given positive-definite matrix /// where a lower triangular workspace is passed. /// </summary> /// <param name="A">A symmetric positive-definite matrix, same size as <c>this</c>. Can be the same object as <c>this</c>.</param> /// <param name="L">A workspace, same size as <paramref name="A"/>.</param> /// <returns><c>this</c></returns> /// <exception cref="PositiveDefiniteMatrixException">If <paramref name="A"/> is not positive definite.</exception> public PositiveDefiniteMatrix SetToInverse(PositiveDefiniteMatrix A, LowerTriangularMatrix L) { CheckCompatible(L, nameof(L)); // Algorithm: // A = L*L' // inv(A) = inv(L')*inv(L) bool isPD = L.SetToCholesky(A); if (!isPD) { throw new PositiveDefiniteMatrixException(); } L.SetToInverse(L); SetToOuterTranspose(L); return(this); }
public UpperTriangularMatrix GetsTranspose(LowerTriangularMatrix L) { if (rows != L.Cols || cols != L.Rows) { throw new ArgumentException("Output matrix is not compatible with the transpose", "that"); } L.CheckLowerTriangular(); // lower triangle of this is assumed to be zero for (int i = 0; i < rows; ++i) { for (int j = i; j < cols; ++j) { this[i, j] = L[j, i]; } } CheckUpperTriangular(); return(this); }
/// <remarks>U is no longer a valid upper triangular matrix.</remarks> public static LowerTriangularMatrix TransposeInPlace(UpperTriangularMatrix U) { U.CheckUpperTriangular(); LowerTriangularMatrix L = new LowerTriangularMatrix(U.Cols, U.Rows, U.SourceArray, U.Start); Assert.IsTrue(L.Rows == L.Cols); for (int i = 0; i < L.Rows; ++i) { for (int j = 0; j < i; ++j) { L[i, j] = L[j, i]; L[j, i] = 0; } } L.CheckLowerTriangular(); return(L); }
/// <summary> /// Transposes a given lower triangular matrix in place. /// </summary> /// <param name="L">Matrix to transpose. Contents are corrupted on exit.</param> /// <returns>An upper triangular wrapper of L's source array.</returns> /// <remarks>L is no longer a valid lower triangular matrix.</remarks> public static UpperTriangularMatrix TransposeInPlace(LowerTriangularMatrix L) { L.CheckLowerTriangular(); UpperTriangularMatrix U = new UpperTriangularMatrix(L.Cols, L.Rows, L.SourceArray); Assert.IsTrue(U.Rows == U.Cols); for (int i = 0; i < U.Rows; ++i) { for (int j = i + 1; j < U.Cols; ++j) { U[i, j] = U[j, i]; U[j, i] = 0; } } U.CheckUpperTriangular(); return(U); }
/// <summary> /// Modifies <c>this</c> to be the inverse of A. /// </summary> /// <param name="A">Can be the same object as <c>this</c></param> public void SetToInverse(LowerTriangularMatrix A) { #if LAPACK if (object.ReferenceEquals(this, A)) { A = (LowerTriangularMatrix)A.Clone(); } this.SetToIdentity(); Lapack.PredivideBy(this, A); #else // Reference: Golub and van Loan (1996) Assert.IsTrue(A.Rows == A.Cols); Assert.IsTrue(A.Rows == this.Rows); for (int k = 0; k < rows; k++) { if (A[k, k] == 0) { throw new MatrixSingularException(A); } } for (int j = 0; j < cols; j++) { int index1 = j; // k < j case for (int k = 0; k < j; k++) { //B[k, j] = 0.0; data[index1] = 0.0; index1 += cols; } // k == j case int index2 = j + j * cols; double v = 1.0 / A.data[index2]; data[index1] = v; for (int i = j + 1; i < rows; i++) { // B[i, j] = -v * A[i, j]; index1 += cols; index2 += cols; data[index1] = -v * A.data[index2]; } // k > j case for (int k = j + 1; k < rows; k++) { index1 = j + k * cols; index2 = k + k * cols; if (data[index1] != 0) { //double u = B[k,j]/A[k,k]; //B[k, j] = u; // TM: this style of indexing may look ugly but it runs much faster double u = data[index1] / A.data[index2]; data[index1] = u; for (int i = k + 1; i < rows; i++) { // B[i, j] -= u * A[i, k]; index1 += cols; index2 += cols; data[index1] -= u * A.data[index2]; } } } } #endif }
public bool SetToCholesky(Matrix A) { A.CheckSymmetry("A"); #if LAPACK SetTo(A); bool isPosDef = Lapack.CholeskyInPlace(this); #else CheckCompatible(A, "A"); bool isPosDef = true; LowerTriangularMatrix L = this; // compute the Cholesky factor // Reference: Golub and van Loan (1996) for (int i = 0; i < A.Cols; i++) { // upper triangle for (int j = 0; j < i; j++) { L[j, i] = 0; } // lower triangle for (int j = i; j < A.Rows; j++) { double sum = A[i, j]; int index1 = i * cols; int index2 = j * cols; for (int k = 0; k < i; k++) { //sum -= L[i, k] * L[j, k]; sum -= data[index1++] * data[index2++]; } if (i == j) { // diagonal entry if (sum <= 0) { isPosDef = false; L[i, i] = 0; } else { L[i, i] = System.Math.Sqrt(sum); } } else { // off-diagonal entry if (L[i, i] > 0) { L[j, i] = sum / L[i, i]; } else { L[j, i] = 0; } } } } CheckLowerTriangular(); #endif return(isPosDef); }
/// <summary> /// Returns the natural logarithm of the determinant of this positive-definite matrix. /// </summary> /// <param name="ignoreInfinity">If true, +infinity on the diagonal is treated as 1.</param> /// <returns>The log-determinant of <c>this</c>.</returns> public double LogDeterminant(bool ignoreInfinity = false) { LowerTriangularMatrix L = new LowerTriangularMatrix(rows, cols); return(LogDeterminant(L, ignoreInfinity)); }
public double LogDeterminant(LowerTriangularMatrix L, bool ignoreInfinity = false) { L.SetToCholesky(this); return(2 * L.LogDeterminant(ignoreInfinity)); }