/// <summary> /// Calculates the inverse of the original matrix and returns it in a new <see cref="SymmetricMatrix"/> instance. /// WARNING: If <paramref name="inPlace"/> is set to true, this object must not be used again, otherwise a /// <see cref="InvalidOperationException"/> will be thrown. /// </summary> /// <param name="inPlace">False, to copy the internal factorization data before inversion. True, to overwrite it with /// the inverse matrix, thus saving memory and time. However, that will make this object unusable, so you MUST NOT /// call any other members afterwards.</param> public SymmetricMatrix Invert(bool inPlace) { CheckOverwritten(); // Call LAPACK double[] inverse; // if A is posdef, so is inv(A) if (inPlace) { inverse = data; IsOverwritten = true; } else { inverse = new double[data.Length]; Array.Copy(data, inverse, data.Length); } int indefiniteMinorIdx = LapackLinearEquations.Dpptri(StoredTriangle.Upper, Order, inverse, 0); // Check LAPACK execution if (indefiniteMinorIdx < 0) { return(SymmetricMatrix.CreateFromPackedColumnMajorArray(inverse, Order, DefiniteProperty.PositiveDefinite)); } else // this should not have happened { throw new IndefiniteMatrixException($"The entry ({indefiniteMinorIdx}, {indefiniteMinorIdx}) of the factor U" + " is 0 and the inverse could not be computed."); } }
/// <summary> /// Calculates the inverse of the original matrix and returns it in a new <see cref="Matrix"/> instance. /// WARNING: If <paramref name="inPlace"/> is set to true, this object must not be used again, otherwise a /// <see cref="InvalidOperationException"/> will be thrown. /// </summary> /// <param name="inPlace">False, to copy the internal factorization data before inversion. True, to overwrite it with /// the inverse matrix, thus saving memory and time. However, that will make this object unusable, so you MUST NOT /// call any other members afterwards.</param> public Matrix Invert(bool inPlace) { CheckOverwritten(); // Call LAPACK double[] inverse; if (inPlace) { inverse = data; IsOverwritten = true; } else { inverse = new double[data.Length]; Array.Copy(data, inverse, data.Length); } int indefiniteMinorIdx = LapackLinearEquations.Dpotri(StoredTriangle.Upper, Order, inverse, 0, Order); Conversions.CopyUpperToLowerColMajor(inverse, Order); //So far the lower triangle was the same as the original matrix // Check LAPACK execution if (indefiniteMinorIdx < 0) { return(Matrix.CreateFromArray(inverse, Order, Order, false)); } else // this should not have happened { throw new IndefiniteMatrixException($"The entry ({indefiniteMinorIdx}, {indefiniteMinorIdx}) of the factor U" + " is 0 and the inverse could not be computed."); } }
/// <summary> /// Calculates the inverse of the original square matrix and returns it in a new <see cref="Matrix"/> instance. This /// only works if the original matrix is not singular, which can be checked through <see cref="IsSingular"/>. /// WARNING: If <paramref name="inPlace"/> is set to true, this object must not be used again, otherwise a /// <see cref="InvalidOperationException"/> will be thrown. /// </summary> /// <param name="inPlace">False, to copy the internal factorization data before inversion. True, to overwrite it with /// the inverse matrix, thus saving memory and time. However, that will make this object unusable, so you MUST NOT /// call any other members afterwards.</param> /// <exception cref="SingularMatrixException">Thrown if the original matrix is not invertible.</exception> public Matrix Invert(bool inPlace) { // Check if the matrix is suitable for inversion CheckOverwritten(); if (IsSingular) { throw new SingularMatrixException("The factorization has been completed, but U is singular." + $" The first zero pivot is U[{firstZeroPivot}, {firstZeroPivot}] = 0."); } // Copy if the matrix if the inversion will be in place. double[] inverse; if (inPlace) { inverse = lowerUpper; IsOverwritten = true; } else { inverse = new double[lowerUpper.Length]; Array.Copy(lowerUpper, inverse, lowerUpper.Length); } // Call LAPACK int firstZeroDiagonal = LapackLinearEquations.Dgetri(Order, inverse, 0, Order, rowExchanges, 0, pivotTolerance); if (firstZeroDiagonal > 0) // This should not have happened though { throw new SingularMatrixException($"The ({firstZeroDiagonal}, {firstZeroDiagonal}) element of factor U is zero," + " U is singular and the inversion could not be completed."); } return(Matrix.CreateFromArray(inverse, Order, Order, false)); }
/// <summary>Initializes a new instance of the <see cref="LapackNativeWrapper" /> class. /// </summary> internal LapackNativeWrapper() { Name = LongName = new IdentifierString("LAPACK"); LinearEquations = new LapackLinearEquations(this); EigenValues = new LapackEigenvalues(this); AuxiliaryRoutines = new LapackAuxiliaryUtilityRoutines(this); }
/// <summary> /// Calculates the LUP factorization of a square matrix, such that A = P * L * U. Requires an extra O(n) available /// memory, where n is the <paramref name="order"/>. /// </summary> /// <param name="order">The number of rows/columns of the square matrix.</param> /// <param name="matrix">The internal buffer stroring the matrix entries in column major order. It will /// be overwritten.</param> /// <param name="pivotTolerance">If a diagonal entry (called pivot) is <= <paramref name="pivotTolerance"/> it will be /// considered as zero and a permutation will be used to find a non-zero pivot (the process is called pivoting). /// </param> public static LUFactorization Factorize(int order, double[] matrix, double pivotTolerance = LUFactorization.PivotTolerance) { int[] rowExchanges = new int[order]; int firstZeroPivot = LapackLinearEquations.Dgetrf(order, order, matrix, 0, order, rowExchanges, 0, pivotTolerance); return(new LUFactorization(order, matrix, rowExchanges, firstZeroPivot, firstZeroPivot > 0, pivotTolerance)); }
/// <summary> /// See <see cref="ITriangulation.SolveLinearSystem(Vector, Vector)"/>. /// </summary> /// <exception cref="LapackException">Thrown if the call to LAPACK fails due to invalid arguments.</exception> public void SolveLinearSystem(Vector rhs, Vector solution) { CheckOverwritten(); Preconditions.CheckSystemSolutionDimensions(Order, rhs.Length); Preconditions.CheckMultiplicationDimensions(Order, solution.Length); // Call LAPACK solution.CopyFrom(rhs); int numRhs = 1; // rhs is a n x nRhs matrix, stored in b int leadingDimB = Order; // column major ordering: leading dimension of b is n LapackLinearEquations.Dpptrs(StoredTriangle.Upper, Order, numRhs, data, 0, solution.RawData, 0, leadingDimB); }
/// <summary> /// Solves a series of linear systems L * L^T * x = b (or L * D * L^T * x = b), where L is the lower triangular factor /// (and D the diagonal factor) of the Cholesky factorization: A = L * L^T (or A = L * D * L^T). /// </summary> /// <param name="rhsVectors"> /// A matrix whose columns are the right hand side vectors b of the linear systems. Constraints: /// <paramref name="rhsVectors"/>.<see cref="IIndexable2D.NumRows"/> == this.<see cref="Order"/>. /// </param> /// <exception cref="NonMatchingDimensionsException"> /// Thrown if <paramref name="rhsVectors"/> violates the described constraints. /// </exception> /// <exception cref="AccessViolationException"> /// Thrown if the unmanaged memory that holds the factorization data has been released. /// </exception> /// <exception cref="SuiteSparseException">Thrown if the call to SuiteSparse library fails.</exception> public Matrix SolveLinearSystems(Matrix rhs) { CheckOverwritten(); Preconditions.CheckSystemSolutionDimensions(Order, rhs.NumRows); //Preconditions.CheckMultiplicationDimensions(Order, solution.NumColumns); // Back & forward substitution using LAPACK Matrix solution = rhs.Copy(); int numRhs = rhs.NumColumns; // rhs is a n x nRhs matrix, stored in b int leadingDimB = Order; // column major ordering: leading dimension of b is n LapackLinearEquations.Dpotrs(StoredTriangle.Upper, Order, numRhs, data, 0, Order, solution.RawData, 0, leadingDimB); return(solution); }
/// <summary> /// Calculates the cholesky factorization of a symmetric positive definite matrix, such that A = transpose(U) * U. /// </summary> /// <param name="order">The number of rows/columns of the square matrix.</param> /// <param name="matrix">The entries of the original matrix in full column major layout.</param> /// <exception cref="IndefiniteMatrixException">Thrown if the matrix is not symmetric positive definite.</exception> public static CholeskyFull Factorize(int order, double[] matrix) { // Call LAPACK int indefiniteMinorIdx = LapackLinearEquations.Dpotrf(StoredTriangle.Upper, order, matrix, 0, order); // Check LAPACK execution if (indefiniteMinorIdx < 0) { return(new CholeskyFull(order, matrix)); } else { string msg = $"The leading minor of order {indefiniteMinorIdx} (and therefore the matrix itself) is not" + " positive-definite, and the factorization could not be completed."; throw new IndefiniteMatrixException(msg); } }
/// <summary>Initializes a new instance of the <see cref="LapackNativeWrapper" /> class. /// </summary> public LapackNativeWrapper() { Name = LongName = new IdentifierString("LAPACK"); LinearEquations = new LapackLinearEquations( MatrixConditionalNumbers.Create(), MatrixEquilibration.Create(), MatrixFactorization.Create(), MatrixInversion.Create(), Solver.Create(), ErrorEstimationSolver.Create()); EigenValues = new LapackEigenvalues( GeneralizedNonsymmetricEigenvalueProblems.Create(), GeneralizedSymmetricEigenvalueProblems.Create(), NonSymmetricEigenvalueProblems.Create(), SymmetricEigenvalueProblems.Create(), SingularValueDecomposition.Create(), GeneralizedSingularValueDecomposition.Create(), LinearLeastSquaresProblems.Create()); AuxiliaryRoutines = new LapackAuxiliaryUtilityRoutines(AuxiliaryUtilityRoutines.Create()); }
/// <summary>Initializes the <see cref="LAPACK"/> class. /// </summary> /// <remarks>This constructor takes into account the Managed Extensibility Framework (MEF) with respect to <see cref="LowLevelMathConfiguration"/>.</remarks> static LAPACK() { ILibrary lapack = null; try { lapack = LowLevelMathConfiguration.LAPACK.CreateFromConfigurationFile(); if (lapack == null) { lapack = LowLevelMathConfiguration.LAPACK.Libraries.Standard; // can be null, i.e. fallback solution is perhaps not available Logger.Stream.LogCritical(LowLevelMathConfigurationResources.LogFileMessageConfigFileUseDefaultImplementation, "LAPACK"); } } catch (Exception e) // thrown of Exceptions in static constructors should be avoided { Logger.Stream.LogError(e, LowLevelMathConfigurationResources.LogFileMessageCorruptConfigFile); lapack = LowLevelMathConfiguration.LAPACK.Libraries.Standard; Logger.Stream.LogError(LowLevelMathConfigurationResources.LogFileMessageConfigFileUseDefaultImplementation, "LAPACK"); } EigenValues = lapack.EigenValues; LinearEquations = lapack.LinearEquations; AuxiliaryRoutines = lapack.AuxiliaryRoutines; }
/// <summary> /// See <see cref="ITriangulation.SolveLinearSystem(Vector, Vector)"/>. /// </summary> /// <remarks> /// This method is not garanteed to succeed. A singular matrix can be factorized as A=P*L*U, but not all linear systems /// with a singular matrix can be solved. /// </remarks> /// <exception cref="SingularMatrixException">Thrown if the original matrix is not invertible.</exception> /// <exception cref="LapackException">Thrown if the call to LAPACK fails due to invalid arguments.</exception> public void SolveLinearSystem(Vector rhs, Vector solution) { CheckOverwritten(); Preconditions.CheckSystemSolutionDimensions(Order, rhs.Length); Preconditions.CheckMultiplicationDimensions(Order, solution.Length); // Check if the matrix is singular first if (IsSingular) { string msg = "The factorization has been completed, but U is singular." + $" The first zero pivot is U[{firstZeroPivot}, {firstZeroPivot}] = 0."; throw new SingularMatrixException(msg); } // Back & forward substitution using LAPACK int n = Order; solution.CopyFrom(rhs); //double[] solution = rhs.CopyToArray(); int numRhs = 1; // rhs is a n x nRhs matrix, stored in b int leadingDimB = n; // column major ordering: leading dimension of b is n LapackLinearEquations.Dgetrs(TransposeMatrix.NoTranspose, n, numRhs, lowerUpper, 0, n, rowExchanges, 0, solution.RawData, 0, leadingDimB); }