From e946954ec42a675927d90dca410c4bdb2c3bcaf1 Mon Sep 17 00:00:00 2001 From: Jurgen Van Gael Date: Wed, 19 May 2010 05:18:14 +0800 Subject: [PATCH] Started implementing LU decomposition. --- .../ILinearAlgebraProviderOfT.cs | 13 +- .../ManagedLinearAlgebraProvider.cs | 11 +- .../NativeAlgebraProvider.include | 15 +- .../Double/Factorization/Cholesky.cs | 26 ++- .../Double/Factorization/DenseCholesky.cs | 36 ---- .../Double/Factorization/DenseLU.cs | 179 ++++++++++++++++++ .../LinearAlgebra/Double/Factorization/LU.cs | 171 +++++++++++++++++ src/Numerics/LinearAlgebra/Double/Matrix.cs | 103 ++++++++++ src/Numerics/Numerics.csproj | 2 + 9 files changed, 504 insertions(+), 52 deletions(-) create mode 100644 src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs create mode 100644 src/Numerics/LinearAlgebra/Double/Factorization/LU.cs diff --git a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs index 8bf94015..d42ac4cf 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs @@ -210,14 +210,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra int aRows, int aColumns, T[] b, int bRows, int bColumns, T beta, T[] c); /// - /// Computes the LU factorization of A. + /// Computes the LUP factorization of A. P*A = L*U. /// - /// An m by n matrix. The matrix is overwritten with the - /// the LU factorization On exit. - /// On exit, it contains the pivot indices. The size - /// of the array must be min(m,n). + /// An by matrix. The matrix is overwritten with the + /// the LU factorization on exit. The lower triangular factor L is stored in under the diagonal of (the diagonal is always 1.0 + /// for the L factor). The upper triangular factor U is stored on and above the diagonal of . + /// The order of the square matrix . + /// On exit, it contains the pivot indices. The size of the array must be . /// This is equivalent to the GETRF LAPACK routine. - void LUFactor(T[] a, int[] ipiv); + void LUFactor(T[] a, int aOrder, int[] ipiv); /// /// Computes the inverse of matrix using LU factorization. diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs index 260d38d1..a49eea9a 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs @@ -688,7 +688,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } } - public void LUFactor(double[] a, int[] ipiv) + /// + /// Computes the LUP factorization of A. P*A = L*U. + /// + /// An by matrix. The matrix is overwritten with the + /// the LU factorization on exit. The lower triangular factor L is stored in under the diagonal of (the diagonal is always 1.0 + /// for the L factor). The upper triangular factor U is stored on and above the diagonal of . + /// The order of the square matrix . + /// On exit, it contains the pivot indices. The size of the array must be . + /// This is equivalent to the GETRF LAPACK routine. + public void LUFactor(double[] a, int aOrder, int[] ipiv) { throw new NotImplementedException(); } diff --git a/src/Numerics/Algorithms/LinearAlgebra/NativeAlgebraProvider.include b/src/Numerics/Algorithms/LinearAlgebra/NativeAlgebraProvider.include index f1a2c689..9ee36977 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/NativeAlgebraProvider.include +++ b/src/Numerics/Algorithms/LinearAlgebra/NativeAlgebraProvider.include @@ -333,16 +333,17 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> SafeNativeMethods.d_matrix_multiply(transposeA, transposeB, m, n, k, alpha, a, b, beta, c); } - + /// - /// Computes the LU factorization of A. + /// Computes the LUP factorization of A. P*A = L*U. /// - /// An m by n matrix. The matrix is overwritten with the - /// the LU factorization On exit. - /// On exit, it contains the pivot indices. The size - /// of the array must be min(m,n). + /// An by matrix. The matrix is overwritten with the + /// the LU factorization on exit. The lower triangular factor L is stored in under the diagonal of (the diagonal is always 1.0 + /// for the L factor). The upper triangular factor U is stored on and above the diagonal of . + /// The order of the square matrix . + /// On exit, it contains the pivot indices. The size of the array must be . /// This is equivalent to the GETRF LAPACK routine. - public void LUFactor(double[] a, int[] ipiv) + public void LUFactor(double[] a, int aOrder, int[] ipiv) { throw new NotImplementedException(); } diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/Cholesky.cs b/src/Numerics/LinearAlgebra/Double/Factorization/Cholesky.cs index 02f8839b..5557e403 100644 --- a/src/Numerics/LinearAlgebra/Double/Factorization/Cholesky.cs +++ b/src/Numerics/LinearAlgebra/Double/Factorization/Cholesky.cs @@ -110,7 +110,18 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization /// /// The right hand side , B. /// The left hand side , X. - public abstract Matrix Solve(Matrix input); + public virtual Matrix Solve(Matrix input) + { + // Check for proper arguments. + if (input == null) + { + throw new ArgumentNullException("input"); + } + + var X = input.CreateMatrix(input.RowCount, input.ColumnCount); + Solve(input, X); + return X; + } /// /// Solves a system of linear equations, AX = B, with A Cholesky factorized. @@ -124,7 +135,18 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization /// /// The right hand side vector, b. /// The left hand side , x. - public abstract Vector Solve(Vector input); + public virtual Vector Solve(Vector input) + { + // Check for proper arguments. + if (input == null) + { + throw new ArgumentNullException("input"); + } + + var x = input.CreateVector(input.Count); + Solve(input, x); + return x; + } /// /// Solves a system of linear equations, Ax = b, with A Cholesky factorized. diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/DenseCholesky.cs b/src/Numerics/LinearAlgebra/Double/Factorization/DenseCholesky.cs index 67ad3bb5..4d55a7a5 100644 --- a/src/Numerics/LinearAlgebra/Double/Factorization/DenseCholesky.cs +++ b/src/Numerics/LinearAlgebra/Double/Factorization/DenseCholesky.cs @@ -70,24 +70,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization mFactor = factor; } - /// - /// Solves a system of linear equations, AX = B, with A Cholesky factorized. - /// - /// The right hand side , B. - /// The left hand side , X. - public override Matrix Solve(Matrix input) - { - // Check for proper arguments. - if (input == null) - { - throw new ArgumentNullException("input"); - } - - var X = new DenseMatrix(input.RowCount, input.ColumnCount); - Solve(input, X); - return X; - } - /// /// Solves a system of linear equations, AX = B, with A Cholesky factorized. /// @@ -142,24 +124,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Data, dresult.RowCount, dresult.ColumnCount); } - /// - /// Solves a system of linear equations, Ax = b, with A Cholesky factorized. - /// - /// The right hand side vector, b. - /// The left hand side , x. - public override Vector Solve(Vector input) - { - // Check for proper arguments. - if (input == null) - { - throw new ArgumentNullException("input"); - } - - var x = new DenseVector(input.Count); - Solve(input, x); - return x; - } - /// /// Solves a system of linear equations, Ax = b, with A Cholesky factorized. /// diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs b/src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs new file mode 100644 index 00000000..deea47c8 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/Factorization/DenseLU.cs @@ -0,0 +1,179 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// http://mathnetnumerics.codeplex.com +// +// Copyright (c) 2009-2010 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Double.Factorization +{ + using System; + using Properties; + + /// + /// A class which encapsulates the functionality of an LU factorization. + /// For a matrix A, the LU factorization is a pair of lower triangular matrix L and + /// upper triangular matrix U so that A = L*U. + /// + /// + /// The computation of the LU factorization is done at construction time. + /// + public class DenseLU : LU + { + /// + /// Initializes a new instance of the class. This object will compute the + /// LU factorization when the constructor is called and cache it's factorization. + /// + /// The matrix to factor. + /// If is null. + /// If is not a square matrix. + public DenseLU(DenseMatrix matrix) + { + if (matrix == null) + { + throw new ArgumentNullException("matrix"); + } + + if (matrix.RowCount != matrix.ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + // Create an array for the pivot indices. + mPivots = new int[matrix.RowCount]; + + // Create a new matrix for the LU factors, then perform factorization (while overwriting). + var factors = (DenseMatrix)matrix.Clone(); + Control.LinearAlgebraProvider.LUFactor(factors.Data, factors.RowCount, mPivots); + mFactors = factors; + } + + /// + /// Solves a system of linear equations, AX = B, with A LU factorized. + /// + /// The right hand side , B. + /// The left hand side , X. + public override void Solve(Matrix input, Matrix result) + { + // Check for proper arguments. + if (input == null) + { + throw new ArgumentNullException("input"); + } + + if (result == null) + { + throw new ArgumentNullException("result"); + } + + // Check for proper dimensions. + if (result.RowCount != input.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); + } + + if (result.ColumnCount != input.ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); + } + + if (input.RowCount != mFactors.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions); + } + + var dinput = input as DenseMatrix; + if (dinput == null) + { + throw new NotImplementedException("Can only do LU factorization for dense matrices at the moment."); + } + + var dresult = result as DenseMatrix; + if (dresult == null) + { + throw new NotImplementedException("Can only do LU factorization for dense matrices at the moment."); + } + + // Copy the contents of input to result. + Buffer.BlockCopy(dinput.Data, 0, dresult.Data, 0, dinput.Data.Length * Constants.SizeOfDouble); + + // LU solve by overwriting result. + var dfactors = mFactors as DenseMatrix; + throw new NotImplementedException(); + //Control.LinearAlgebraProvider.LUSolveFactored(dfactors.Data, dfactors.RowCount, dresult.Data, dresult.RowCount, dresult.ColumnCount); + } + + /// + /// Solves a system of linear equations, Ax = b, with A LU factorized. + /// + /// The right hand side vector, b. + /// The left hand side , x. + public override void Solve(Vector input, Vector result) + { + // Check for proper arguments. + if (input == null) + { + throw new ArgumentNullException("input"); + } + + if (result == null) + { + throw new ArgumentNullException("result"); + } + + // Check for proper dimensions. + if (input.Count != result.Count) + { + throw new ArgumentException(Resources.ArgumentVectorsSameLength); + } + + if (input.Count != mFactors.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions); + } + + var dinput = input as DenseVector; + if (dinput == null) + { + throw new NotImplementedException("Can only do LU factorization for dense vectors at the moment."); + } + + var dresult = result as DenseVector; + if (dresult == null) + { + throw new NotImplementedException("Can only do LU factorization for dense vectors at the moment."); + } + + // Copy the contents of input to result. + Buffer.BlockCopy(dinput.Data, 0, dresult.Data, 0, dinput.Data.Length * Constants.SizeOfDouble); + + // LU solve by overwriting result. + var dfactors = mFactors as DenseMatrix; + throw new NotImplementedException(); + //Control.LinearAlgebraProvider.LUSolveFactored(dfactors.Data, dfactors.RowCount, dresult.Data, dresult.Count, 1); + } + } +} diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/LU.cs b/src/Numerics/LinearAlgebra/Double/Factorization/LU.cs new file mode 100644 index 00000000..de7a25c2 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/Factorization/LU.cs @@ -0,0 +1,171 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// http://mathnetnumerics.codeplex.com +// +// Copyright (c) 2009-2010 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Double.Factorization +{ + using System; + using Properties; + + /// + /// A class which encapsulates the functionality of an LU factorization. + /// For a matrix A, the LU factorization is a pair of lower triangular matrix L and + /// upper triangular matrix U so that A = L*U. + /// In the Math.Net implementation we also store a set of pivot elements for increased + /// numerical stability. The pivot elements encode a permutation matrix P such that P*A = L*U. + /// + /// + /// The computation of the LU factorization is done at construction time. + /// + public abstract class LU + { + /// + /// Stores both the L and U factors in the same matrix.. + /// + protected Matrix mFactors; + + /// + /// Stores the pivot indices of the LU factorization. + /// + protected int[] mPivots; + + /// + /// Internal method which routes the call to perform the LU factorization to the appropriate class. + /// + /// The matrix to factor. + /// An LU factorization object. + internal static LU Create(Matrix matrix) + { + var dense = matrix as DenseMatrix; + if (dense != null) + { + return new DenseLU(dense); + } + + throw new NotImplementedException(); + } + + /// + /// Returns the lower triangular factor. + /// + public virtual Matrix L + { + get + { + Matrix result = mFactors.GetLowerTriangle(); + for (int i = 0; i < result.RowCount; i++) + { + result.At(i, i, 1); + } + return result; + } + } + + /// + /// Returns the upper triangular factor. + /// + public virtual Matrix U + { + get { return mFactors.GetUpperTriangle(); } + } + + /// + /// The determinant of the matrix for which the LU factorization was computed. + /// + public virtual double Determinant + { + get + { + double det = 1.0; + for (int j = 0; j < mFactors.RowCount; j++) + { + if (mPivots[j] != j) + { + det = -det * mFactors.At(j, j); + } + else + { + det *= mFactors.At(j, j); + } + } + return det; + } + } + + /// + /// Solves a system of linear equations, AX = B, with A LU factorized. + /// + /// The right hand side , B. + /// The left hand side , X. + public virtual Matrix Solve(Matrix input) + { + // Check for proper arguments. + if (input == null) + { + throw new ArgumentNullException("input"); + } + + var X = input.CreateMatrix(input.RowCount, input.ColumnCount); + Solve(input, X); + return X; + } + + /// + /// Solves a system of linear equations, AX = B, with A LU factorized. + /// + /// The right hand side , B. + /// The left hand side , X. + public abstract void Solve(Matrix input, Matrix result); + + /// + /// Solves a system of linear equations, Ax = b, with A LU factorized. + /// + /// The right hand side vector, b. + /// The left hand side , x. + public virtual Vector Solve(Vector input) + { + // Check for proper arguments. + if (input == null) + { + throw new ArgumentNullException("input"); + } + + var x = input.CreateVector(input.Count); + Solve(input, x); + return x; + } + + /// + /// Solves a system of linear equations, Ax = b, with A LU factorized. + /// + /// The right hand side vector, b. + /// The left hand side , x. + public abstract void Solve(Vector input, Vector result); + } +} diff --git a/src/Numerics/LinearAlgebra/Double/Matrix.cs b/src/Numerics/LinearAlgebra/Double/Matrix.cs index d36cd2fa..c5da5b90 100644 --- a/src/Numerics/LinearAlgebra/Double/Matrix.cs +++ b/src/Numerics/LinearAlgebra/Double/Matrix.cs @@ -33,6 +33,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double using System; using System.Text; using Properties; + using MathNet.Numerics.Threading; /// /// Defines the base class for Matrix classes. @@ -456,6 +457,108 @@ namespace MathNet.Numerics.LinearAlgebra.Double } } + /// + /// Returns a new matrix containing the lower triangle of this matrix. + /// + /// The lower triangle of this matrix. + public virtual Matrix GetLowerTriangle() + { + Matrix ret = CreateMatrix(RowCount, ColumnCount); + CommonParallel.For(0, ColumnCount, j => + { + for (int i = j; i < RowCount; i++) + { + ret.At(i, j, At(i, j)); + } + }); + return ret; + } + + /// + /// Puts the lower triangle of this matrix into the result matrix. + /// + /// Where to store the lower triangle. + /// If is . + /// If the result matrix's dimensions are not the same as this matrix. + public virtual void GetLowerTriangle(Matrix result) + { + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); + } + + CommonParallel.For(0, ColumnCount, j => + { + for (int i = 0; i < RowCount; i++) + { + if (i >= j) + { + result.At(i, j, At(i, j)); + } + else + { + result.At(i, j, 0); + } + } + }); + } + + /// + /// Returns a new matrix containing the upper triangle of this matrix. + /// + /// The upper triangle of this matrix. + public virtual Matrix GetUpperTriangle() + { + Matrix ret = CreateMatrix(RowCount, ColumnCount); + CommonParallel.For(0, ColumnCount, j => + { + for (int i = 0; i <= j; i++) + { + ret.At(i, j, At(i, j)); + } + }); + return ret; + } + + /// + /// Puts the upper triangle of this matrix into the result matrix. + /// + /// Where to store the lower triangle. + /// If is . + /// If the result matrix's dimensions are not the same as this matrix. + public virtual void GetUpperTriangle(Matrix result) + { + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); + } + + CommonParallel.For(0, ColumnCount, j => + { + for (int i = 0; i < RowCount; i++) + { + if (i <= j) + { + result.At(i, j, At(i, j)); + } + else + { + result.At(i, j, 0); + } + } + }); + } + #region Implemented Interfaces #if !SILVERLIGHT diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index ccac2022..fe5ca4f5 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -145,6 +145,8 @@ + +