From f9647af27dd07292440eb018a69ed3c85864a198 Mon Sep 17 00:00:00 2001 From: Abratiychuk Date: Tue, 6 Jul 2010 18:41:11 +0800 Subject: [PATCH] Implemented Matrix Rank, ConditionNumber, Determinant, Inverse. Finished LU in ManagedLinearAlgebraProvider --- .../Atlas/AtlasLinearAlgebraProvider.cs | 97 ++-- .../ILinearAlgebraProviderOfT.cs | 24 +- .../ManagedLinearAlgebraProvider.cs | 474 ++++++++++++++++-- .../Mkl/MklLinearAlgebraProvider.cs | 97 ++-- .../Double/Factorization/DenseLU.cs | 19 +- .../LinearAlgebra/Double/Factorization/LU.cs | 6 + .../LinearAlgebra/Double/Matrix.Arithmetic.cs | 28 +- src/Numerics/LinearAlgebra/Double/Matrix.cs | 4 +- .../Double/Factorization/LUTests.cs | 306 +++++++++-- 9 files changed, 879 insertions(+), 176 deletions(-) diff --git a/src/Numerics/Algorithms/LinearAlgebra/Atlas/AtlasLinearAlgebraProvider.cs b/src/Numerics/Algorithms/LinearAlgebra/Atlas/AtlasLinearAlgebraProvider.cs index 41c52f77..a2331ba1 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/Atlas/AtlasLinearAlgebraProvider.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/Atlas/AtlasLinearAlgebraProvider.cs @@ -347,8 +347,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(double[] a) + public void LUInverse(double[] a, int order) { throw new NotImplementedException(); } @@ -357,9 +358,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(double[] a, int[] ipiv) + public void LUInverseFactored(double[] a, int order, int[] ipiv) { throw new NotImplementedException(); } @@ -368,11 +370,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(double[] a, double[] work) + public void LUInverse(double[] a, int order, double[] work) { throw new NotImplementedException(); } @@ -381,12 +384,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(double[] a, int[] ipiv, double[] work) + public void LUInverseFactored(double[] a, int order, int[] ipiv, double[] work) { throw new NotImplementedException(); } @@ -396,9 +400,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(int columnsOfB, double[] a, double[] b) + public void LUSolve(int columnsOfB, double[] a, int order, double[] b) { throw new NotImplementedException(); } @@ -408,10 +413,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(int columnsOfB, double[] a, int ipiv, double[] b) + public void LUSolveFactored(int columnsOfB, double[] a, int order, int[] ipiv, double[] b) { throw new NotImplementedException(); } @@ -422,9 +428,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// How to transpose the matrix. /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(Transpose transposeA, int columnsOfB, double[] a, double[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, double[] a, int order, double[] b) { throw new NotImplementedException(); } @@ -435,10 +442,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// How to transpose the matrix. /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(Transpose transposeA, int columnsOfB, double[] a, int ipiv, double[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, double[] a, int order, int[] ipiv, double[] b) { throw new NotImplementedException(); } @@ -958,7 +966,6 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas SafeNativeMethods.s_matrix_multiply(transposeA, transposeB, m, n, k, alpha, a, b, beta, c); } - /// /// /// Computes the LUP factorization of A. P*A = L*U. /// @@ -977,8 +984,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(float[] a) + public void LUInverse(float[] a, int order) { throw new NotImplementedException(); } @@ -987,9 +995,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(float[] a, int[] ipiv) + public void LUInverseFactored(float[] a, int order, int[] ipiv) { throw new NotImplementedException(); } @@ -998,11 +1007,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(float[] a, float[] work) + public void LUInverse(float[] a, int order, float[] work) { throw new NotImplementedException(); } @@ -1011,12 +1021,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(float[] a, int[] ipiv, float[] work) + public void LUInverseFactored(float[] a, int order, int[] ipiv, float[] work) { throw new NotImplementedException(); } @@ -1026,9 +1037,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(int columnsOfB, float[] a, float[] b) + public void LUSolve(int columnsOfB, float[] a, int order, float[] b) { throw new NotImplementedException(); } @@ -1038,10 +1050,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(int columnsOfB, float[] a, int ipiv, float[] b) + public void LUSolveFactored(int columnsOfB, float[] a, int order, int[] ipiv, float[] b) { throw new NotImplementedException(); } @@ -1052,9 +1065,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// How to transpose the matrix. /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(Transpose transposeA, int columnsOfB, float[] a, float[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, float[] a, int order, float[] b) { throw new NotImplementedException(); } @@ -1065,10 +1079,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// How to transpose the matrix. /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(Transpose transposeA, int columnsOfB, float[] a, int ipiv, float[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, float[] a, int order, int[] ipiv, float[] b) { throw new NotImplementedException(); } @@ -1605,8 +1620,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(Complex[] a) + public void LUInverse(Complex[] a, int order) { throw new NotImplementedException(); } @@ -1615,9 +1631,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(Complex[] a, int[] ipiv) + public void LUInverseFactored(Complex[] a, int order, int[] ipiv) { throw new NotImplementedException(); } @@ -1626,11 +1643,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(Complex[] a, Complex[] work) + public void LUInverse(Complex[] a, int order, Complex[] work) { throw new NotImplementedException(); } @@ -1639,12 +1657,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(Complex[] a, int[] ipiv, Complex[] work) + public void LUInverseFactored(Complex[] a, int order, int[] ipiv, Complex[] work) { throw new NotImplementedException(); } @@ -1654,9 +1673,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(int columnsOfB, Complex[] a, Complex[] b) + public void LUSolve(int columnsOfB, Complex[] a, int order, Complex[] b) { throw new NotImplementedException(); } @@ -1666,10 +1686,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(int columnsOfB, Complex[] a, int ipiv, Complex[] b) + public void LUSolveFactored(int columnsOfB, Complex[] a, int order, int[] ipiv, Complex[] b) { throw new NotImplementedException(); } @@ -1680,9 +1701,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// How to transpose the matrix. /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(Transpose transposeA, int columnsOfB, Complex[] a, Complex[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, Complex[] a, int order, Complex[] b) { throw new NotImplementedException(); } @@ -1693,10 +1715,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// How to transpose the matrix. /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex[] a, int ipiv, Complex[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex[] a, int order, int[] ipiv, Complex[] b) { throw new NotImplementedException(); } @@ -2233,8 +2256,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(Complex32[] a) + public void LUInverse(Complex32[] a, int order) { throw new NotImplementedException(); } @@ -2243,9 +2267,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(Complex32[] a, int[] ipiv) + public void LUInverseFactored(Complex32[] a, int order, int[] ipiv) { throw new NotImplementedException(); } @@ -2254,11 +2279,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(Complex32[] a, Complex32[] work) + public void LUInverse(Complex32[] a, int order, Complex32[] work) { throw new NotImplementedException(); } @@ -2267,12 +2293,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(Complex32[] a, int[] ipiv, Complex32[] work) + public void LUInverseFactored(Complex32[] a, int order, int[] ipiv, Complex32[] work) { throw new NotImplementedException(); } @@ -2282,9 +2309,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(int columnsOfB, Complex32[] a, Complex32[] b) + public void LUSolve(int columnsOfB, Complex32[] a, int order, Complex32[] b) { throw new NotImplementedException(); } @@ -2294,10 +2322,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(int columnsOfB, Complex32[] a, int ipiv, Complex32[] b) + public void LUSolveFactored(int columnsOfB, Complex32[] a, int order, int[] ipiv, Complex32[] b) { throw new NotImplementedException(); } @@ -2308,9 +2337,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// How to transpose the matrix. /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(Transpose transposeA, int columnsOfB, Complex32[] a, Complex32[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, Complex32[] a, int order, Complex32[] b) { throw new NotImplementedException(); } @@ -2321,10 +2351,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// How to transpose the matrix. /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex32[] a, int ipiv, Complex32[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex32[] a, int order, int[] ipiv, Complex32[] b) { throw new NotImplementedException(); } diff --git a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs index 3beb89c7..bf1a7532 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs @@ -226,56 +226,62 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// This is equivalent to the GETRF and GETRI LAPACK routines. - void LUInverse(T[] a); + void LUInverse(T[] a, int order); /// /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// This is equivalent to the GETRI LAPACK routine. - void LUInverseFactored(T[] a, int[] ipiv); + void LUInverseFactored(T[] a, int order, int[] ipiv); /// /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRF and GETRI LAPACK routines. - void LUInverse(T[] a, T[] work); + void LUInverse(T[] a, int order, T[] work); /// /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRI LAPACK routine. - void LUInverseFactored(T[] a, int[] ipiv, T[] work); + void LUInverseFactored(T[] a, int order, int[] ipiv, T[] work); /// /// Solves A*X=B for X using LU factorization. /// /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - void LUSolve(int columnsOfB, T[] a, T[] b); + void LUSolve(int columnsOfB, T[] a, int order, T[] b); /// /// Solves A*X=B for X using a previously factored A matrix. /// /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - void LUSolveFactored(int columnsOfB, T[] a, int ipiv, T[] b); + void LUSolveFactored(int columnsOfB, T[] a, int order, int[] ipiv, T[] b); /// /// Solves A*X=B for X using LU factorization. @@ -283,9 +289,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// How to transpose the matrix. /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - void LUSolve(Transpose transposeA, int columnsOfB, T[] a, T[] b); + void LUSolve(Transpose transposeA, int columnsOfB, T[] a, int order, T[] b); /// /// Solves A*X=B for X using a previously factored A matrix. @@ -293,10 +300,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// How to transpose the matrix. /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - void LUSolveFactored(Transpose transposeA, int columnsOfB, T[] a, int ipiv, T[] b); + void LUSolveFactored(Transpose transposeA, int columnsOfB, T[] a, int order, int[] ipiv, T[] b); /// /// Computes the Cholesky factorization of A. diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs index 6fcf52a5..54c8a990 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs @@ -724,6 +724,26 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// This is equivalent to the GETRF LAPACK routine. public void LUFactor(double[] data, int order, int[] ipiv) { + if (data == null) + { + throw new ArgumentNullException("data"); + } + + if (ipiv == null) + { + throw new ArgumentNullException("ipiv"); + } + + if (data.Length != order * order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "data"); + } + + if (ipiv.Length != order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); + } + // Initialize the pivot matrix to the identity permutation. for (var i = 0; i < order; i++) { @@ -794,44 +814,322 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } } - public void LUInverse(double[] a) + /// + /// Computes the inverse of matrix using LU factorization. + /// + /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . + /// This is equivalent to the GETRF and GETRI LAPACK routines. + public void LUInverse(double[] a, int order) { - throw new NotImplementedException(); + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (a.Length != order * order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + } + + var ipiv = new int[order]; + LUFactor(a, order, ipiv); + LUInverseFactored(a, order, ipiv); } - public void LUInverseFactored(double[] a, int[] ipiv) + /// + /// Computes the inverse of a previously factored matrix. + /// + /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . + /// The pivot indices of . + /// This is equivalent to the GETRI LAPACK routine. + public void LUInverseFactored(double[] a, int order, int[] ipiv) { - throw new NotImplementedException(); + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (ipiv == null) + { + throw new ArgumentNullException("ipiv"); + } + + if (a.Length != order * order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + } + + if (ipiv.Length != order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); + } + + var inverse = new double[a.Length]; + for (var i = 0; i < order; i++) + { + inverse[i + order * i] = 1.0; + } + + LUSolveFactored(order, a, order, ipiv, inverse); + Buffer.BlockCopy(inverse, 0, a, 0, a.Length * Constants.SizeOfDouble); } - public void LUInverse(double[] a, double[] work) + /// + /// Computes the inverse of matrix using LU factorization. + /// + /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . + /// The work array. The array must have a length of at least N, + /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal + /// work size value. + /// This is equivalent to the GETRF and GETRI LAPACK routines. + public void LUInverse(double[] a, int order, double[] work) { - throw new NotImplementedException(); + LUInverse(a, order); } - public void LUInverseFactored(double[] a, int[] ipiv, double[] work) + /// + /// Computes the inverse of a previously factored matrix. + /// + /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . + /// The pivot indices of . + /// The work array. The array must have a length of at least N, + /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal + /// work size value. + /// This is equivalent to the GETRI LAPACK routine. + public void LUInverseFactored(double[] a, int order, int[] ipiv, double[] work) { - throw new NotImplementedException(); + LUInverseFactored(a, order, ipiv); } - public void LUSolve(int columnsOfB, double[] a, double[] b) + /// + /// Solves A*X=B for X using LU factorization. + /// + /// The number of columns of B. + /// The square matrix A. + /// The order of the square matrix . + /// The B matrix. + /// This is equivalent to the GETRF and GETRS LAPACK routines. + public void LUSolve(int columnsOfB, double[] a, int order, double[] b) { - throw new NotImplementedException(); + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (b == null) + { + throw new ArgumentNullException("b"); + } + + if (a.Length != order * order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + } + + if (b.Length != order * columnsOfB) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } + + var ipiv = new int[order]; + LUFactor(a, order, ipiv); + LUSolveFactored(columnsOfB, a, order, ipiv, b); } - public void LUSolveFactored(int columnsOfB, double[] a, int ipiv, double[] b) + /// + /// Solves A*X=B for X using a previously factored A matrix. + /// + /// The number of columns of B. + /// The factored A matrix. + /// The order of the square matrix . + /// The pivot indices of . + /// The B matrix. + /// This is equivalent to the GETRS LAPACK routine. + public void LUSolveFactored(int columnsOfB, double[] a, int order, int[] ipiv, double[] b) { - throw new NotImplementedException(); + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (ipiv == null) + { + throw new ArgumentNullException("ipiv"); + } + + if (b == null) + { + throw new ArgumentNullException("b"); + } + + if (a.Length != order * order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + } + + if (ipiv.Length != order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); + } + + if (b.Length != order * columnsOfB) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } + + // Compute the column vector P*B + for (var i = 0; i < ipiv.Length; i++) + { + if (ipiv[i] == i) + { + continue; + } + + var p = ipiv[i]; + for (var j = 0; j < columnsOfB; j++) + { + var indexk = j*order; + var indexkp = indexk + p; + var indexkj = indexk + i; + var temp = b[indexkp]; + b[indexkp] = b[indexkj]; + b[indexkj] = temp; + } + } + + // Solve L*Y = P*B + for (var k = 0; k < order; k++) + { + var korder = k * order; + for (var i = k + 1; i < order; i++) + { + for (var j = 0; j < columnsOfB; j++) + { + var index = j * order; + b[i + index] -= b[k + index] * a[i + korder]; + } + } + } + + // Solve U*X = Y; + for (var k = order - 1; k >= 0; k--) + { + var korder = k + k * order; + for (var j = 0; j < columnsOfB; j++) + { + b[k + j * order] /= a[korder]; + } + + korder = k * order; + for (var i = 0; i < k; i++) + { + for (var j = 0; j < columnsOfB; j++) + { + var index = j * order; + b[i + index] -= b[k + index] * a[i + korder]; + } + } + } } - public void LUSolve(Transpose transposeA, int columnsOfB, double[] a, double[] b) + /// + /// Solves A*X=B for X using LU factorization. + /// + /// How to transpose the matrix. + /// The number of columns of B. + /// The square matrix A. + /// The order of the square matrix . + /// The B matrix. + /// This is equivalent to the GETRF and GETRS LAPACK routines. + public void LUSolve(Transpose transposeA, int columnsOfB, double[] a, int order, double[] b) { - throw new NotImplementedException(); + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (b == null) + { + throw new ArgumentNullException("b"); + } + + if (a.Length != order * order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + } + + if (b.Length != order * columnsOfB) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } + + var ipiv = new int[order]; + LUFactor(a, order, ipiv); + LUSolveFactored(transposeA, columnsOfB, a, order, ipiv, b); } - public void LUSolveFactored(Transpose transposeA, int columnsOfB, double[] a, int ipiv, double[] b) + /// + /// Solves A*X=B for X using a previously factored A matrix. + /// + /// How to transpose the matrix. + /// The number of columns of B. + /// The factored A matrix. + /// The order of the square matrix . + /// The pivot indices of . + /// The B matrix. + /// This is equivalent to the GETRS LAPACK routine. + public void LUSolveFactored(Transpose transposeA, int columnsOfB, double[] a, int order, int[] ipiv, double[] b) { - throw new NotImplementedException(); + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (ipiv == null) + { + throw new ArgumentNullException("ipiv"); + } + + if (b == null) + { + throw new ArgumentNullException("b"); + } + + if (a.Length != order * order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + } + + if (ipiv.Length != order) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); + } + + if (b.Length != order * columnsOfB) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } + + if ((transposeA == Transpose.Transpose) || (transposeA == Transpose.ConjugateTranspose)) + { + var aT = new double[a.Length]; + for (var i = 0; i < order; i++) + { + for (var j = 0; j < order; j++) + { + aT[(j * order) + i] = a[(i * order) + j]; + } + } + LUSolveFactored(columnsOfB, aT, order, ipiv, b); + } + else + { + LUSolveFactored(columnsOfB, a, order, ipiv, b); + } } /// @@ -3724,42 +4022,74 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new NotImplementedException(); } - public void LUInverse(float[] a) + /// + /// Computes the inverse of matrix using LU factorization. + /// + /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . + /// This is equivalent to the GETRF and GETRI LAPACK routines. + public void LUInverse(float[] a, int order) { throw new NotImplementedException(); } - public void LUInverseFactored(float[] a, int[] ipiv) + /// + /// Computes the inverse of a previously factored matrix. + /// + /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . + /// The pivot indices of . + /// This is equivalent to the GETRI LAPACK routine. + public void LUInverseFactored(float[] a, int order, int[] ipiv) { throw new NotImplementedException(); } - public void LUInverse(float[] a, float[] work) + /// + /// Computes the inverse of matrix using LU factorization. + /// + /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . + /// The work array. The array must have a length of at least N, + /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal + /// work size value. + /// This is equivalent to the GETRF and GETRI LAPACK routines. + public void LUInverse(float[] a, int order, float[] work) { throw new NotImplementedException(); } - public void LUInverseFactored(float[] a, int[] ipiv, float[] work) + /// + /// Computes the inverse of a previously factored matrix. + /// + /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . + /// The pivot indices of . + /// The work array. The array must have a length of at least N, + /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal + /// work size value. + /// This is equivalent to the GETRI LAPACK routine. + public void LUInverseFactored(float[] a, int order, int[] ipiv, float[] work) { throw new NotImplementedException(); } - public void LUSolve(int columnsOfB, float[] a, float[] b) + public void LUSolve(int columnsOfB, float[] a, int order, float[] b) { throw new NotImplementedException(); } - public void LUSolveFactored(int columnsOfB, float[] a, int ipiv, float[] b) + public void LUSolveFactored(int columnsOfB, float[] a, int order, int[] ipiv, float[] b) { throw new NotImplementedException(); } - public void LUSolve(Transpose transposeA, int columnsOfB, float[] a, float[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, float[] a, int order, float[] b) { throw new NotImplementedException(); } - public void LUSolveFactored(Transpose transposeA, int columnsOfB, float[] a, int ipiv, float[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, float[] a, int order, int[] ipiv, float[] b) { throw new NotImplementedException(); } @@ -4677,42 +5007,74 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new NotImplementedException(); } - public void LUInverse(Complex[] a) + /// + /// Computes the inverse of matrix using LU factorization. + /// + /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . + /// This is equivalent to the GETRF and GETRI LAPACK routines. + public void LUInverse(Complex[] a, int order) { throw new NotImplementedException(); } - public void LUInverseFactored(Complex[] a, int[] ipiv) + /// + /// Computes the inverse of a previously factored matrix. + /// + /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . + /// The pivot indices of . + /// This is equivalent to the GETRI LAPACK routine. + public void LUInverseFactored(Complex[] a, int order, int[] ipiv) { throw new NotImplementedException(); } - public void LUInverse(Complex[] a, Complex[] work) + /// + /// Computes the inverse of matrix using LU factorization. + /// + /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . + /// The work array. The array must have a length of at least N, + /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal + /// work size value. + /// This is equivalent to the GETRF and GETRI LAPACK routines. + public void LUInverse(Complex[] a, int order, Complex[] work) { throw new NotImplementedException(); } - public void LUInverseFactored(Complex[] a, int[] ipiv, Complex[] work) + /// + /// Computes the inverse of a previously factored matrix. + /// + /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . + /// The pivot indices of . + /// The work array. The array must have a length of at least N, + /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal + /// work size value. + /// This is equivalent to the GETRI LAPACK routine. + public void LUInverseFactored(Complex[] a, int order, int[] ipiv, Complex[] work) { throw new NotImplementedException(); } - public void LUSolve(int columnsOfB, Complex[] a, Complex[] b) + public void LUSolve(int columnsOfB, Complex[] a, int order, Complex[] b) { throw new NotImplementedException(); } - public void LUSolveFactored(int columnsOfB, Complex[] a, int ipiv, Complex[] b) + public void LUSolveFactored(int columnsOfB, Complex[] a, int order, int[] ipiv, Complex[] b) { throw new NotImplementedException(); } - public void LUSolve(Transpose transposeA, int columnsOfB, Complex[] a, Complex[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, Complex[] a, int order, Complex[] b) { throw new NotImplementedException(); } - public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex[] a, int ipiv, Complex[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex[] a, int order, int[] ipiv, Complex[] b) { throw new NotImplementedException(); } @@ -5595,42 +5957,74 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new NotImplementedException(); } - public void LUInverse(Complex32[] a) + /// + /// Computes the inverse of matrix using LU factorization. + /// + /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . + /// This is equivalent to the GETRF and GETRI LAPACK routines. + public void LUInverse(Complex32[] a, int order) { throw new NotImplementedException(); } - public void LUInverseFactored(Complex32[] a, int[] ipiv) + /// + /// Computes the inverse of a previously factored matrix. + /// + /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . + /// The pivot indices of . + /// This is equivalent to the GETRI LAPACK routine. + public void LUInverseFactored(Complex32[] a, int order, int[] ipiv) { throw new NotImplementedException(); } - public void LUInverse(Complex32[] a, Complex32[] work) + /// + /// Computes the inverse of matrix using LU factorization. + /// + /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . + /// The work array. The array must have a length of at least N, + /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal + /// work size value. + /// This is equivalent to the GETRF and GETRI LAPACK routines. + public void LUInverse(Complex32[] a, int order, Complex32[] work) { throw new NotImplementedException(); } - public void LUInverseFactored(Complex32[] a, int[] ipiv, Complex32[] work) + /// + /// Computes the inverse of a previously factored matrix. + /// + /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . + /// The pivot indices of . + /// The work array. The array must have a length of at least N, + /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal + /// work size value. + /// This is equivalent to the GETRI LAPACK routine. + public void LUInverseFactored(Complex32[] a, int order, int[] ipiv, Complex32[] work) { throw new NotImplementedException(); } - public void LUSolve(int columnsOfB, Complex32[] a, Complex32[] b) + public void LUSolve(int columnsOfB, Complex32[] a, int order, Complex32[] b) { throw new NotImplementedException(); } - public void LUSolveFactored(int columnsOfB, Complex32[] a, int ipiv, Complex32[] b) + public void LUSolveFactored(int columnsOfB, Complex32[] a, int order, int[] ipiv, Complex32[] b) { throw new NotImplementedException(); } - public void LUSolve(Transpose transposeA, int columnsOfB, Complex32[] a, Complex32[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, Complex32[] a, int order, Complex32[] b) { throw new NotImplementedException(); } - public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex32[] a, int ipiv, Complex32[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex32[] a, int order, int[] ipiv, Complex32[] b) { throw new NotImplementedException(); } diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs index 43d26741..dbe3826d 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs @@ -346,8 +346,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(double[] a) + public void LUInverse(double[] a, int order) { throw new NotImplementedException(); } @@ -356,9 +357,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(double[] a, int[] ipiv) + public void LUInverseFactored(double[] a, int order, int[] ipiv) { throw new NotImplementedException(); } @@ -367,11 +369,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(double[] a, double[] work) + public void LUInverse(double[] a, int order, double[] work) { throw new NotImplementedException(); } @@ -380,12 +383,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(double[] a, int[] ipiv, double[] work) + public void LUInverseFactored(double[] a, int order, int[] ipiv, double[] work) { throw new NotImplementedException(); } @@ -395,9 +399,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(int columnsOfB, double[] a, double[] b) + public void LUSolve(int columnsOfB, double[] a, int order, double[] b) { throw new NotImplementedException(); } @@ -407,10 +412,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(int columnsOfB, double[] a, int ipiv, double[] b) + public void LUSolveFactored(int columnsOfB, double[] a, int order, int[] ipiv, double[] b) { throw new NotImplementedException(); } @@ -421,9 +427,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// How to transpose the matrix. /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(Transpose transposeA, int columnsOfB, double[] a, double[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, double[] a, int order, double[] b) { throw new NotImplementedException(); } @@ -434,10 +441,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// How to transpose the matrix. /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(Transpose transposeA, int columnsOfB, double[] a, int ipiv, double[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, double[] a, int order, int[] ipiv, double[] b) { throw new NotImplementedException(); } @@ -957,7 +965,6 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl SafeNativeMethods.s_matrix_multiply(transposeA, transposeB, m, n, k, alpha, a, b, beta, c); } - /// /// /// Computes the LUP factorization of A. P*A = L*U. /// @@ -976,8 +983,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(float[] a) + public void LUInverse(float[] a, int order) { throw new NotImplementedException(); } @@ -986,9 +994,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(float[] a, int[] ipiv) + public void LUInverseFactored(float[] a, int order, int[] ipiv) { throw new NotImplementedException(); } @@ -997,11 +1006,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(float[] a, float[] work) + public void LUInverse(float[] a, int order, float[] work) { throw new NotImplementedException(); } @@ -1010,12 +1020,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(float[] a, int[] ipiv, float[] work) + public void LUInverseFactored(float[] a, int order, int[] ipiv, float[] work) { throw new NotImplementedException(); } @@ -1025,9 +1036,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(int columnsOfB, float[] a, float[] b) + public void LUSolve(int columnsOfB, float[] a, int order, float[] b) { throw new NotImplementedException(); } @@ -1037,10 +1049,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(int columnsOfB, float[] a, int ipiv, float[] b) + public void LUSolveFactored(int columnsOfB, float[] a, int order, int[] ipiv, float[] b) { throw new NotImplementedException(); } @@ -1051,9 +1064,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// How to transpose the matrix. /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(Transpose transposeA, int columnsOfB, float[] a, float[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, float[] a, int order, float[] b) { throw new NotImplementedException(); } @@ -1064,10 +1078,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// How to transpose the matrix. /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(Transpose transposeA, int columnsOfB, float[] a, int ipiv, float[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, float[] a, int order, int[] ipiv, float[] b) { throw new NotImplementedException(); } @@ -1604,8 +1619,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(Complex[] a) + public void LUInverse(Complex[] a, int order) { throw new NotImplementedException(); } @@ -1614,9 +1630,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(Complex[] a, int[] ipiv) + public void LUInverseFactored(Complex[] a, int order, int[] ipiv) { throw new NotImplementedException(); } @@ -1625,11 +1642,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(Complex[] a, Complex[] work) + public void LUInverse(Complex[] a, int order, Complex[] work) { throw new NotImplementedException(); } @@ -1638,12 +1656,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(Complex[] a, int[] ipiv, Complex[] work) + public void LUInverseFactored(Complex[] a, int order, int[] ipiv, Complex[] work) { throw new NotImplementedException(); } @@ -1653,9 +1672,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(int columnsOfB, Complex[] a, Complex[] b) + public void LUSolve(int columnsOfB, Complex[] a, int order, Complex[] b) { throw new NotImplementedException(); } @@ -1665,10 +1685,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(int columnsOfB, Complex[] a, int ipiv, Complex[] b) + public void LUSolveFactored(int columnsOfB, Complex[] a, int order, int[] ipiv, Complex[] b) { throw new NotImplementedException(); } @@ -1679,9 +1700,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// How to transpose the matrix. /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(Transpose transposeA, int columnsOfB, Complex[] a, Complex[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, Complex[] a, int order, Complex[] b) { throw new NotImplementedException(); } @@ -1692,10 +1714,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// How to transpose the matrix. /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex[] a, int ipiv, Complex[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex[] a, int order, int[] ipiv, Complex[] b) { throw new NotImplementedException(); } @@ -2232,8 +2255,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(Complex32[] a) + public void LUInverse(Complex32[] a, int order) { throw new NotImplementedException(); } @@ -2242,9 +2266,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(Complex32[] a, int[] ipiv) + public void LUInverseFactored(Complex32[] a, int order, int[] ipiv) { throw new NotImplementedException(); } @@ -2253,11 +2278,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of matrix using LU factorization. /// /// The N by N matrix to invert. Contains the inverse On exit. + /// The order of the square matrix . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRF and GETRI LAPACK routines. - public void LUInverse(Complex32[] a, Complex32[] work) + public void LUInverse(Complex32[] a, int order, Complex32[] work) { throw new NotImplementedException(); } @@ -2266,12 +2292,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the inverse of a previously factored matrix. /// /// The LU factored N by N matrix. Contains the inverse On exit. + /// The order of the square matrix . /// The pivot indices of . /// The work array. The array must have a length of at least N, /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal /// work size value. /// This is equivalent to the GETRI LAPACK routine. - public void LUInverseFactored(Complex32[] a, int[] ipiv, Complex32[] work) + public void LUInverseFactored(Complex32[] a, int order, int[] ipiv, Complex32[] work) { throw new NotImplementedException(); } @@ -2281,9 +2308,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(int columnsOfB, Complex32[] a, Complex32[] b) + public void LUSolve(int columnsOfB, Complex32[] a, int order, Complex32[] b) { throw new NotImplementedException(); } @@ -2293,10 +2321,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(int columnsOfB, Complex32[] a, int ipiv, Complex32[] b) + public void LUSolveFactored(int columnsOfB, Complex32[] a, int order, int[] ipiv, Complex32[] b) { throw new NotImplementedException(); } @@ -2307,9 +2336,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// How to transpose the matrix. /// The number of columns of B. /// The square matrix A. + /// The order of the square matrix . /// The B matrix. /// This is equivalent to the GETRF and GETRS LAPACK routines. - public void LUSolve(Transpose transposeA, int columnsOfB, Complex32[] a, Complex32[] b) + public void LUSolve(Transpose transposeA, int columnsOfB, Complex32[] a, int order, Complex32[] b) { throw new NotImplementedException(); } @@ -2320,10 +2350,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// How to transpose the matrix. /// The number of columns of B. /// The factored A matrix. + /// The order of the square matrix . /// The pivot indices of . /// The B matrix. /// This is equivalent to the GETRS LAPACK routine. - public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex32[] a, int ipiv, Complex32[] b) + public void LUSolveFactored(Transpose transposeA, int columnsOfB, Complex32[] a, int order, int[] ipiv, Complex32[] b) { throw new NotImplementedException(); } diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs b/src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs index 3283fb06..8524e4ef 100644 --- a/src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs +++ b/src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs @@ -122,8 +122,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization // LU solve by overwriting result. var dfactors = (DenseMatrix)Factors; - throw new NotImplementedException(); - //Control.LinearAlgebraProvider.LUSolveFactored(dfactors.Data, dfactors.RowCount, dresult.Data, dresult.RowCount, dresult.ColumnCount); + Control.LinearAlgebraProvider.LUSolveFactored(input.ColumnCount, dfactors.Data, dfactors.RowCount, Pivots, dresult.Data); } /// @@ -171,9 +170,19 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization Buffer.BlockCopy(dinput.Data, 0, dresult.Data, 0, dinput.Data.Length * Constants.SizeOfDouble); // LU solve by overwriting result. - var dfactors = Factors as DenseMatrix; - throw new NotImplementedException(); - //Control.LinearAlgebraProvider.LUSolveFactored(dfactors.Data, dfactors.RowCount, dresult.Data, dresult.Count, 1); + var dfactors = (DenseMatrix)Factors; + Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Data); + } + + /// + /// Returns the inverse of this matrix. The inverse is calculated using LU decomposition. + /// + /// The inverse of this matrix. + public override Matrix Inverse() + { + var result = (DenseMatrix)Factors.Clone(); + Control.LinearAlgebraProvider.LUInverseFactored(result.Data, result.RowCount, Pivots); + return result; } } } diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/LU.cs b/src/Numerics/LinearAlgebra/Double/Factorization/LU.cs index 465330fd..2b0c35e5 100644 --- a/src/Numerics/LinearAlgebra/Double/Factorization/LU.cs +++ b/src/Numerics/LinearAlgebra/Double/Factorization/LU.cs @@ -186,5 +186,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization /// The right hand side vector, b. /// The left hand side , x. public abstract void Solve(Vector input, Vector result); + + /// + /// Returns the inverse of this matrix. The inverse is calculated using LU decomposition. + /// + /// The inverse of this matrix. + public abstract Matrix Inverse(); } } diff --git a/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs b/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs index 357fb0a8..1ee9c6b2 100644 --- a/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs +++ b/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs @@ -28,6 +28,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double { using System; using Distributions; + using Factorization; using Properties; using Threading; @@ -831,7 +832,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// effective numerical rank, obtained from SVD public virtual int Rank() { - throw new NotImplementedException(); + var svd = this.Svd(false); + return svd.Rank; } /// Calculates the condition number of this matrix. @@ -839,14 +841,34 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// The condition number is calculated using singular value decomposition. public virtual double ConditionNumber() { - throw new NotImplementedException(); + var svd = this.Svd(false); + return svd.ConditionNumber; } /// Computes the determinant of this matrix. /// The determinant of this matrix. public virtual double Determinant() { - throw new NotImplementedException(); + if (RowCount != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + var lu = this.LU(); + return lu.Determinant; + } + + /// Computes the inverse of this matrix. + /// The inverse of this matrix. + public virtual Matrix Inverse() + { + if (RowCount != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + var lu = this.LU(); + return lu.Inverse(); } /// diff --git a/src/Numerics/LinearAlgebra/Double/Matrix.cs b/src/Numerics/LinearAlgebra/Double/Matrix.cs index f5888801..e279548d 100644 --- a/src/Numerics/LinearAlgebra/Double/Matrix.cs +++ b/src/Numerics/LinearAlgebra/Double/Matrix.cs @@ -1088,12 +1088,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double if (columnLength > subMatrix.ColumnCount) { - throw new ArgumentOutOfRangeException("columnLength", "columnLength can be at most the number of columns in subMatrix."); + throw new ArgumentOutOfRangeException("columnLength", @"columnLength can be at most the number of columns in subMatrix."); } if (rowLength > subMatrix.RowCount) { - throw new ArgumentOutOfRangeException("rowLength", "rowLength can be at most the number of rows in subMatrix."); + throw new ArgumentOutOfRangeException("rowLength", @"rowLength can be at most the number of rows in subMatrix."); } var colMax = columnIndex + columnLength; diff --git a/src/UnitTests/LinearAlgebraTests/Double/Factorization/LUTests.cs b/src/UnitTests/LinearAlgebraTests/Double/Factorization/LUTests.cs index 66b6a183..2fb150ca 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/Factorization/LUTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/Factorization/LUTests.cs @@ -30,7 +30,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization { - using System.Collections.Generic; using MbUnit.Framework; using LinearAlgebra.Double; using LinearAlgebra.Double.Factorization; @@ -43,44 +42,30 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization [Row(100)] public void CanFactorizeIdentity(int order) { - var I = DenseMatrix.Identity(order); - var lu = I.LU(); + var matrixI = DenseMatrix.Identity(order); + var factorLU = matrixI.LU(); // Check lower triangular part. - var L = lu.L; - Assert.AreEqual(I.RowCount, L.RowCount); - Assert.AreEqual(I.ColumnCount, L.ColumnCount); - for (var i = 0; i < L.RowCount; i++) + var matrixL = factorLU.L; + Assert.AreEqual(matrixI.RowCount, matrixL.RowCount); + Assert.AreEqual(matrixI.ColumnCount, matrixL.ColumnCount); + for (var i = 0; i < matrixL.RowCount; i++) { - for (var j = 0; j < L.ColumnCount; j++) + for (var j = 0; j < matrixL.ColumnCount; j++) { - if (i == j) - { - Assert.AreEqual(1.0, L[i, j]); - } - else - { - Assert.AreEqual(0.0, L[i, j]); - } + Assert.AreEqual(i == j ? 1.0 : 0.0, matrixL[i, j]); } } // Check upper triangular part. - var U = lu.U; - Assert.AreEqual(I.RowCount, U.RowCount); - Assert.AreEqual(I.ColumnCount, U.ColumnCount); - for (var i = 0; i < U.RowCount; i++) + var matrixU = factorLU.U; + Assert.AreEqual(matrixI.RowCount, matrixU.RowCount); + Assert.AreEqual(matrixI.ColumnCount, matrixU.ColumnCount); + for (var i = 0; i < matrixU.RowCount; i++) { - for (var j = 0; j < U.ColumnCount; j++) + for (var j = 0; j < matrixU.ColumnCount; j++) { - if (i == j) - { - Assert.AreEqual(1.0, U[i, j]); - } - else - { - Assert.AreEqual(0.0, U[i, j]); - } + Assert.AreEqual(i == j ? 1.0 : 0.0, matrixU[i, j]); } } } @@ -92,7 +77,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization public void LUFailsWithNonSquareMatrix(int row, int col) { var I = new DenseMatrix(row, col); - var lu = I.LU(); + I.LU(); } [Test] @@ -116,47 +101,264 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization [MultipleAsserts] public void CanFactorizeRandomMatrix(int order) { - var X = MatrixLoader.GenerateRandomMatrix(order, order); - var lu = X.LU(); - var L = lu.L; - var U = lu.U; + var matrixX = MatrixLoader.GenerateRandomMatrix(order, order); + var factorLU = matrixX.LU(); + var matrixL = factorLU.L; + var matrixU = factorLU.U; // Make sure the factors have the right dimensions. - Assert.AreEqual(order, L.RowCount); - Assert.AreEqual(order, L.ColumnCount); - Assert.AreEqual(order, U.RowCount); - Assert.AreEqual(order, U.ColumnCount); + Assert.AreEqual(order, matrixL.RowCount); + Assert.AreEqual(order, matrixL.ColumnCount); + Assert.AreEqual(order, matrixU.RowCount); + Assert.AreEqual(order, matrixU.ColumnCount); // Make sure the L factor is lower triangular. - for (int i = 0; i < L.RowCount; i++) + for (var i = 0; i < matrixL.RowCount; i++) { - Assert.AreEqual(1.0, L[i, i]); - for (int j = i+1; j < L.ColumnCount; j++) + Assert.AreEqual(1.0, matrixL[i, i]); + for (var j = i+1; j < matrixL.ColumnCount; j++) { - Assert.AreEqual(0.0, L[i, j]); + Assert.AreEqual(0.0, matrixL[i, j]); } } // Make sure the U factor is upper triangular. - for (int i = 0; i < L.RowCount; i++) + for (var i = 0; i < matrixL.RowCount; i++) + { + for (var j = 0; j < i; j++) + { + Assert.AreEqual(0.0, matrixU[i, j]); + } + } + + // Make sure the LU factor times it's transpose is the original matrix. + var matrixXfromLU = matrixL * matrixU; + var permutationInverse = factorLU.P.Inverse(); + matrixXfromLU.PermuteRows(permutationInverse); + for (var i = 0; i < matrixXfromLU.RowCount; i++) + { + for (var j = 0; j < matrixXfromLU.ColumnCount; j++) + { + Assert.AreApproximatelyEqual(matrixX[i, j], matrixXfromLU[i, j], 1.0e-11); + } + } + } + + [Test] + [Row(1)] + [Row(2)] + [Row(5)] + [Row(10)] + [Row(50)] + [Row(100)] + [MultipleAsserts] + public void CanSolveForRandomVector(int order) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(order, order); + var matrixACopy = matrixA.Clone(); + var factorLU = matrixA.LU(); + + var vectorb = MatrixLoader.GenerateRandomVector(order); + var resultx = factorLU.Solve(vectorb); + + Assert.AreEqual(matrixA.ColumnCount, resultx.Count); + + var bReconstruct = matrixA * resultx; + + // Check the reconstruction. + for (var i = 0; i < order; i++) + { + Assert.AreApproximatelyEqual(vectorb[i], bReconstruct[i], 1.0e-11); + } + + // Make sure A didn't change. + for (var i = 0; i < matrixA.RowCount; i++) { - for (int j = 0; j < i; j++) + for (var j = 0; j < matrixA.ColumnCount; j++) { - Assert.AreEqual(0.0, U[i, j]); + Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); + } + } + } + + [Test] + [Row(1)] + [Row(4)] + [Row(8)] + [Row(10)] + [Row(50)] + [Row(100)] + [MultipleAsserts] + public void CanSolveForRandomMatrix(int order) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(order, order); + var matrixACopy = matrixA.Clone(); + var factorLU = matrixA.LU(); + + var matrixB = MatrixLoader.GenerateRandomMatrix(order, order); + var matrixX = factorLU.Solve(matrixB); + + // The solution X row dimension is equal to the column dimension of A + Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + // The solution X has the same number of columns as B + Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + + var matrixBReconstruct = matrixA * matrixX; + + // Check the reconstruction. + for (var i = 0; i < matrixB.RowCount; i++) + { + for (var j = 0; j < matrixB.ColumnCount; j++) + { + Assert.AreApproximatelyEqual(matrixB[i, j], matrixBReconstruct[i, j], 1.0e-11); } } - // Make sure the cholesky factor times it's transpose is the original matrix. - var XfromLU = L * U; - var Pinv = lu.P.Inverse(); - XfromLU.PermuteRows(Pinv); - for (int i = 0; i < XfromLU.RowCount; i++) + // Make sure A didn't change. + for (var i = 0; i < matrixA.RowCount; i++) { - for (int j = 0; j < XfromLU.ColumnCount; j++) + for (var j = 0; j < matrixA.ColumnCount; j++) { - Assert.AreApproximatelyEqual(X[i, j], XfromLU[i, j], 1.0e-11); + Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); } } } + + [Test] + [Row(1)] + [Row(2)] + [Row(5)] + [Row(10)] + [Row(50)] + [Row(100)] + [MultipleAsserts] + public void CanSolveForRandomVectorWhenResultVectorGiven(int order) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(order, order); + var matrixACopy = matrixA.Clone(); + var factorLU = matrixA.LU(); + var vectorb = MatrixLoader.GenerateRandomVector(order); + var vectorbCopy = vectorb.Clone(); + var resultx = new DenseVector(order); + factorLU.Solve(vectorb, resultx); + + Assert.AreEqual(vectorb.Count, resultx.Count); + + var bReconstruct = matrixA * resultx; + + // Check the reconstruction. + for (var i = 0; i < vectorb.Count; i++) + { + Assert.AreApproximatelyEqual(vectorb[i], bReconstruct[i], 1.0e-11); + } + + // Make sure A didn't change. + for (var i = 0; i < matrixA.RowCount; i++) + { + for (var j = 0; j < matrixA.ColumnCount; j++) + { + Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); + } + } + + // Make sure b didn't change. + for (var i = 0; i < vectorb.Count; i++) + { + Assert.AreEqual(vectorbCopy[i], vectorb[i]); + } + } + + [Test] + [Row(1)] + [Row(4)] + [Row(8)] + [Row(10)] + [Row(50)] + [Row(100)] + [MultipleAsserts] + public void CanSolveForRandomMatrixWhenResultMatrixGiven(int order) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(order, order); + var matrixACopy = matrixA.Clone(); + var factorLU = matrixA.LU(); + + var matrixB = MatrixLoader.GenerateRandomMatrix(order, order); + var matrixBCopy = matrixB.Clone(); + + var matrixX = new DenseMatrix(order, order); + factorLU.Solve(matrixB, matrixX); + + // The solution X row dimension is equal to the column dimension of A + Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + // The solution X has the same number of columns as B + Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + + var matrixBReconstruct = matrixA * matrixX; + + // Check the reconstruction. + for (var i = 0; i < matrixB.RowCount; i++) + { + for (var j = 0; j < matrixB.ColumnCount; j++) + { + Assert.AreApproximatelyEqual(matrixB[i, j], matrixBReconstruct[i, j], 1.0e-11); + } + } + + // Make sure A didn't change. + for (var i = 0; i < matrixA.RowCount; i++) + { + for (var j = 0; j < matrixA.ColumnCount; j++) + { + Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); + } + } + + // Make sure B didn't change. + for (var i = 0; i < matrixB.RowCount; i++) + { + for (var j = 0; j < matrixB.ColumnCount; j++) + { + Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); + } + } + } + + [Test] + [Row(1)] + [Row(4)] + [Row(8)] + [Row(10)] + [Row(50)] + [Row(100)] + [MultipleAsserts] + public void CanInverse(int order) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(order, order); + var matrixACopy = matrixA.Clone(); + var factorLU = matrixA.LU(); + + var matrixAInverse = factorLU.Inverse(); + + // The inverse dimension is equal A + Assert.AreEqual(matrixAInverse.RowCount, matrixAInverse.RowCount); + Assert.AreEqual(matrixAInverse.ColumnCount, matrixAInverse.ColumnCount); + + var matrixIdentity = matrixA * matrixAInverse; + + // Make sure A didn't change. + for (var i = 0; i < matrixA.RowCount; i++) + { + for (var j = 0; j < matrixA.ColumnCount; j++) + { + Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); + } + } + + // Check if multiplication of A and AI produced identity matrix. + for (var i = 0; i < matrixIdentity.RowCount; i++) + { + Assert.AreApproximatelyEqual(matrixIdentity[i, i], 1.0, 1.0e-11); + } + } } }