From b61a1a97b9039eca0a48dd39244da9629b98c425 Mon Sep 17 00:00:00 2001 From: Marcus Cuda Date: Sun, 4 Jul 2010 21:22:24 +0800 Subject: [PATCH] svd: merged Andriy's svd code and qr work array update --- .../Atlas/AtlasLinearAlgebraProvider.cs | 398 ++- .../ILinearAlgebraProviderOfT.cs | 72 +- .../ManagedLinearAlgebraProvider.cs | 2626 +++++++++++++++-- .../Mkl/MklLinearAlgebraProvider.cs | 398 ++- .../NativeAlgebraProvider.include | 396 ++- .../Double/Factorization/DenseQR.cs | 23 +- .../Double/Factorization/DenseSvd.cs | 180 ++ .../Double/Factorization/ExtensionMethods.cs | 11 + .../LinearAlgebra/Double/Factorization/QR.cs | 4 +- .../LinearAlgebra/Double/Factorization/Svd.cs | 283 ++ src/Numerics/Numerics.csproj | 2 + src/Numerics/Properties/Resources.Designer.cs | 18 + src/Numerics/Properties/Resources.resx | 6 + src/Silverlight/Silverlight.csproj | 6 + .../Double/Factorization/SvdTests.cs | 370 +++ src/UnitTests/UnitTests.csproj | 1 + 16 files changed, 4116 insertions(+), 678 deletions(-) create mode 100644 src/Numerics/LinearAlgebra/Double/Factorization/DenseSvd.cs create mode 100644 src/Numerics/LinearAlgebra/Double/Factorization/Svd.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Double/Factorization/SvdTests.cs diff --git a/src/Numerics/Algorithms/LinearAlgebra/Atlas/AtlasLinearAlgebraProvider.cs b/src/Numerics/Algorithms/LinearAlgebra/Atlas/AtlasLinearAlgebraProvider.cs index c28750a8..41c52f77 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/Atlas/AtlasLinearAlgebraProvider.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/Atlas/AtlasLinearAlgebraProvider.cs @@ -28,7 +28,7 @@ /* This file is automatically generated - do not modify it. Change NativeLinearAlgebraProvider.include instead. - Last generated on UTC 2010-06-27 13:41:23Z + Last generated on UTC 2010-07-04 13:21:14Z */ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas @@ -235,6 +235,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// /// The requested of the matrix. @@ -248,6 +250,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// The work array. Only used when /// and needs to be have a length of at least M (number of rows of . @@ -452,24 +456,25 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.d_cholesky_factor(order, a); + + SafeNativeMethods.d_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. - /// This is equivalent to the POTRF add POTRS LAPACK routines. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. + /// This is equivalent to the POTRF add POTRS LAPACK routines. + /// public void CholeskySolve(double[] a, int aOrder, double[] b, int bRows, int bColumns) { throw new NotImplementedException(); @@ -481,8 +486,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(double[] a, int aOrder, double[] b, int bRows, int bColumns) { @@ -493,11 +498,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(double[] r, double[] q) + public void QRFactor(double[] r, int rRows, int rColumns, double[] q) { throw new NotImplementedException(); } @@ -506,13 +513,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(double[] r, double[] q, double[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(double[] r, int rRows, int rColumns, double[] q, double[] work) { throw new NotImplementedException(); } @@ -520,14 +530,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, double[] r, double[] q, double[] b, double[] x) + public void QRSolve(double[] r, int rRows, int rColumns, double[] q, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -535,17 +547,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, double[] r, double[] q, double[] b, double[] x, double[] work) + public void QRSolve(double[] r, int rRows, int rColumns, double[] q, double[] b, int bColumns, double[] x, double[] work) { throw new NotImplementedException(); } @@ -553,12 +567,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, double[] q, double[] r, double[] b, double[] x) + public void QRSolveFactored(double[] q, double[] r, int rRows, int rColumns, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -568,13 +584,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, double[] a, double[] s, double[] u, double[] vt) + public void SingularValueDecomposition(bool computeVectors, double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt) { throw new NotImplementedException(); } @@ -584,6 +602,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -593,7 +613,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, double[] a, double[] s, double[] u, double[] vt, double[] work) + public void SingularValueDecomposition(bool computeVectors, double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] work) { throw new NotImplementedException(); } @@ -602,12 +622,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(double[] a, double[] s, double[] u, double[] vt, double[] b, double[] x) + public void SvdSolve(double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -616,15 +639,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(double[] a, double[] s, double[] u, double[] vt, double[] b, double[] x, double[] work) + public void SvdSolve(double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x, double[] work) { throw new NotImplementedException(); } @@ -632,13 +658,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, double[] s, double[] u, double[] vt, double[] b, double[] x) + public void SvdSolveFactored(int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -836,6 +864,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// /// The requested of the matrix. @@ -849,6 +879,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// The work array. Only used when /// and needs to be have a length of at least M (number of rows of . @@ -926,6 +958,7 @@ 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. /// @@ -1053,23 +1086,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.s_cholesky_factor(order, a); + + SafeNativeMethods.s_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRF add POTRS LAPACK routines. public void CholeskySolve(float[] a, int aOrder, float[] b, int bRows, int bColumns) { @@ -1082,8 +1115,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(float[] a, int aOrder, float[] b, int bRows, int bColumns) { @@ -1094,11 +1127,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(float[] r, float[] q) + public void QRFactor(float[] r, int rRows, int rColumns, float[] q) { throw new NotImplementedException(); } @@ -1107,13 +1142,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(float[] r, float[] q, float[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(float[] r, int rRows, int rColumns, float[] q, float[] work) { throw new NotImplementedException(); } @@ -1121,14 +1159,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, float[] r, float[] q, float[] b, float[] x) + public void QRSolve(float[] r, int rRows, int rColumns, float[] q, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1136,17 +1176,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, float[] r, float[] q, float[] b, float[] x, float[] work) + public void QRSolve(float[] r, int rRows, int rColumns, float[] q, float[] b, int bColumns, float[] x, float[] work) { throw new NotImplementedException(); } @@ -1154,12 +1196,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, float[] q, float[] r, float[] b, float[] x) + public void QRSolveFactored(float[] q, float[] r, int rRows, int rColumns, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1169,13 +1213,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, float[] a, float[] s, float[] u, float[] vt) + public void SingularValueDecomposition(bool computeVectors, float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt) { throw new NotImplementedException(); } @@ -1185,6 +1231,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -1194,7 +1242,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, float[] a, float[] s, float[] u, float[] vt, float[] work) + public void SingularValueDecomposition(bool computeVectors, float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] work) { throw new NotImplementedException(); } @@ -1203,12 +1251,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(float[] a, float[] s, float[] u, float[] vt, float[] b, float[] x) + public void SvdSolve(float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1217,15 +1268,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(float[] a, float[] s, float[] u, float[] vt, float[] b, float[] x, float[] work) + public void SvdSolve(float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x, float[] work) { throw new NotImplementedException(); } @@ -1233,13 +1287,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, float[] s, float[] u, float[] vt, float[] b, float[] x) + public void SvdSolveFactored(int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1437,6 +1493,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// /// The requested of the matrix. @@ -1450,6 +1508,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// The work array. Only used when /// and needs to be have a length of at least M (number of rows of . @@ -1654,23 +1714,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.z_cholesky_factor(order, a); + + SafeNativeMethods.z_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRF add POTRS LAPACK routines. public void CholeskySolve(Complex[] a, int aOrder, Complex[] b, int bRows, int bColumns) { @@ -1683,8 +1743,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(Complex[] a, int aOrder, Complex[] b, int bRows, int bColumns) { @@ -1695,11 +1755,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(Complex[] r, Complex[] q) + public void QRFactor(Complex[] r, int rRows, int rColumns, Complex[] q) { throw new NotImplementedException(); } @@ -1708,13 +1770,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(Complex[] r, Complex[] q, Complex[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] work) { throw new NotImplementedException(); } @@ -1722,14 +1787,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, Complex[] r, Complex[] q, Complex[] b, Complex[] x) + public void QRSolve(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -1737,17 +1804,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, Complex[] r, Complex[] q, Complex[] b, Complex[] x, Complex[] work) + public void QRSolve(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] b, int bColumns, Complex[] x, Complex[] work) { throw new NotImplementedException(); } @@ -1755,12 +1824,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, Complex[] q, Complex[] r, Complex[] b, Complex[] x) + public void QRSolveFactored(Complex[] q, Complex[] r, int rRows, int rColumns, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -1770,13 +1841,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex[] a, Complex[] s, Complex[] u, Complex[] vt) + public void SingularValueDecomposition(bool computeVectors, Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt) { throw new NotImplementedException(); } @@ -1786,6 +1859,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -1795,7 +1870,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) + public void SingularValueDecomposition(bool computeVectors, Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) { throw new NotImplementedException(); } @@ -1804,12 +1879,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x) + public void SvdSolve(Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -1818,15 +1896,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x, Complex[] work) + public void SvdSolve(Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x, Complex[] work) { throw new NotImplementedException(); } @@ -1834,13 +1915,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x) + public void SvdSolveFactored(int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -2259,23 +2342,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.c_cholesky_factor(order, a); + + SafeNativeMethods.c_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRF add POTRS LAPACK routines. public void CholeskySolve(Complex32[] a, int aOrder, Complex32[] b, int bRows, int bColumns) { @@ -2288,8 +2371,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(Complex32[] a, int aOrder, Complex32[] b, int bRows, int bColumns) { @@ -2300,11 +2383,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(Complex32[] r, Complex32[] q) + public void QRFactor(Complex32[] r, int rRows, int rColumns, Complex32[] q) { throw new NotImplementedException(); } @@ -2313,13 +2398,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(Complex32[] r, Complex32[] q, Complex32[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] work) { throw new NotImplementedException(); } @@ -2327,14 +2415,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, Complex32[] r, Complex32[] q, Complex32[] b, Complex32[] x) + public void QRSolve(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } @@ -2342,17 +2432,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, Complex32[] r, Complex32[] q, Complex32[] b, Complex32[] x, Complex32[] work) + public void QRSolve(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] b, int bColumns, Complex32[] x, Complex32[] work) { throw new NotImplementedException(); } @@ -2360,12 +2452,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, Complex32[] q, Complex32[] r, Complex32[] b, Complex32[] x) + public void QRSolveFactored(Complex32[] q, Complex32[] r, int rRows, int rColumns, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } @@ -2375,13 +2469,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt) + public void SingularValueDecomposition(bool computeVectors, Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt) { throw new NotImplementedException(); } @@ -2391,6 +2487,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -2400,7 +2498,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) + public void SingularValueDecomposition(bool computeVectors, Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) { throw new NotImplementedException(); } @@ -2409,12 +2507,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x) + public void SvdSolve(Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } @@ -2423,15 +2524,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x, Complex32[] work) + public void SvdSolve(Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x, Complex32[] work) { throw new NotImplementedException(); } @@ -2439,13 +2543,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Atlas /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x) + public void SvdSolveFactored(int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } diff --git a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs index 01bed7d2..3beb89c7 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs @@ -3,9 +3,7 @@ // 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 @@ -83,7 +81,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// Interface to linear algebra algorithms that work off 1-D arrays. /// /// Supported data types are double, single, , and . - public interface ILinearAlgebraProvider where T : struct + public interface ILinearAlgebraProvider + where T : struct { /*/// /// Queries the provider for the optimal, workspace block size @@ -93,7 +92,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// -1 if the provider cannot compute the workspace size; otherwise /// the suggested block size. int QueryWorkspaceBlockSize(string methodName);*/ - + /// /// Adds a scaled vector to another: y += alpha*x. /// @@ -210,9 +209,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// The number of columns in the matrix. /// The value to scale the matrix. /// The c matrix. - void MatrixMultiplyWithUpdate(Transpose transposeA, Transpose transposeB, T alpha, T[] a, - int aRows, int aColumns, T[] b, int bRows, int bColumns, T beta, T[] c); - + void MatrixMultiplyWithUpdate(Transpose transposeA, Transpose transposeB, T alpha, T[] a, int aRows, int aColumns, T[] b, int bRows, int bColumns, T beta, T[] c); + /// /// Computes the LUP factorization of A. P*A = L*U. /// @@ -336,79 +334,93 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// /// On entry, it is the M by N A matrix to factor. On exit, /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - void QRFactor(T[] r, T[] q); + void QRFactor(T[] r, int rRows, int rColumns, T[] q); /// /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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 similar to the GEQRF and ORGQR LAPACK routines. - void QRFactor(T[] r, T[] q, T[] work); + void QRFactor(T[] r, int rRows, int rColumns, T[] q, T[] work); /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - void QRSolve(int columnsOfB, T[] r, T[] q, T[] b, T[] x); + void QRSolve(T[] r, int rRows, int rColumns, T[] q, T[] b, int bColumns, T[] x); /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - void QRSolve(int columnsOfB, T[] r, T[] q, T[] b, T[] x, T[] work); + void QRSolve(T[] r, int rRows, int rColumns, T[] q, T[] b, int bColumns, T[] x, T[] work); /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - void QRSolveFactored(int columnsOfB, T[] q, T[] r, T[] b, T[] x); + void QRSolveFactored(T[] q, T[] r, int rRows, int rColumns, T[] b, int bColumns, T[] x); /// /// Computes the singular value decomposition of A. /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - void SingularValueDecomposition(bool computeVectors, T[] a, T[] s, T[] u, T[] vt); + void SingularValueDecomposition(bool computeVectors, T[] a, int aRows, int aColumns, T[] s, T[] u, T[] vt); /// /// Computes the singular value decomposition of A. /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -419,43 +431,51 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// On exit, work[0] contains the optimal work size value. /// /// This is equivalent to the GESVD LAPACK routine. - void SingularValueDecomposition(bool computeVectors, T[] a, T[] s, T[] u, T[] vt, T[] work); + void SingularValueDecomposition(bool computeVectors, T[] a, int aRows, int aColumns, T[] s, T[] u, T[] vt, T[] work); /// /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - void SvdSolve(T[] a, T[] s, T[] u, T[] vt, T[] b, T[] x); + void SvdSolve(T[] a, int aRows, int aColumns, T[] s, T[] u, T[] vt, T[] b, int bColumns, T[] x); /// /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// - void SvdSolve(T[] a, T[] s, T[] u, T[] vt, T[] b, T[] x, T[] work); + void SvdSolve(T[] a, int aRows, int aColumns, T[] s, T[] u, T[] vt, T[] b, int bColumns, T[] x, T[] work); /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - void SvdSolveFactored(int columnsOfB, T[] s, T[] u, T[] vt, T[] b, T[] x); + void SvdSolveFactored(int aRows, int aColumns, T[] s, T[] u, T[] vt, T[] b, int bColumns, T[] x); } } diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs index 31ca3024..d65226ad 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs @@ -254,6 +254,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra case Norm.FrobeniusNorm: break; } + return ret; } @@ -367,12 +368,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// The number of columns in the matrix. /// The value to scale the matrix. /// The c matrix. - public void MatrixMultiplyWithUpdate(Transpose transposeA, Transpose transposeB, double alpha, double[] a, - int aRows, int aColumns, double[] b, int bRows, int bColumns, double beta, double[] c) + public void MatrixMultiplyWithUpdate(Transpose transposeA, Transpose transposeB, double alpha, double[] a, int aRows, int aColumns, double[] b, int bRows, int bColumns, double beta, double[] c) { // Choose nonsensical values for the number of rows in c; fill them in depending // on the operations on a and b. - var cRows = -1; + int cRows; // First check some basic requirement on the parameters of the matrix multiplication. if (a == null) @@ -730,7 +730,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra ipiv[i] = i; } - var LUcolj = new double[order]; + var vLUcolj = new double[order]; // Outer loop. for (var j = 0; j < order; j++) @@ -738,10 +738,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var indexj = j * order; var indexjj = indexj + j; -// Make a copy of the j-th column to localize references. + // Make a copy of the j-th column to localize references. for (var i = 0; i < order; i++) { - LUcolj[i] = data[indexj + i]; + vLUcolj[i] = data[indexj + i]; } // Apply previous transformations. @@ -752,17 +752,17 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var s = 0.0; for (var k = 0; k < kmax; k++) { - s += data[k * order + i] * LUcolj[k]; + s += data[k * order + i] * vLUcolj[k]; } - data[indexj + i] = LUcolj[i] -= s; + data[indexj + i] = vLUcolj[i] -= s; } // Find pivot and exchange if necessary. var p = j; for (var i = j + 1; i < order; i++) { - if (Math.Abs(LUcolj[i]) > Math.Abs(LUcolj[p])) + if (Math.Abs(vLUcolj[i]) > Math.Abs(vLUcolj[p])) { p = i; } @@ -899,9 +899,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// /// Solves A*X=B for X using a previously factored A matrix. /// - /// The square, positive definite matrix A. Has to be different than . + /// The square, positive definite matrix A. Has to be different than . /// The number of rows and columns in A. - /// The B matrix. Has to be different than . + /// The B matrix. Has to be different than . /// The number of rows in the B matrix. /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. @@ -964,10 +964,325 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// /// On entry, it is the M by N A matrix to factor. On exit, /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(double[] r, double[] q) + public void QRFactor(double[] r, int rRows, int rColumns, double[] q) + { + if (r == null) + { + throw new ArgumentNullException("r"); + } + + if (q == null) + { + throw new ArgumentNullException("q"); + } + + if (r.Length != rRows * rColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "r"); + } + + if (q.Length != rRows * rRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "q"); + } + + var work = new double[rRows * rRows]; + QRFactor(r, rRows, rColumns, q, work); + } + + /// + /// Computes the QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// 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 similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(double[] r, int rRows, int rColumns, double[] q, double[] work) + { + if (r == null) + { + throw new ArgumentNullException("r"); + } + + if (q == null) + { + throw new ArgumentNullException("q"); + } + + if (work == null) + { + throw new ArgumentNullException("q"); + } + + if (r.Length != rRows * rColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "r"); + } + + if (q.Length != rRows * rRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "q"); + } + + if (work.Length < rRows * rRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "work"); + } + + CommonParallel.For(0, rRows, i => q[(i * rRows) + i] = 1.0); + + var minmn = Math.Min(rRows, rColumns); + for (var i = 0; i < minmn; i++) + { + GenerateColumn(work, r, rRows, i, rRows - 1, i); + ComputeQR(work, i, r, rRows, i, rRows - 1, i + 1, rColumns - 1); + } + + for (var i = minmn - 1; i >= 0; i--) + { + ComputeQR(work, i, q, rRows, i, rRows - 1, i, rRows - 1); + } + } + + #region QR Factor Helper functions + + /// + /// Perform calculation of Q or R + /// + /// Work arrat + /// Index of colunn in work array + /// Q or R matrices + /// The number of rows + /// The first row in + /// The last row + /// The first column + /// The last column + private static void ComputeQR(double[] work, int workIndex, double[] a, int rowCount, int rowStart, int rowEnd, int columnStart, int columnEnd) + { + if (rowStart > rowEnd || columnStart > columnEnd) + { + return; + } + + var vector = new double[columnEnd - columnStart + 1]; + for (var i = rowStart; i <= rowEnd; i++) + { + for (var j = columnStart; j <= columnEnd; j++) + { + vector[j - columnStart] += work[(workIndex * rowCount) + i - rowStart] * a[(j * rowCount) + i]; + } + } + + for (var i = rowStart; i <= rowEnd; i++) + { + for (var j = columnStart; j <= columnEnd; j++) + { + a[(j * rowCount) + i] -= work[(workIndex * rowCount) + i - rowStart] * vector[j - columnStart]; + } + } + } + + /// + /// Generate column from initial matrix to work array + /// + /// Work array + /// Initial matrix + /// The number of rows in matrix + /// The firts row + /// The last row + /// Column index + private static void GenerateColumn(double[] work, double[] a, int rowCount, int rowStart, int rowEnd, int column) + { + var tmp = column * rowCount; + var index = tmp + rowStart; + + CommonParallel.For( + rowStart, + rowEnd + 1, + i => + { + var iIndex = tmp + i; + work[iIndex - rowStart] = a[iIndex]; + a[iIndex] = 0.0; + }); + + var norm = 0.0; + for (var i = 0; i < rowEnd - rowStart + 1; ++i) + { + var iIndex = tmp + i; + norm += work[iIndex] * work[iIndex]; + } + + norm = Math.Sqrt(norm); + if (rowStart == rowEnd || norm == 0) + { + a[index] = -work[tmp]; + work[tmp] = Math.Sqrt(2.0); + return; + } + + var scale = 1.0 / norm; + if (work[tmp] < 0.0) + { + scale *= -1.0; + } + + a[index] = -1.0 / scale; + CommonParallel.For(0, rowEnd - rowStart + 1, i => work[tmp + i] *= scale); + work[tmp] += 1.0; + + var s = Math.Sqrt(1.0 / work[tmp]); + CommonParallel.For(0, rowEnd - rowStart + 1, i => work[tmp + i] *= s); + } + + #endregion + + /// + /// Solves A*X=B for X using QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void QRSolve(double[] r, int rRows, int rColumns, double[] q, double[] b, int bColumns, double[] x) + { + if (r == null) + { + throw new ArgumentNullException("r"); + } + + if (q == null) + { + throw new ArgumentNullException("q"); + } + + if (b == null) + { + throw new ArgumentNullException("q"); + } + + if (x == null) + { + throw new ArgumentNullException("q"); + } + + if (r.Length != rRows * rColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "r"); + } + + if (q.Length != rRows * rRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "q"); + } + + if (b.Length != rRows * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } + + if (x.Length != rColumns * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "x"); + } + + var work = new double[rRows * rRows]; + QRSolve(r, rRows, rColumns, q, b, bColumns, x, work); + } + + /// + /// Solves A*X=B for X using QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution 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. + public void QRSolve(double[] r, int rRows, int rColumns, double[] q, double[] b, int bColumns, double[] x, double[] work) + { + if (r == null) + { + throw new ArgumentNullException("r"); + } + + if (q == null) + { + throw new ArgumentNullException("q"); + } + + if (b == null) + { + throw new ArgumentNullException("q"); + } + + if (x == null) + { + throw new ArgumentNullException("q"); + } + + if (r.Length != rRows * rColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "r"); + } + + if (q.Length != rRows * rRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "q"); + } + + if (b.Length != rRows * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } + + if (x.Length != rColumns * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "x"); + } + + if (work.Length < rRows * rRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "work"); + } + + QRFactor(r, rRows, rColumns, q, work); + QRSolveFactored(q, r, rRows, rColumns, b, bColumns, x); + } + + /// + /// Solves A*X=B for X using a previously QR factored matrix. + /// + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void QRSolveFactored(double[] q, double[] r, int rRows, int rColumns, double[] b, int bColumns, double[] x) { if (r == null) { @@ -979,234 +1294,1778 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("q"); } - // Matrix Q is square (m x m), where "m" is number of rows of initial matrix; - var rowCount = (int)Math.Sqrt(q.Length); - var columnCount = r.Length / rowCount; - - for (var i = 0; i < rowCount; i++) + if (b == null) + { + throw new ArgumentNullException("q"); + } + + if (x == null) + { + throw new ArgumentNullException("q"); + } + + if (r.Length != rRows * rColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "r"); + } + + if (q.Length != rRows * rRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "q"); + } + + if (b.Length != rRows * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } + + if (x.Length != rColumns * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "x"); + } + + var sol = new double[b.Length]; + + // Copy B matrix to "sol", so B data will not be changed + Buffer.BlockCopy(b, 0, sol, 0, b.Length * Constants.SizeOfDouble); + + // Compute Y = transpose(Q)*B + var column = new double[rRows]; + for (var j = 0; j < bColumns; j++) + { + var jm = j * rRows; + CommonParallel.For(0, rRows, k => column[k] = sol[jm + k]); + CommonParallel.For( + 0, + rRows, + i => + { + var im = i * rRows; + sol[jm + i] = CommonParallel.Aggregate(0, rRows, k => q[im + k] * column[k]); + }); + } + + // Solve R*X = Y; + for (var k = rColumns - 1; k >= 0; k--) + { + var km = k * rRows; + for (var j = 0; j < bColumns; j++) + { + sol[(j * rRows) + k] /= r[km + k]; + } + + for (var i = 0; i < k; i++) + { + for (var j = 0; j < bColumns; j++) + { + var jm = j * rRows; + sol[jm + i] -= sol[jm + k] * r[km + i]; + } + } + } + + // Fill result matrix + CommonParallel.For( + 0, + rColumns, + row => + { + for (var col = 0; col < bColumns; col++) + { + x[(col * rColumns) + row] = sol[row + (col * rRows)]; + } + }); + } + + /// + /// Computes the singular value decomposition of A. + /// + /// Compute the singular U and VT vectors or not. + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// If is true, on exit U contains the left + /// singular vectors. + /// If is true, on exit VT contains the transposed + /// right singular vectors. + /// This is equivalent to the GESVD LAPACK routine. + public void SingularValueDecomposition(bool computeVectors, double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt) + { + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (s == null) + { + throw new ArgumentNullException("s"); + } + + if (u == null) + { + throw new ArgumentNullException("u"); + } + + if (vt == null) + { + throw new ArgumentNullException("vt"); + } + + if (u.Length != aRows * aRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); + } + + if (vt.Length != aColumns * aColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); + } + + if (s.Length != Math.Min(aRows, aColumns)) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); + } + + // TODO: Actually "work = new double[aRows]" is acceptable size of work array. I set size proposed in method description + var work = new double[Math.Max((3 * Math.Min(aRows, aColumns)) + Math.Max(aRows, aColumns), 5 * Math.Min(aRows, aColumns))]; + SingularValueDecomposition(computeVectors, a, aRows, aColumns, s, u, vt, work); + } + + /// + /// Computes the singular value decomposition of A. + /// + /// Compute the singular U and VT vectors or not. + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// If is true, on exit U contains the left + /// singular vectors. + /// If is true, on exit VT contains the transposed + /// right singular vectors. + /// The work array. For real matrices, the work array should be at least + /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). + /// On exit, work[0] contains the optimal work size value. + /// This is equivalent to the GESVD LAPACK routine. + public void SingularValueDecomposition(bool computeVectors, double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] work) + { + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (s == null) + { + throw new ArgumentNullException("s"); + } + + if (u == null) + { + throw new ArgumentNullException("u"); + } + + if (vt == null) + { + throw new ArgumentNullException("vt"); + } + + if (work == null) + { + throw new ArgumentNullException("work"); + } + + if (u.Length != aRows * aRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); + } + + if (vt.Length != aColumns * aColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); + } + + if (s.Length != Math.Min(aRows, aColumns)) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); + } + + if (work.Length == 0) + { + throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); + } + + if (work.Length < aRows) + { + // TODO: Actually "work = new double[aRows]" is acceptable size of work array. I set size proposed in method description + work[0] = Math.Max((3 * Math.Min(aRows, aColumns)) + Math.Max(aRows, aColumns), 5 * Math.Min(aRows, aColumns)); + return; + } + + const int Maxiter = 1000; + + var e = new double[aColumns]; + var v = new double[vt.Length]; + var stemp = new double[Math.Min(aRows + 1, aColumns)]; + + int i, j, l, lp1; + + var cs = 0.0; + var sn = 0.0; + double t; + + var ncu = aRows; + + // Reduce matrix to bidiagonal form, storing the diagonal elements + // in "s" and the super-diagonal elements in "e". + var nct = Math.Min(aRows - 1, aColumns); + var nrt = Math.Max(0, Math.Min(aColumns - 2, aRows)); + var lu = Math.Max(nct, nrt); + + for (l = 0; l < lu; l++) + { + lp1 = l + 1; + if (l < nct) + { + // Compute the transformation for the l-th column and + // place the l-th diagonal in vector s[l]. + var l1 = l; + stemp[l] = Math.Sqrt(CommonParallel.Aggregate(l, aRows, i1 => (a[(l1 * aRows) + i1] * a[(l1 * aRows) + i1]))); + + if (stemp[l] != 0.0) + { + if (a[(l * aRows) + l] != 0.0) + { + stemp[l] = Math.Abs(stemp[l]) * (a[(l * aRows) + l] / Math.Abs(a[(l * aRows) + l])); + } + + // A part of column "l" of Matrix A from row "l" to end multiply by 1.0 / s[l] + for (i = l; i < aRows; i++) + { + a[(l * aRows) + i] = a[(l * aRows) + i] * (1.0 / stemp[l]); + } + + a[(l * aRows) + l] = 1.0 + a[(l * aRows) + l]; + } + + stemp[l] = -stemp[l]; + } + + for (j = lp1; j < aColumns; j++) + { + if (l < nct) + { + if (stemp[l] != 0.0) + { + // Apply the transformation. + t = 0.0; + for (i = l; i < aRows; i++) + { + t += a[(j * aRows) + i] * a[(l * aRows) + i]; + } + + t = -t / a[(l * aRows) + l]; + + for (var ii = l; ii < aRows; ii++) + { + a[(j * aRows) + ii] += t * a[(l * aRows) + ii]; + } + } + } + + // Place the l-th row of matrix into "e" for the + // subsequent calculation of the row transformation. + e[j] = a[(j * aRows) + l]; + } + + if (computeVectors && l < nct) + { + // Place the transformation in "u" for subsequent back multiplication. + for (i = l; i < aRows; i++) + { + u[(l * aRows) + i] = a[(l * aRows) + i]; + } + } + + if (l >= nrt) + { + continue; + } + + // Compute the l-th row transformation and place the l-th super-diagonal in e(l). + var enorm = 0.0; + for (i = lp1; i < e.Length; i++) + { + enorm += e[i] * e[i]; + } + + e[l] = Math.Sqrt(enorm); + if (e[l] != 0.0) + { + if (e[lp1] != 0.0) + { + e[l] = Math.Abs(e[l]) * (e[lp1] / Math.Abs(e[lp1])); + } + + // Scale vector "e" from "lp1" by 1.0 / e[l] + for (i = lp1; i < e.Length; i++) + { + e[i] = e[i] * (1.0 / e[l]); + } + + e[lp1] = 1.0 + e[lp1]; + } + + e[l] = -e[l]; + + if (lp1 < aRows && e[l] != 0.0) + { + // Apply the transformation. + for (i = lp1; i < aRows; i++) + { + work[i] = 0.0; + } + + for (j = lp1; j < aColumns; j++) + { + for (var ii = lp1; ii < aRows; ii++) + { + work[ii] += e[j] * a[(j * aRows) + ii]; + } + } + + for (j = lp1; j < aColumns; j++) + { + var ww = -e[j] / e[lp1]; + for (var ii = lp1; ii < aRows; ii++) + { + a[(j * aRows) + ii] += ww * work[ii]; + } + } + } + + if (!computeVectors) + { + continue; + } + + // Place the transformation in v for subsequent back multiplication. + for (i = lp1; i < aColumns; i++) + { + v[(l * aColumns) + i] = e[i]; + } + } + + // Set up the final bidiagonal matrix or order m. + var m = Math.Min(aColumns, aRows + 1); + var nctp1 = nct + 1; + var nrtp1 = nrt + 1; + if (nct < aColumns) + { + stemp[nctp1 - 1] = a[((nctp1 - 1) * aRows) + (nctp1 - 1)]; + } + + if (aRows < m) + { + stemp[m - 1] = 0.0; + } + + if (nrtp1 < m) + { + e[nrtp1 - 1] = a[((m - 1) * aRows) + (nrtp1 - 1)]; + } + + e[m - 1] = 0.0; + + // If required, generate "u". + if (computeVectors) + { + for (j = nctp1 - 1; j < ncu; j++) + { + for (i = 0; i < aRows; i++) + { + u[(j * aRows) + i] = 0.0; + } + + u[(j * aRows) + j] = 1.0; + } + + for (l = nct - 1; l >= 0; l--) + { + if (stemp[l] != 0.0) + { + for (j = l + 1; j < ncu; j++) + { + t = 0.0; + for (i = l; i < aRows; i++) + { + t += u[(j * aRows) + i] * u[(l * aRows) + i]; + } + + t = -t / u[(l * aRows) + l]; + + for (var ii = l; ii < aRows; ii++) + { + u[(j * aRows) + ii] += t * u[(l * aRows) + ii]; + } + } + + // A part of column "l" of matrix A from row "l" to end multiply by -1.0 + for (i = l; i < aRows; i++) + { + u[(l * aRows) + i] = u[(l * aRows) + i] * -1.0; + } + + u[(l * aRows) + l] = 1.0 + u[(l * aRows) + l]; + for (i = 0; i < l; i++) + { + u[(l * aRows) + i] = 0.0; + } + } + else + { + for (i = 0; i < aRows; i++) + { + u[(l * aRows) + i] = 0.0; + } + + u[(l * aRows) + l] = 1.0; + } + } + } + + // If it is required, generate v. + if (computeVectors) + { + for (l = aColumns - 1; l >= 0; l--) + { + lp1 = l + 1; + if (l < nrt) + { + if (e[l] != 0.0) + { + for (j = lp1; j < aColumns; j++) + { + t = 0.0; + for (i = lp1; i < aColumns; i++) + { + t += v[(j * aColumns) + i] * v[(l * aColumns) + i]; + } + + t = -t / v[(l * aColumns) + lp1]; + for (var ii = l; ii < aColumns; ii++) + { + v[(j * aColumns) + ii] += t * v[(l * aColumns) + ii]; + } + } + } + } + + for (i = 0; i < aColumns; i++) + { + v[(l * aColumns) + i] = 0.0; + } + + v[(l * aColumns) + l] = 1.0; + } + } + + // Transform "s" and "e" so that they are double + for (i = 0; i < m; i++) + { + double r; + if (stemp[i] != 0.0) + { + t = stemp[i]; + r = stemp[i] / t; + stemp[i] = t; + if (i < m - 1) + { + e[i] = e[i] / r; + } + + if (computeVectors) + { + // A part of column "i" of matrix U from row 0 to end multiply by r + for (j = 0; j < aRows; j++) + { + u[(i * aRows) + j] = u[(i * aRows) + j] * r; + } + } + } + + // Exit + if (i == m - 1) + { + break; + } + + if (e[i] == 0.0) + { + continue; + } + + t = e[i]; + r = t / e[i]; + e[i] = t; + stemp[i + 1] = stemp[i + 1] * r; + if (!computeVectors) + { + continue; + } + + // A part of column "i+1" of matrix VT from row 0 to end multiply by r + for (j = 0; j < aColumns; j++) + { + v[((i + 1) * aColumns) + j] = v[((i + 1) * aColumns) + j] * r; + } + } + + // Main iteration loop for the singular values. + var mn = m; + var iter = 0; + + while (m > 0) + { + // Quit if all the singular values have been found. + // If too many iterations have been performed throw exception. + if (iter >= Maxiter) + { + throw new ArgumentException(Resources.ConvergenceFailed); + } + + // This section of the program inspects for negligible elements in the s and e arrays, + // on completion the variables kase and l are set as follows: + // kase = 1: if mS[m] and e[l-1] are negligible and l < m + // kase = 2: if mS[l] is negligible and l < m + // kase = 3: if e[l-1] is negligible, l < m, and mS[l, ..., mS[m] are not negligible (qr step). + // kase = 4: if e[m-1] is negligible (convergence). + double ztest; + double test; + for (l = m - 2; l >= 0; l--) + { + test = Math.Abs(stemp[l]) + Math.Abs(stemp[l + 1]); + ztest = test + Math.Abs(e[l]); + if (ztest.AlmostEqualInDecimalPlaces(test, 15)) + { + e[l] = 0.0; + break; + } + } + + int kase; + if (l == m - 2) + { + kase = 4; + } + else + { + int ls; + for (ls = m - 1; ls > l; ls--) + { + test = 0.0; + if (ls != m - 1) + { + test = test + Math.Abs(e[ls]); + } + + if (ls != l + 1) + { + test = test + Math.Abs(e[ls - 1]); + } + + ztest = test + Math.Abs(stemp[ls]); + if (ztest.AlmostEqualInDecimalPlaces(test, 15)) + { + stemp[ls] = 0.0; + break; + } + } + + if (ls == l) + { + kase = 3; + } + else if (ls == m - 1) + { + kase = 1; + } + else + { + kase = 2; + l = ls; + } + } + + l = l + 1; + + // Perform the task indicated by kase. + int k; + double f; + switch (kase) + { + // Deflate negligible s[m]. + case 1: + f = e[m - 2]; + e[m - 2] = 0.0; + double t1; + for (var kk = l; kk < m - 1; kk++) + { + k = m - 2 - kk + l; + t1 = stemp[k]; + + Drotg(ref t1, ref f, ref cs, ref sn); + stemp[k] = t1; + if (k != l) + { + f = -sn * e[k - 1]; + e[k - 1] = cs * e[k - 1]; + } + + if (computeVectors) + { + // Rotate + for (i = 0; i < aColumns; i++) + { + var z = (cs * v[(k * aColumns) + i]) + (sn * v[((m - 1) * aColumns) + i]); + v[((m - 1) * aColumns) + i] = (cs * v[((m - 1) * aColumns) + i]) - (sn * v[(k * aColumns) + i]); + v[(k * aColumns) + i] = z; + } + } + } + + break; + + // Split at negligible s[l]. + case 2: + f = e[l - 1]; + e[l - 1] = 0.0; + for (k = l; k < m; k++) + { + t1 = stemp[k]; + Drotg(ref t1, ref f, ref cs, ref sn); + stemp[k] = t1; + f = -sn * e[k]; + e[k] = cs * e[k]; + if (computeVectors) + { + // Rotate + for (i = 0; i < aRows; i++) + { + var z = (cs * u[(k * aRows) + i]) + (sn * u[((l - 1) * aRows) + i]); + u[((l - 1) * aRows) + i] = (cs * u[((l - 1) * aRows) + i]) - (sn * u[(k * aRows) + i]); + u[(k * aRows) + i] = z; + } + } + } + + break; + + // Perform one qr step. + case 3: + +// calculate the shift. + var scale = 0.0; + scale = Math.Max(scale, Math.Abs(stemp[m - 1])); + scale = Math.Max(scale, Math.Abs(stemp[m - 2])); + scale = Math.Max(scale, Math.Abs(e[m - 2])); + scale = Math.Max(scale, Math.Abs(stemp[l])); + scale = Math.Max(scale, Math.Abs(e[l])); + var sm = stemp[m - 1] / scale; + var smm1 = stemp[m - 2] / scale; + var emm1 = e[m - 2] / scale; + var sl = stemp[l] / scale; + var el = e[l] / scale; + var b = (((smm1 + sm) * (smm1 - sm)) + (emm1 * emm1)) / 2.0; + var c = (sm * emm1) * (sm * emm1); + var shift = 0.0; + if (b != 0.0 || c != 0.0) + { + shift = Math.Sqrt((b * b) + c); + if (b < 0.0) + { + shift = -shift; + } + + shift = c / (b + shift); + } + + f = ((sl + sm) * (sl - sm)) + shift; + var g = sl * el; + + // Chase zeros + for (k = l; k < m - 1; k++) + { + Drotg(ref f, ref g, ref cs, ref sn); + if (k != l) + { + e[k - 1] = f; + } + + f = (cs * stemp[k]) + (sn * e[k]); + e[k] = (cs * e[k]) - (sn * stemp[k]); + g = sn * stemp[k + 1]; + stemp[k + 1] = cs * stemp[k + 1]; + if (computeVectors) + { + for (i = 0; i < aColumns; i++) + { + var z = (cs * v[(k * aColumns) + i]) + (sn * v[((k + 1) * aColumns) + i]); + v[((k + 1) * aColumns) + i] = (cs * v[((k + 1) * aColumns) + i]) - (sn * v[(k * aColumns) + i]); + v[(k * aColumns) + i] = z; + } + } + + Drotg(ref f, ref g, ref cs, ref sn); + stemp[k] = f; + f = (cs * e[k]) + (sn * stemp[k + 1]); + stemp[k + 1] = -(sn * e[k]) + (cs * stemp[k + 1]); + g = sn * e[k + 1]; + e[k + 1] = cs * e[k + 1]; + if (computeVectors && k < aRows) + { + for (i = 0; i < aRows; i++) + { + var z = (cs * u[(k * aRows) + i]) + (sn * u[((k + 1) * aRows) + i]); + u[((k + 1) * aRows) + i] = (cs * u[((k + 1) * aRows) + i]) - (sn * u[(k * aRows) + i]); + u[(k * aRows) + i] = z; + } + } + } + + e[m - 2] = f; + iter = iter + 1; + break; + + // Convergence + case 4: + +// Make the singular value positive + if (stemp[l] < 0.0) + { + stemp[l] = -stemp[l]; + if (computeVectors) + { + // A part of column "l" of matrix VT from row 0 to end multiply by -1 + for (i = 0; i < aColumns; i++) + { + v[(l * aColumns) + i] = v[(l * aColumns) + i] * -1.0; + } + } + } + + // Order the singular value. + while (l != mn - 1) + { + if (stemp[l] >= stemp[l + 1]) + { + break; + } + + t = stemp[l]; + stemp[l] = stemp[l + 1]; + stemp[l + 1] = t; + if (computeVectors && l < aColumns) + { + // Swap columns l, l + 1 + for (i = 0; i < aColumns; i++) + { + var z = v[(l * aColumns) + i]; + v[(l * aColumns) + i] = v[((l + 1) * aColumns) + i]; + v[((l + 1) * aColumns) + i] = z; + } + } + + if (computeVectors && l < aRows) + { + // Swap columns l, l + 1 + for (i = 0; i < aRows; i++) + { + var z = u[(l * aRows) + i]; + u[(l * aRows) + i] = u[((l + 1) * aRows) + i]; + u[((l + 1) * aRows) + i] = z; + } + } + + l = l + 1; + } + + iter = 0; + m = m - 1; + break; + } + } + + if (computeVectors) + { + // Finally transpose "v" to get "vt" matrix + for (i = 0; i < aColumns; i++) + { + for (j = 0; j < aColumns; j++) + { + vt[(j * aColumns) + i] = v[(i * aColumns) + j]; + } + } + } + + // Copy stemp to s with size adjustment. We are using ported copy of linpack's svd code and it uses + // a singular vector of length rows+1 when rows < columns. The last element is not used and needs to be removed. + // We should port lapack's svd routine to remove this problem. + Buffer.BlockCopy(stemp, 0, s, 0, Math.Min(aRows, aColumns) * Constants.SizeOfDouble); + + // On return the first element of the work array stores the min size of the work array could have been + // work[0] = Math.Max(3 * Math.Min(aRows, aColumns) + Math.Max(aRows, aColumns), 5 * Math.Min(aRows, aColumns)); + work[0] = aRows; + } + + public void SingularValueDecompositionWithCommonParallel(bool computeVectors, double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] work) + { + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (s == null) + { + throw new ArgumentNullException("s"); + } + + if (u == null) + { + throw new ArgumentNullException("u"); + } + + if (vt == null) + { + throw new ArgumentNullException("vt"); + } + + if (u.Length != aRows * aRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); + } + + if (vt.Length != aColumns * aColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); + } + + if (s.Length != Math.Min(aRows, aColumns)) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); + } + + if (work == null) + { + throw new ArgumentNullException("work"); + } + + if (work.Length == 0) + { + throw new ArgumentException(Resources.ArgumentSingleDimensionArray); + } + + if (work.Length < aRows) + { + work[0] = Math.Max(3 * Math.Min(aRows, aColumns) + Math.Max(aRows, aColumns), 5 * Math.Min(aRows, aColumns)); + return; + } + + const int Maxiter = 1000; + + var e = new double[aColumns]; + var v = new double[vt.Length]; + var stemp = new double[Math.Min(aRows + 1, aColumns)]; + + int i, j, l, lp1; + + var cs = 0.0; + var sn = 0.0; + double t; + + var ncu = aRows; + + // Reduce matrix to bidiagonal form, storing the diagonal elements + // in "s" and the super-diagonal elements in "e". + var nct = Math.Min(aRows - 1, aColumns); + var nrt = Math.Max(0, Math.Min(aColumns - 2, aRows)); + var lu = Math.Max(nct, nrt); + + for (l = 0; l < lu; l++) + { + lp1 = l + 1; + var lCopy = l; + if (l < nct) + { + // Compute the transformation for the l-th column and + // place the l-th diagonal in vector s[l]. + stemp[l] = Math.Sqrt(CommonParallel.Aggregate(lCopy, aRows, row => (a[(lCopy * aRows) + row] * a[(lCopy * aRows) + row]))); + + if (stemp[l] != 0.0) + { + if (a[(l * aRows) + l] != 0.0) + { + stemp[l] = Math.Abs(stemp[l]) * (a[(l * aRows) + l] / Math.Abs(a[(l * aRows) + l])); + } + + // A part of column "l" of Matrix A from row "l" to end multiply by 1.0 / s[l] + for (i = l; i < aRows; i++) + { + a[(l * aRows) + i] = a[(l * aRows) + i] * (1.0 / stemp[l]); + } + + a[(l * aRows) + l] = 1.0 + a[(l * aRows) + l]; + } + + stemp[l] = -stemp[l]; + } + + for (j = lp1; j < aColumns; j++) + { + var jcopy = j; + + if (l < nct) + { + if (stemp[l] != 0.0) + { + // Apply the transformation. + t = CommonParallel.Aggregate(lCopy, aRows, row => a[(jcopy * aRows) + row] * a[(lCopy * aRows) + row]); + t = -t / a[(l * aRows) + l]; + for (var ii = l; ii < aRows; ii++) + { + a[(j * aRows) + ii] += t * a[(l * aRows) + ii]; + } + } + } + + // Place the l-th row of matrix into "e" for the + // subsequent calculation of the row transformation. + e[j] = a[(j * aRows) + l]; + } + + if (computeVectors && l < nct) + { + // Place the transformation in "u" for subsequent back multiplication. + CommonParallel.For(lCopy, aRows, row => u[(lCopy * aRows) + row] = a[(lCopy * aRows) + row]); + } + + if (l >= nrt) + { + continue; + } + + // Compute the l-th row transformation and place the l-th super-diagonal in e(l). + e[l] = Math.Sqrt(CommonParallel.Aggregate(lp1, e.Length, index => e[index] * e[index])); + if (e[l] != 0.0) + { + if (e[lp1] != 0.0) + { + e[l] = Math.Abs(e[l]) * (e[lp1] / Math.Abs(e[lp1])); + } + + // Scale vector "e" from "lp1" by 1.0 / e[l] + // lp1 > l, so we may use CommonParallel here + CommonParallel.For(lp1, e.Length, index => e[index] = e[index] * (1.0 / e[lCopy])); + e[lp1] = 1.0 + e[lp1]; + } + + e[l] = -e[l]; + + if (lp1 < aRows && e[l] != 0.0) + { + // Apply the transformation. + for (i = lp1; i < aRows; i++) + { + work[i] = 0.0; + } + + for (j = lp1; j < aColumns; j++) + { + for (var ii = lp1; ii < aRows; ii++) + { + work[ii] += e[j] * a[(j * aRows) + ii]; + } + } + + for (j = lp1; j < aColumns; j++) + { + var ww = -e[j] / e[lp1]; + for (var ii = lp1; ii < aRows; ii++) + { + a[(j * aRows) + ii] += ww * work[ii]; + } + } + } + + if (!computeVectors) + { + continue; + } + + // Place the transformation in v for subsequent back multiplication. + CommonParallel.For(lp1, aColumns, index => v[(lCopy * aColumns) + index] = e[index]); + } + + // Set up the final bidiagonal matrix or order m. + var m = Math.Min(aColumns, aRows + 1); + var nctp1 = nct + 1; + var nrtp1 = nrt + 1; + if (nct < aColumns) + { + stemp[nctp1 - 1] = a[(nctp1 - 1) * aRows + (nctp1 - 1)]; + } + + if (aRows < m) + { + stemp[m - 1] = 0.0; + } + + if (nrtp1 < m) + { + e[nrtp1 - 1] = a[(m - 1) * aRows + (nrtp1 - 1)]; + } + + e[m - 1] = 0.0; + + // If required, generate "u". + if (computeVectors) + { + CommonParallel.For(nctp1 - 1, ncu, indexCol => + { + CommonParallel.For(0, aRows, indexRow => u[(indexCol * aRows) + indexRow] = 0.0); + u[(indexCol * aRows) + indexCol] = 1.0; + }); + + for (l = nct - 1; l >= 0; l--) + { + var lCopy = l; + + if (stemp[l] != 0.0) + { + for (j = l + 1; j < ncu; j++) + { + var jCopy = j; + t = CommonParallel.Aggregate(lCopy, aRows, index => u[(jCopy * aRows) + index] * u[(lCopy * aRows) + index]); + t = -t / u[(l * aRows) + l]; + + for (var ii = l; ii < aRows; ii++) + { + u[(j * aRows) + ii] += t * u[(l * aRows) + ii]; + } + } + + // A part of column "l" of matrix A from row "l" to end multiply by -1.0 + CommonParallel.For(lCopy, aRows, index => u[(lCopy * aRows) + index] *= -1.0); + u[(l * aRows) + l] = 1.0 + u[(l * aRows) + l]; + if (lCopy != 0) + { + CommonParallel.For(0, lCopy, index => u[(lCopy * aRows) + index] = 0.0); + } + } + else + { + CommonParallel.For(0, aRows, index => u[(lCopy * aRows) + index] = 0.0); + u[(l * aRows) + l] = 1.0; + } + } + } + + // If it is required, generate v. + if (computeVectors) + { + for (l = aColumns - 1; l >= 0; l--) + { + lp1 = l + 1; + var lCopy = l; + + if (l < nrt) + { + if (e[l] != 0.0) + { + for (j = lp1; j < aColumns; j++) + { + var jCopy = j; + t = CommonParallel.Aggregate(lp1, aColumns, index => v[(jCopy * aColumns) + index] * v[(lCopy * aColumns) + index]); + t = -t / v[(l * aColumns) + lp1]; + for (var ii = l; ii < aColumns; ii++) + { + v[(j * aColumns) + ii] += t * v[(l * aColumns) + ii]; + } + } + } + } + + CommonParallel.For(0, aColumns, index => v[(lCopy * aColumns) + index] = 0.0); + v[(l * aColumns) + l] = 1.0; + } + } + + // Transform "s" and "e" so that they are double + for (i = 0; i < m; i++) + { + double r; + if (stemp[i] != 0.0) + { + t = stemp[i]; + r = stemp[i] / t; + stemp[i] = t; + if (i < m - 1) + { + e[i] = e[i] / r; + } + + if (computeVectors) + { + // A part of column "i" of matrix U from row 0 to end multiply by r + for (j = 0; j < aRows; j++) + { + u[(i * aRows) + j] = u[(i * aRows) + j] * r; + } + } + } + + // Exit + if (i == m - 1) + { + break; + } + + if (e[i] == 0.0) + { + continue; + } + + t = e[i]; + r = t / e[i]; + e[i] = t; + stemp[i + 1] = stemp[i + 1] * r; + if (!computeVectors) + { + continue; + } + + // A part of column "i+1" of matrix VT from row 0 to end multiply by r + for (j = 0; j < aColumns; j++) + { + v[((i + 1) * aColumns) + j] = v[((i + 1) * aColumns) + j] * r; + } + } + + // Main iteration loop for the singular values. + var mn = m; + var iter = 0; + + while (m > 0) + { + // Quit if all the singular values have been found. + // If too many iterations have been performed throw exception. + if (iter >= Maxiter) + { + throw new ArgumentException(Resources.ConvergenceFailed); + } + + // This section of the program inspects for negligible elements in the s and e arrays. + // On completion the variables kase and l are set as follows. + + // kase = 1: if mS[m] and e[l-1] are negligible and l < m + // kase = 2: if mS[l] is negligible and l < m + // kase = 3: if e[l-1] is negligible, l < m, and mS[l, ..., mS[m] are not negligible (qr step). + // kase = 4: if e[m-1] is negligible (convergence). + double ztest; + double test; + for (l = m - 2; l >= 0; l--) + { + test = Math.Abs(stemp[l]) + Math.Abs(stemp[l + 1]); + ztest = test + Math.Abs(e[l]); + if (ztest.AlmostEqualInDecimalPlaces(test, 15)) + { + e[l] = 0.0; + break; + } + } + + int kase; + if (l == m - 2) + { + kase = 4; + } + else + { + int ls; + for (ls = m - 1; ls > l; ls--) + { + test = 0.0; + if (ls != m - 1) + { + test = test + Math.Abs(e[ls]); + } + + if (ls != l + 1) + { + test = test + Math.Abs(e[ls - 1]); + } + + ztest = test + Math.Abs(stemp[ls]); + if (ztest.AlmostEqualInDecimalPlaces(test, 15)) + { + stemp[ls] = 0.0; + break; + } + } + + if (ls == l) + { + kase = 3; + } + else if (ls == m - 1) + { + kase = 1; + } + else + { + kase = 2; + l = ls; + } + } + + l = l + 1; + + // Perform the task indicated by kase. + int k; + double f; + switch (kase) + { + // Deflate negligible s[m]. + case 1: + f = e[m - 2]; + e[m - 2] = 0.0; + double t1; + for (var kk = l; kk < m - 1; kk++) + { + k = m - 2 - kk + l; + t1 = stemp[k]; + + Drotg(ref t1, ref f, ref cs, ref sn); + stemp[k] = t1; + if (k != l) + { + f = -sn * e[k - 1]; + e[k - 1] = cs * e[k - 1]; + } + + if (computeVectors) + { + // Rotate + for (i = 0; i < aColumns; i++) + { + var z = cs * v[(k * aColumns) + i] + sn * v[((m - 1) * aColumns) + i]; + v[((m - 1) * aColumns) + i] = cs * v[((m - 1) * aColumns) + i] - sn * v[(k * aColumns) + i]; + v[(k * aColumns) + i] = z; + } + } + } + + break; + + // Split at negligible s[l]. + case 2: + f = e[l - 1]; + e[l - 1] = 0.0; + for (k = l; k < m; k++) + { + t1 = stemp[k]; + Drotg(ref t1, ref f, ref cs, ref sn); + stemp[k] = t1; + f = -sn * e[k]; + e[k] = cs * e[k]; + if (computeVectors) + { + // Rotate + for (i = 0; i < aRows; i++) + { + var z = cs * u[(k * aRows) + i] + sn * u[((l - 1) * aRows) + i]; + u[((l - 1) * aRows) + i] = cs * u[((l - 1) * aRows) + i] - sn * u[(k * aRows) + i]; + u[(k * aRows) + i] = z; + } + } + } + + break; + + // Perform one qr step. + case 3: + +// calculate the shift. + var scale = 0.0; + scale = Math.Max(scale, Math.Abs(stemp[m - 1])); + scale = Math.Max(scale, Math.Abs(stemp[m - 2])); + scale = Math.Max(scale, Math.Abs(e[m - 2])); + scale = Math.Max(scale, Math.Abs(stemp[l])); + scale = Math.Max(scale, Math.Abs(e[l])); + var sm = stemp[m - 1] / scale; + var smm1 = stemp[m - 2] / scale; + var emm1 = e[m - 2] / scale; + var sl = stemp[l] / scale; + var el = e[l] / scale; + var b = ((smm1 + sm) * (smm1 - sm) + (emm1 * emm1)) / 2.0; + var c = (sm * emm1) * (sm * emm1); + var shift = 0.0; + if (b != 0.0 || c != 0.0) + { + shift = Math.Sqrt((b * b) + c); + if (b < 0.0) + { + shift = -shift; + } + + shift = c / (b + shift); + } + + f = (sl + sm) * (sl - sm) + shift; + var g = sl * el; + + // Chase zeros + for (k = l; k < m - 1; k++) + { + Drotg(ref f, ref g, ref cs, ref sn); + if (k != l) + { + e[k - 1] = f; + } + + f = cs * stemp[k] + sn * e[k]; + e[k] = cs * e[k] - sn * stemp[k]; + g = sn * stemp[k + 1]; + stemp[k + 1] = cs * stemp[k + 1]; + if (computeVectors) + { + for (i = 0; i < aColumns; i++) + { + var z = cs * v[k * aColumns + i] + sn * v[(k + 1) * aColumns + i]; + v[(k + 1) * aColumns + i] = cs * v[(k + 1) * aColumns + i] - sn * v[k * aColumns + i]; + v[k * aColumns + i] = z; + } + } + + Drotg(ref f, ref g, ref cs, ref sn); + stemp[k] = f; + f = cs * e[k] + sn * stemp[k + 1]; + stemp[k + 1] = -sn * e[k] + cs * stemp[k + 1]; + g = sn * e[k + 1]; + e[k + 1] = cs * e[k + 1]; + if (computeVectors && k < aRows) + { + for (i = 0; i < aRows; i++) + { + var z = cs * u[k * aRows + i] + sn * u[(k + 1) * aRows + i]; + u[(k + 1) * aRows + i] = cs * u[(k + 1) * aRows + i] - sn * u[k * aRows + i]; + u[k * aRows + i] = z; + } + } + } + + e[m - 2] = f; + iter = iter + 1; + break; + + // Convergence + case 4: + +// Make the singular value positive + if (stemp[l] < 0.0) + { + stemp[l] = -stemp[l]; + if (computeVectors) + { + // A part of column "l" of matrix VT from row 0 to end multiply by -1 + for (i = 0; i < aColumns; i++) + { + v[(l * aColumns) + i] = v[(l * aColumns) + i] * -1.0; + } + } + } + + // Order the singular value. + while (l != mn - 1) + { + if (stemp[l] >= stemp[l + 1]) + { + break; + } + + t = stemp[l]; + stemp[l] = stemp[l + 1]; + stemp[l + 1] = t; + if (computeVectors && l < aColumns) + { + // Swap columns l, l + 1 + for (i = 0; i < aColumns; i++) + { + var z = v[l * aColumns + i]; + v[l * aColumns + i] = v[(l + 1) * aColumns + i]; + v[(l + 1) * aColumns + i] = z; + } + } + + if (computeVectors && l < aRows) + { + // Swap columns l, l + 1 + for (i = 0; i < aRows; i++) + { + var z = u[l * aRows + i]; + u[l * aRows + i] = u[(l + 1) * aRows + i]; + u[(l + 1) * aRows + i] = z; + } + } + + l = l + 1; + } + + iter = 0; + m = m - 1; + break; + } + } + + if (computeVectors) + { + // Finally transpose "v" to get "vt" matrix + for (i = 0; i < aColumns; i++) + { + for (j = 0; j < aColumns; j++) + { + vt[j * aColumns + i] = v[i * aColumns + j]; + } + } + } + + // Copy stemp to s with size adjustment. We are using ported copy of linpack's svd code and it uses + // a singular vector of length rows+1 when rows < columns. The last element is not used and needs to be removed. + // We should port lapack's svd routine to remove this problem. + Buffer.BlockCopy(stemp, 0, s, 0, Math.Min(aRows, aColumns) * Constants.SizeOfDouble); + + // On return the first element of the work array stores the min size of the work array could have been + // work[0] = Math.Max(3 * Math.Min(aRows, aColumns) + Math.Max(aRows, aColumns), 5 * Math.Min(aRows, aColumns)); + work[0] = aRows; + } + + /// + /// Сonstruct givens plane rotation + /// + /// + /// + /// + /// + private static void Drotg(ref double da, ref double db, ref double c, ref double s) + { + // Сonstruct givens plane rotation. + // jack dongarra, linpack, 3/11/78. + double r, z; + + var roe = db; + var absda = Math.Abs(da); + var absdb = Math.Abs(db); + if (absda > absdb) + { + roe = da; + } + + var scale = absda + absdb; + if (scale == 0.0) + { + c = 1.0; + s = 0.0; + r = 0.0; + z = 0.0; + } + else + { + var sda = da / scale; + var sdb = db / scale; + r = scale * Math.Sqrt((sda * sda) + (sdb * sdb)); + if (roe < 0.0) + { + r = -r; + } + + c = da / r; + s = db / r; + z = 1.0; + if (absda > absdb) + { + z = s; + } + + if (absdb >= absda && c != 0.0) + { + z = 1.0 / c; + } + } + + da = r; + db = z; + return; + } + + /// + /// Solves A*X=B for X using the singular value decomposition of A. + /// + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// On exit U contains the left singular vectors. + /// On exit VT contains the transposed right singular vectors. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void SvdSolve(double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x) + { + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (s == null) + { + throw new ArgumentNullException("s"); + } + + if (u == null) + { + throw new ArgumentNullException("u"); + } + + if (vt == null) + { + throw new ArgumentNullException("vt"); + } + + if (b == null) + { + throw new ArgumentNullException("b"); + } + + if (x == null) + { + throw new ArgumentNullException("x"); + } + + if (u.Length != aRows * aRows) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); + } + + if (vt.Length != aColumns * aColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); + } + + if (s.Length != Math.Min(aRows, aColumns)) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); + } + + if (b.Length != aRows * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } + + if (x.Length != aColumns * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } + + // TODO: Actually "work = new double[aRows]" is acceptable size of work array. I set size proposed in method description + var work = new double[Math.Max((3 * Math.Min(aRows, aColumns)) + Math.Max(aRows, aColumns), 5 * Math.Min(aRows, aColumns))]; + SvdSolve(a, aRows, aColumns, s, u, vt, b, bColumns, x, work); + } + + /// + /// Solves A*X=B for X using the singular value decomposition of A. + /// + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// On exit U contains the left singular vectors. + /// On exit VT contains the transposed right singular vectors. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + /// The work array. For real matrices, the work array should be at least + /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). + /// On exit, work[0] contains the optimal work size value. + public void SvdSolve(double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x, double[] work) + { + if (a == null) + { + throw new ArgumentNullException("a"); + } + + if (s == null) { - q[i * rowCount + i] = 1.0; + throw new ArgumentNullException("s"); } - var minmn = Math.Min(rowCount, columnCount); - var u = new double[minmn][]; - - for (var i = 0; i < minmn; i++) + if (u == null) { - u[i] = GenerateColumn(r, rowCount, i, rowCount - 1, i); - UA(u[i], r, rowCount, i, rowCount - 1, i + 1, columnCount - 1); + throw new ArgumentNullException("u"); } - for (var i = minmn - 1; i >= 0; i--) + if (vt == null) { - UA(u[i], q, rowCount, i, rowCount - 1, i, rowCount - 1); + throw new ArgumentNullException("vt"); } - } - - public void QRFactor(double[] r, double[] q, double[] work) - { - throw new NotImplementedException(); - } - - #region QR Factor Helper functions - private static void UA(double[] u, double[] A, int rowCount, int rowStart, int rowEnd, int columnStart, int columnEnd) - { - if (rowStart > rowEnd || columnStart > columnEnd) + if (b == null) { - return; + throw new ArgumentNullException("b"); } - var vector = new double[columnEnd - columnStart + 1]; - for (var j = columnStart; j <= columnEnd; j++) + if (x == null) { - vector[j - columnStart] = 0.0; + throw new ArgumentNullException("x"); } - for (var i = rowStart; i <= rowEnd; i++) + if (u.Length != aRows * aRows) { - for (var j = columnStart; j <= columnEnd; j++) - { - vector[j - columnStart] = vector[j - columnStart] + u[i - rowStart] * A[j * rowCount + i]; - } + throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - for (var i = rowStart; i <= rowEnd; i++) + if (vt.Length != aColumns * aColumns) { - for (var j = columnStart; j <= columnEnd; j++) - { - A[j * rowCount + i] = A[j * rowCount + i] - u[i - rowStart] * vector[j - columnStart]; - } + throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } - } - - private static double[] GenerateColumn(double[] A, int rowCount, int rowStart, int rowEnd, int column) - { - var u = new double[rowEnd - rowStart + 1]; - - var tmp = column * rowCount; - var index = tmp + rowStart; - for (var i = rowStart; i <= rowEnd; i++) + if (s.Length != Math.Min(aRows, aColumns)) { - u[i - rowStart] = A[tmp + i]; - A[tmp + i] = 0.0; + throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - var norm = u.Sum(t => t * t); - norm = Math.Sqrt(norm); - - if (rowStart == rowEnd || norm == 0) + if (b.Length != aRows * bColumns) { - A[index] = -u[0]; - u[0] = Math.Sqrt(2.0); - return u; + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - var scale = 1.0 / norm; - if (u[0] < 0.0) + if (x.Length != aColumns * bColumns) { - scale *= -1.0; + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - A[index] = -1.0 / scale; - for (var i = 0; i < u.Length; i++) + if (work.Length == 0) { - u[i] *= scale; + throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); } - u[0] += 1.0; - var s = Math.Sqrt(1.0 / u[0]); - for (var i = 0; i < u.Length; i++) + if (work.Length < aRows) { - u[i] *= s; + // TODO: Actually "work = new double[aRows]" is acceptable size of work array. I set size proposed in method description + work[0] = Math.Max((3 * Math.Min(aRows, aColumns)) + Math.Max(aRows, aColumns), 5 * Math.Min(aRows, aColumns)); + return; } - return u; - } - - #endregion - - public void QRSolve(int columnsOfB, double[] r, double[] q, double[] b, double[] x) - { - throw new NotImplementedException(); - } - - public void QRSolve(int columnsOfB, double[] r, double[] q, double[] b, double[] x, double[] work) - { - throw new NotImplementedException(); + SingularValueDecomposition(true, a, aRows, aColumns, s, u, vt, work); + SvdSolveFactored(aRows, aColumns, s, u, vt, b, bColumns, x); } /// - /// Solves A*X=B for X using a previously QR factored matrix. + /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, double[] q, double[] r, double[] b, double[] x) + public void SvdSolveFactored(int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x) { - if (r == null) + if (s == null) { - throw new ArgumentNullException("r"); + throw new ArgumentNullException("s"); } - if (q == null) + if (u == null) { - throw new ArgumentNullException("q"); + throw new ArgumentNullException("u"); + } + + if (vt == null) + { + throw new ArgumentNullException("vt"); } if (b == null) { - throw new ArgumentNullException("q"); + throw new ArgumentNullException("b"); } if (x == null) { - throw new ArgumentNullException("q"); + throw new ArgumentNullException("x"); } - if (b.Length != x.Length) + if (u.Length != aRows * aRows) { - throw new ArgumentException(Resources.ArgumentVectorsSameLength); + throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - // Matrix Q is square (m x m), where "m" is number of rows of initial matrix; - var rowCount = (int)Math.Sqrt(q.Length); - var columnCount = r.Length / rowCount; - - // Copy B matrix to result, so B data will not be changed - Buffer.BlockCopy(b, 0, x, 0, b.Length * Constants.SizeOfDouble); + if (vt.Length != aColumns * aColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); + } - // Compute Y = transpose(Q)*B - var column = new double[rowCount]; - for (var j = 0; j < columnsOfB; j++) + if (s.Length != Math.Min(aRows, aColumns)) { - var jm = j * rowCount; - for (var k = 0; k < rowCount; k++) - { - column[k] = x[jm + k]; - } + throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); + } - for (var i = 0; i < rowCount; i++) - { - double s = 0; - var im = i * rowCount; - for (var k = 0; k < rowCount; k++) - { - s += q[im + k] * column[k]; - } + if (b.Length != aRows * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); + } - x[jm + i] = s; - } + if (x.Length != aColumns * bColumns) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - // Solve R*X = Y; - for (var k = columnCount - 1; k >= 0; k--) + var mn = Math.Min(aRows, aColumns); + var tmp = new double[aColumns]; + + for (var k = 0; k < bColumns; k++) { - var km = k * rowCount; - for (var j = 0; j < columnsOfB; j++) + for (var j = 0; j < aColumns; j++) { - x[j * rowCount + k] /= r[km + k]; + double value = 0; + if (j < mn) + { + for (var i = 0; i < aRows; i++) + { + value += u[(j * aRows) + i] * b[(k * aRows) + i]; + } + + value /= s[j]; + } + + tmp[j] = value; } - for (var i = 0; i < k; i++) + for (var j = 0; j < aColumns; j++) { - for (var j = 0; j < columnsOfB; j++) + double value = 0; + for (var i = 0; i < aColumns; i++) { - var jm = j * rowCount; - x[jm + i] -= x[jm + k] * r[km + i]; + value += vt[(j * aColumns) + i] * tmp[i]; } + + x[(k * aColumns) + j] = value; } } } - public void SingularValueDecomposition(bool computeVectors, double[] a, double[] s, double[] u, double[] vt) - { - throw new NotImplementedException(); - } - - public void SingularValueDecomposition(bool computeVectors, double[] a, double[] s, double[] u, double[] vt, double[] work) - { - throw new NotImplementedException(); - } - - public void SvdSolve(double[] a, double[] s, double[] u, double[] vt, double[] b, double[] x) - { - throw new NotImplementedException(); - } - - public void SvdSolve(double[] a, double[] s, double[] u, double[] vt, double[] b, double[] x, double[] work) - { - throw new NotImplementedException(); - } - - public void SvdSolveFactored(int columnsOfB, double[] s, double[] u, double[] vt, double[] b, double[] x) - { - throw new NotImplementedException(); - } - #endregion #region ILinearAlgebraProvider Members @@ -1976,52 +3835,179 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new NotImplementedException(); } - public void QRFactor(float[] r, float[] q) + /// + /// Computes the QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(float[] r, int rRows, int rColumns, float[] q) { throw new NotImplementedException(); } - public void QRFactor(float[] r, float[] q, float[] work) + /// + /// Computes the QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// 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 similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(float[] r, int rRows, int rColumns, float[] q, float[] work) { throw new NotImplementedException(); } - public void QRSolve(int columnsOfB, float[] r, float[] q, float[] b, float[] x) + /// + /// Solves A*X=B for X using QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void QRSolve(float[] r, int rRows, int rColumns, float[] q, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } - public void QRSolve(int columnsOfB, float[] r, float[] q, float[] b, float[] x, float[] work) + /// + /// Solves A*X=B for X using QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution 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. + public void QRSolve(float[] r, int rRows, int rColumns, float[] q, float[] b, int bColumns, float[] x, float[] work) { throw new NotImplementedException(); } - public void QRSolveFactored(int columnsOfB, float[] q, float[] r, float[] b, float[] x) + /// + /// Solves A*X=B for X using a previously QR factored matrix. + /// + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void QRSolveFactored(float[] q, float[] r, int rRows, int rColumns, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } - public void SingularValueDecomposition(bool computeVectors, float[] a, float[] s, float[] u, float[] vt) + /// + /// Computes the singular value decomposition of A. + /// + /// Compute the singular U and VT vectors or not. + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// If is true, on exit U contains the left + /// singular vectors. + /// If is true, on exit VT contains the transposed + /// right singular vectors. + /// This is equivalent to the GESVD LAPACK routine. + public void SingularValueDecomposition(bool computeVectors, float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt) { throw new NotImplementedException(); } - public void SingularValueDecomposition(bool computeVectors, float[] a, float[] s, float[] u, float[] vt, float[] work) + /// + /// Computes the singular value decomposition of A. + /// + /// Compute the singular U and VT vectors or not. + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// If is true, on exit U contains the left + /// singular vectors. + /// If is true, on exit VT contains the transposed + /// right singular vectors. + /// The work array. For real matrices, the work array should be at least + /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). + /// On exit, work[0] contains the optimal work size value. + /// This is equivalent to the GESVD LAPACK routine. + public void SingularValueDecomposition(bool computeVectors, float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] work) { throw new NotImplementedException(); } - public void SvdSolve(float[] a, float[] s, float[] u, float[] vt, float[] b, float[] x) + /// + /// Solves A*X=B for X using the singular value decomposition of A. + /// + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// On exit U contains the left singular vectors. + /// On exit VT contains the transposed right singular vectors. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void SvdSolve(float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } - public void SvdSolve(float[] a, float[] s, float[] u, float[] vt, float[] b, float[] x, float[] work) + /// + /// Solves A*X=B for X using the singular value decomposition of A. + /// + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// On exit U contains the left singular vectors. + /// On exit VT contains the transposed right singular vectors. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + /// The work array. For real matrices, the work array should be at least + /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). + /// On exit, work[0] contains the optimal work size value. + public void SvdSolve(float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x, float[] work) { throw new NotImplementedException(); } - public void SvdSolveFactored(int columnsOfB, float[] s, float[] u, float[] vt, float[] b, float[] x) + /// + /// Solves A*X=B for X using a previously SVD decomposed matrix. + /// + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void SvdSolveFactored(int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -2767,52 +4753,179 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new NotImplementedException(); } - public void QRFactor(Complex[] r, Complex[] q) + /// + /// Computes the QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex[] r, int rRows, int rColumns, Complex[] q) { throw new NotImplementedException(); } - public void QRFactor(Complex[] r, Complex[] q, Complex[] work) + /// + /// Computes the QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// 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 similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] work) { throw new NotImplementedException(); } - public void QRSolve(int columnsOfB, Complex[] r, Complex[] q, Complex[] b, Complex[] x) + /// + /// Solves A*X=B for X using QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void QRSolve(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } - public void QRSolve(int columnsOfB, Complex[] r, Complex[] q, Complex[] b, Complex[] x, Complex[] work) + /// + /// Solves A*X=B for X using QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution 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. + public void QRSolve(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] b, int bColumns, Complex[] x, Complex[] work) { throw new NotImplementedException(); } - public void QRSolveFactored(int columnsOfB, Complex[] q, Complex[] r, Complex[] b, Complex[] x) + /// + /// Solves A*X=B for X using a previously QR factored matrix. + /// + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void QRSolveFactored(Complex[] q, Complex[] r, int rRows, int rColumns, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } - public void SingularValueDecomposition(bool computeVectors, Complex[] a, Complex[] s, Complex[] u, Complex[] vt) + /// + /// Computes the singular value decomposition of A. + /// + /// Compute the singular U and VT vectors or not. + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// If is true, on exit U contains the left + /// singular vectors. + /// If is true, on exit VT contains the transposed + /// right singular vectors. + /// This is equivalent to the GESVD LAPACK routine. + public void SingularValueDecomposition(bool computeVectors, Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt) { throw new NotImplementedException(); } - public void SingularValueDecomposition(bool computeVectors, Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) + /// + /// Computes the singular value decomposition of A. + /// + /// Compute the singular U and VT vectors or not. + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// If is true, on exit U contains the left + /// singular vectors. + /// If is true, on exit VT contains the transposed + /// right singular vectors. + /// The work array. For real matrices, the work array should be at least + /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). + /// On exit, work[0] contains the optimal work size value. + /// This is equivalent to the GESVD LAPACK routine. + public void SingularValueDecomposition(bool computeVectors, Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) { throw new NotImplementedException(); } - public void SvdSolve(Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x) + /// + /// Solves A*X=B for X using the singular value decomposition of A. + /// + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// On exit U contains the left singular vectors. + /// On exit VT contains the transposed right singular vectors. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void SvdSolve(Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } - public void SvdSolve(Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x, Complex[] work) + /// + /// Solves A*X=B for X using the singular value decomposition of A. + /// + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// On exit U contains the left singular vectors. + /// On exit VT contains the transposed right singular vectors. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + /// The work array. For real matrices, the work array should be at least + /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). + /// On exit, work[0] contains the optimal work size value. + public void SvdSolve(Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x, Complex[] work) { throw new NotImplementedException(); } - public void SvdSolveFactored(int columnsOfB, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x) + /// + /// Solves A*X=B for X using a previously SVD decomposed matrix. + /// + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void SvdSolveFactored(int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -3558,52 +5671,179 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new NotImplementedException(); } - public void QRFactor(Complex32[] r, Complex32[] q) + /// + /// Computes the QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex32[] r, int rRows, int rColumns, Complex32[] q) { throw new NotImplementedException(); } - public void QRFactor(Complex32[] r, Complex32[] q, Complex32[] work) + /// + /// Computes the QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// 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 similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] work) { throw new NotImplementedException(); } - public void QRSolve(int columnsOfB, Complex32[] r, Complex32[] q, Complex32[] b, Complex32[] x) + /// + /// Solves A*X=B for X using QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void QRSolve(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } - public void QRSolve(int columnsOfB, Complex32[] r, Complex32[] q, Complex32[] b, Complex32[] x, Complex32[] work) + /// + /// Solves A*X=B for X using QR factorization of A. + /// + /// On entry, it is the M by N A matrix to factor. On exit, + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the + /// QR factorization. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution 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. + public void QRSolve(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] b, int bColumns, Complex32[] x, Complex32[] work) { throw new NotImplementedException(); } - public void QRSolveFactored(int columnsOfB, Complex32[] q, Complex32[] r, Complex32[] b, Complex32[] x) + /// + /// Solves A*X=B for X using a previously QR factored matrix. + /// + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void QRSolveFactored(Complex32[] q, Complex32[] r, int rRows, int rColumns, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } - public void SingularValueDecomposition(bool computeVectors, Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt) + /// + /// Computes the singular value decomposition of A. + /// + /// Compute the singular U and VT vectors or not. + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// If is true, on exit U contains the left + /// singular vectors. + /// If is true, on exit VT contains the transposed + /// right singular vectors. + /// This is equivalent to the GESVD LAPACK routine. + public void SingularValueDecomposition(bool computeVectors, Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt) { throw new NotImplementedException(); } - public void SingularValueDecomposition(bool computeVectors, Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) + /// + /// Computes the singular value decomposition of A. + /// + /// Compute the singular U and VT vectors or not. + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// If is true, on exit U contains the left + /// singular vectors. + /// If is true, on exit VT contains the transposed + /// right singular vectors. + /// The work array. For real matrices, the work array should be at least + /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). + /// On exit, work[0] contains the optimal work size value. + /// This is equivalent to the GESVD LAPACK routine. + public void SingularValueDecomposition(bool computeVectors, Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) { throw new NotImplementedException(); } - public void SvdSolve(Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x) + /// + /// Solves A*X=B for X using the singular value decomposition of A. + /// + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// On exit U contains the left singular vectors. + /// On exit VT contains the transposed right singular vectors. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void SvdSolve(Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } - public void SvdSolve(Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x, Complex32[] work) + /// + /// Solves A*X=B for X using the singular value decomposition of A. + /// + /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The singular values of A in ascending value. + /// On exit U contains the left singular vectors. + /// On exit VT contains the transposed right singular vectors. + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + /// The work array. For real matrices, the work array should be at least + /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). + /// On exit, work[0] contains the optimal work size value. + public void SvdSolve(Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x, Complex32[] work) { throw new NotImplementedException(); } - public void SvdSolveFactored(int columnsOfB, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x) + /// + /// Solves A*X=B for X using a previously SVD decomposed matrix. + /// + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . + /// The B matrix. + /// The number of columns of B. + /// On exit, the solution matrix. + public void SvdSolveFactored(int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs index 0281e06b..43d26741 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs @@ -28,7 +28,7 @@ /* This file is automatically generated - do not modify it. Change NativeLinearAlgebraProvider.include instead. - Last generated on UTC 2010-06-27 13:41:29Z + Last generated on UTC 2010-07-04 13:21:48Z */ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl @@ -234,6 +234,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// /// The requested of the matrix. @@ -247,6 +249,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// The work array. Only used when /// and needs to be have a length of at least M (number of rows of . @@ -451,24 +455,25 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.d_cholesky_factor(order, a); + + SafeNativeMethods.d_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. - /// This is equivalent to the POTRF add POTRS LAPACK routines. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. + /// This is equivalent to the POTRF add POTRS LAPACK routines. + /// public void CholeskySolve(double[] a, int aOrder, double[] b, int bRows, int bColumns) { throw new NotImplementedException(); @@ -480,8 +485,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(double[] a, int aOrder, double[] b, int bRows, int bColumns) { @@ -492,11 +497,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(double[] r, double[] q) + public void QRFactor(double[] r, int rRows, int rColumns, double[] q) { throw new NotImplementedException(); } @@ -505,13 +512,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(double[] r, double[] q, double[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(double[] r, int rRows, int rColumns, double[] q, double[] work) { throw new NotImplementedException(); } @@ -519,14 +529,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, double[] r, double[] q, double[] b, double[] x) + public void QRSolve(double[] r, int rRows, int rColumns, double[] q, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -534,17 +546,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, double[] r, double[] q, double[] b, double[] x, double[] work) + public void QRSolve(double[] r, int rRows, int rColumns, double[] q, double[] b, int bColumns, double[] x, double[] work) { throw new NotImplementedException(); } @@ -552,12 +566,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, double[] q, double[] r, double[] b, double[] x) + public void QRSolveFactored(double[] q, double[] r, int rRows, int rColumns, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -567,13 +583,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, double[] a, double[] s, double[] u, double[] vt) + public void SingularValueDecomposition(bool computeVectors, double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt) { throw new NotImplementedException(); } @@ -583,6 +601,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -592,7 +612,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, double[] a, double[] s, double[] u, double[] vt, double[] work) + public void SingularValueDecomposition(bool computeVectors, double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] work) { throw new NotImplementedException(); } @@ -601,12 +621,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(double[] a, double[] s, double[] u, double[] vt, double[] b, double[] x) + public void SvdSolve(double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -615,15 +638,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(double[] a, double[] s, double[] u, double[] vt, double[] b, double[] x, double[] work) + public void SvdSolve(double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x, double[] work) { throw new NotImplementedException(); } @@ -631,13 +657,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, double[] s, double[] u, double[] vt, double[] b, double[] x) + public void SvdSolveFactored(int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -835,6 +863,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// /// The requested of the matrix. @@ -848,6 +878,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// The work array. Only used when /// and needs to be have a length of at least M (number of rows of . @@ -925,6 +957,7 @@ 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. /// @@ -1052,23 +1085,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.s_cholesky_factor(order, a); + + SafeNativeMethods.s_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRF add POTRS LAPACK routines. public void CholeskySolve(float[] a, int aOrder, float[] b, int bRows, int bColumns) { @@ -1081,8 +1114,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(float[] a, int aOrder, float[] b, int bRows, int bColumns) { @@ -1093,11 +1126,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(float[] r, float[] q) + public void QRFactor(float[] r, int rRows, int rColumns, float[] q) { throw new NotImplementedException(); } @@ -1106,13 +1141,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(float[] r, float[] q, float[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(float[] r, int rRows, int rColumns, float[] q, float[] work) { throw new NotImplementedException(); } @@ -1120,14 +1158,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, float[] r, float[] q, float[] b, float[] x) + public void QRSolve(float[] r, int rRows, int rColumns, float[] q, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1135,17 +1175,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, float[] r, float[] q, float[] b, float[] x, float[] work) + public void QRSolve(float[] r, int rRows, int rColumns, float[] q, float[] b, int bColumns, float[] x, float[] work) { throw new NotImplementedException(); } @@ -1153,12 +1195,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, float[] q, float[] r, float[] b, float[] x) + public void QRSolveFactored(float[] q, float[] r, int rRows, int rColumns, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1168,13 +1212,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, float[] a, float[] s, float[] u, float[] vt) + public void SingularValueDecomposition(bool computeVectors, float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt) { throw new NotImplementedException(); } @@ -1184,6 +1230,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -1193,7 +1241,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, float[] a, float[] s, float[] u, float[] vt, float[] work) + public void SingularValueDecomposition(bool computeVectors, float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] work) { throw new NotImplementedException(); } @@ -1202,12 +1250,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(float[] a, float[] s, float[] u, float[] vt, float[] b, float[] x) + public void SvdSolve(float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1216,15 +1267,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(float[] a, float[] s, float[] u, float[] vt, float[] b, float[] x, float[] work) + public void SvdSolve(float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x, float[] work) { throw new NotImplementedException(); } @@ -1232,13 +1286,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, float[] s, float[] u, float[] vt, float[] b, float[] x) + public void SvdSolveFactored(int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1436,6 +1492,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// /// The requested of the matrix. @@ -1449,6 +1507,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// The work array. Only used when /// and needs to be have a length of at least M (number of rows of . @@ -1653,23 +1713,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.z_cholesky_factor(order, a); + + SafeNativeMethods.z_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRF add POTRS LAPACK routines. public void CholeskySolve(Complex[] a, int aOrder, Complex[] b, int bRows, int bColumns) { @@ -1682,8 +1742,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(Complex[] a, int aOrder, Complex[] b, int bRows, int bColumns) { @@ -1694,11 +1754,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(Complex[] r, Complex[] q) + public void QRFactor(Complex[] r, int rRows, int rColumns, Complex[] q) { throw new NotImplementedException(); } @@ -1707,13 +1769,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(Complex[] r, Complex[] q, Complex[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] work) { throw new NotImplementedException(); } @@ -1721,14 +1786,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, Complex[] r, Complex[] q, Complex[] b, Complex[] x) + public void QRSolve(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -1736,17 +1803,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, Complex[] r, Complex[] q, Complex[] b, Complex[] x, Complex[] work) + public void QRSolve(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] b, int bColumns, Complex[] x, Complex[] work) { throw new NotImplementedException(); } @@ -1754,12 +1823,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, Complex[] q, Complex[] r, Complex[] b, Complex[] x) + public void QRSolveFactored(Complex[] q, Complex[] r, int rRows, int rColumns, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -1769,13 +1840,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex[] a, Complex[] s, Complex[] u, Complex[] vt) + public void SingularValueDecomposition(bool computeVectors, Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt) { throw new NotImplementedException(); } @@ -1785,6 +1858,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -1794,7 +1869,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) + public void SingularValueDecomposition(bool computeVectors, Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) { throw new NotImplementedException(); } @@ -1803,12 +1878,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x) + public void SvdSolve(Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -1817,15 +1895,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x, Complex[] work) + public void SvdSolve(Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x, Complex[] work) { throw new NotImplementedException(); } @@ -1833,13 +1914,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x) + public void SvdSolveFactored(int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -2258,23 +2341,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.c_cholesky_factor(order, a); + + SafeNativeMethods.c_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRF add POTRS LAPACK routines. public void CholeskySolve(Complex32[] a, int aOrder, Complex32[] b, int bRows, int bColumns) { @@ -2287,8 +2370,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(Complex32[] a, int aOrder, Complex32[] b, int bRows, int bColumns) { @@ -2299,11 +2382,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(Complex32[] r, Complex32[] q) + public void QRFactor(Complex32[] r, int rRows, int rColumns, Complex32[] q) { throw new NotImplementedException(); } @@ -2312,13 +2397,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(Complex32[] r, Complex32[] q, Complex32[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] work) { throw new NotImplementedException(); } @@ -2326,14 +2414,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, Complex32[] r, Complex32[] q, Complex32[] b, Complex32[] x) + public void QRSolve(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } @@ -2341,17 +2431,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, Complex32[] r, Complex32[] q, Complex32[] b, Complex32[] x, Complex32[] work) + public void QRSolve(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] b, int bColumns, Complex32[] x, Complex32[] work) { throw new NotImplementedException(); } @@ -2359,12 +2451,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, Complex32[] q, Complex32[] r, Complex32[] b, Complex32[] x) + public void QRSolveFactored(Complex32[] q, Complex32[] r, int rRows, int rColumns, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } @@ -2374,13 +2468,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt) + public void SingularValueDecomposition(bool computeVectors, Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt) { throw new NotImplementedException(); } @@ -2390,6 +2486,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -2399,7 +2497,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) + public void SingularValueDecomposition(bool computeVectors, Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) { throw new NotImplementedException(); } @@ -2408,12 +2506,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x) + public void SvdSolve(Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } @@ -2422,15 +2523,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x, Complex32[] work) + public void SvdSolve(Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x, Complex32[] work) { throw new NotImplementedException(); } @@ -2438,13 +2542,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x) + public void SvdSolveFactored(int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } diff --git a/src/Numerics/Algorithms/LinearAlgebra/NativeAlgebraProvider.include b/src/Numerics/Algorithms/LinearAlgebra/NativeAlgebraProvider.include index 0c8bcc52..4c5f734c 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/NativeAlgebraProvider.include +++ b/src/Numerics/Algorithms/LinearAlgebra/NativeAlgebraProvider.include @@ -249,6 +249,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// /// The requested of the matrix. @@ -262,6 +264,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// The work array. Only used when /// and needs to be have a length of at least M (number of rows of . @@ -466,24 +470,25 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.d_cholesky_factor(order, a); + + SafeNativeMethods.d_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. - /// This is equivalent to the POTRF add POTRS LAPACK routines. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. + /// This is equivalent to the POTRF add POTRS LAPACK routines. + /// public void CholeskySolve(double[] a, int aOrder, double[] b, int bRows, int bColumns) { throw new NotImplementedException(); @@ -495,8 +500,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(double[] a, int aOrder, double[] b, int bRows, int bColumns) { @@ -507,11 +512,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(double[] r, double[] q) + public void QRFactor(double[] r, int rRows, int rColumns, double[] q) { throw new NotImplementedException(); } @@ -520,13 +527,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(double[] r, double[] q, double[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(double[] r, int rRows, int rColumns, double[] q, double[] work) { throw new NotImplementedException(); } @@ -534,14 +544,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, double[] r, double[] q, double[] b, double[] x) + public void QRSolve(double[] r, int rRows, int rColumns, double[] q, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -549,17 +561,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, double[] r, double[] q, double[] b, double[] x, double[] work) + public void QRSolve(double[] r, int rRows, int rColumns, double[] q, double[] b, int bColumns, double[] x, double[] work) { throw new NotImplementedException(); } @@ -567,12 +581,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, double[] q, double[] r, double[] b, double[] x) + public void QRSolveFactored(double[] q, double[] r, int rRows, int rColumns, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -582,13 +598,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, double[] a, double[] s, double[] u, double[] vt) + public void SingularValueDecomposition(bool computeVectors, double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt) { throw new NotImplementedException(); } @@ -598,6 +616,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -607,7 +627,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, double[] a, double[] s, double[] u, double[] vt, double[] work) + public void SingularValueDecomposition(bool computeVectors, double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] work) { throw new NotImplementedException(); } @@ -616,12 +636,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(double[] a, double[] s, double[] u, double[] vt, double[] b, double[] x) + public void SvdSolve(double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -630,15 +653,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(double[] a, double[] s, double[] u, double[] vt, double[] b, double[] x, double[] work) + public void SvdSolve(double[] a, int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x, double[] work) { throw new NotImplementedException(); } @@ -646,13 +672,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, double[] s, double[] u, double[] vt, double[] b, double[] x) + public void SvdSolveFactored(int aRows, int aColumns, double[] s, double[] u, double[] vt, double[] b, int bColumns, double[] x) { throw new NotImplementedException(); } @@ -862,6 +890,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// /// The requested of the matrix. @@ -875,6 +905,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// The work array. Only used when /// and needs to be have a length of at least M (number of rows of . @@ -952,6 +984,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> SafeNativeMethods.s_matrix_multiply(transposeA, transposeB, m, n, k, alpha, a, b, beta, c); } + /// /// /// Computes the LUP factorization of A. P*A = L*U. /// @@ -1079,23 +1112,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.s_cholesky_factor(order, a); + + SafeNativeMethods.s_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRF add POTRS LAPACK routines. public void CholeskySolve(float[] a, int aOrder, float[] b, int bRows, int bColumns) { @@ -1108,8 +1141,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(float[] a, int aOrder, float[] b, int bRows, int bColumns) { @@ -1120,11 +1153,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(float[] r, float[] q) + public void QRFactor(float[] r, int rRows, int rColumns, float[] q) { throw new NotImplementedException(); } @@ -1133,13 +1168,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(float[] r, float[] q, float[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(float[] r, int rRows, int rColumns, float[] q, float[] work) { throw new NotImplementedException(); } @@ -1147,14 +1185,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, float[] r, float[] q, float[] b, float[] x) + public void QRSolve(float[] r, int rRows, int rColumns, float[] q, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1162,17 +1202,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, float[] r, float[] q, float[] b, float[] x, float[] work) + public void QRSolve(float[] r, int rRows, int rColumns, float[] q, float[] b, int bColumns, float[] x, float[] work) { throw new NotImplementedException(); } @@ -1180,12 +1222,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, float[] q, float[] r, float[] b, float[] x) + public void QRSolveFactored(float[] q, float[] r, int rRows, int rColumns, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1195,13 +1239,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, float[] a, float[] s, float[] u, float[] vt) + public void SingularValueDecomposition(bool computeVectors, float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt) { throw new NotImplementedException(); } @@ -1211,6 +1257,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -1220,7 +1268,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, float[] a, float[] s, float[] u, float[] vt, float[] work) + public void SingularValueDecomposition(bool computeVectors, float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] work) { throw new NotImplementedException(); } @@ -1229,12 +1277,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(float[] a, float[] s, float[] u, float[] vt, float[] b, float[] x) + public void SvdSolve(float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1243,15 +1294,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(float[] a, float[] s, float[] u, float[] vt, float[] b, float[] x, float[] work) + public void SvdSolve(float[] a, int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x, float[] work) { throw new NotImplementedException(); } @@ -1259,13 +1313,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, float[] s, float[] u, float[] vt, float[] b, float[] x) + public void SvdSolveFactored(int aRows, int aColumns, float[] s, float[] u, float[] vt, float[] b, int bColumns, float[] x) { throw new NotImplementedException(); } @@ -1475,6 +1531,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// /// The requested of the matrix. @@ -1488,6 +1546,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the requested of the matrix. /// /// The type of norm to compute. + /// The number of rows in the matrix. + /// The number of columns in the matrix. /// The matrix to compute the norm from. /// The work array. Only used when /// and needs to be have a length of at least M (number of rows of . @@ -1692,23 +1752,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.z_cholesky_factor(order, a); + + SafeNativeMethods.z_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRF add POTRS LAPACK routines. public void CholeskySolve(Complex[] a, int aOrder, Complex[] b, int bRows, int bColumns) { @@ -1721,8 +1781,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(Complex[] a, int aOrder, Complex[] b, int bRows, int bColumns) { @@ -1733,11 +1793,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(Complex[] r, Complex[] q) + public void QRFactor(Complex[] r, int rRows, int rColumns, Complex[] q) { throw new NotImplementedException(); } @@ -1746,13 +1808,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(Complex[] r, Complex[] q, Complex[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] work) { throw new NotImplementedException(); } @@ -1760,14 +1825,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, Complex[] r, Complex[] q, Complex[] b, Complex[] x) + public void QRSolve(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -1775,17 +1842,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, Complex[] r, Complex[] q, Complex[] b, Complex[] x, Complex[] work) + public void QRSolve(Complex[] r, int rRows, int rColumns, Complex[] q, Complex[] b, int bColumns, Complex[] x, Complex[] work) { throw new NotImplementedException(); } @@ -1793,12 +1862,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, Complex[] q, Complex[] r, Complex[] b, Complex[] x) + public void QRSolveFactored(Complex[] q, Complex[] r, int rRows, int rColumns, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -1808,13 +1879,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex[] a, Complex[] s, Complex[] u, Complex[] vt) + public void SingularValueDecomposition(bool computeVectors, Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt) { throw new NotImplementedException(); } @@ -1824,6 +1897,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -1833,7 +1908,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) + public void SingularValueDecomposition(bool computeVectors, Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) { throw new NotImplementedException(); } @@ -1842,12 +1917,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x) + public void SvdSolve(Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -1856,15 +1934,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(Complex[] a, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x, Complex[] work) + public void SvdSolve(Complex[] a, int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x, Complex[] work) { throw new NotImplementedException(); } @@ -1872,13 +1953,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, Complex[] x) + public void SvdSolveFactored(int aRows, int aColumns, Complex[] s, Complex[] u, Complex[] vt, Complex[] b, int bColumns, Complex[] x) { throw new NotImplementedException(); } @@ -2309,23 +2392,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> { throw new ArgumentNullException("a"); } - - if ( order < 1) + + if (order < 1) { - throw new ArgumentException(Properties.Resources.ArgumentMustBePositive, "order"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - - SafeNativeMethods.c_cholesky_factor(order, a); + + SafeNativeMethods.c_cholesky_factor(order, a); } - + /// /// Solves A*X=B for X using Cholesky factorization. /// /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRF add POTRS LAPACK routines. public void CholeskySolve(Complex32[] a, int aOrder, Complex32[] b, int bRows, int bColumns) { @@ -2338,8 +2421,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// The square, positive definite matrix A. /// The number of rows and columns in A. /// The B matrix. - /// The number of rows in the B matrix. - /// The number of columns in the B matrix. + /// The number of rows in the B matrix. + /// The number of columns in the B matrix. /// This is equivalent to the POTRS LAPACK routine. public void CholeskySolveFactored(Complex32[] a, int aOrder, Complex32[] b, int bRows, int bColumns) { @@ -2350,11 +2433,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// This is similar to the GEQRF and ORGQR LAPACK routines. - public void QRFactor(Complex32[] r, Complex32[] q) + public void QRFactor(Complex32[] r, int rRows, int rColumns, Complex32[] q) { throw new NotImplementedException(); } @@ -2363,13 +2448,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Computes the QR factorization of A. /// /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// 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. - public void QRFactor(Complex32[] r, Complex32[] q, Complex32[] work) + /// This is similar to the GEQRF and ORGQR LAPACK routines. + public void QRFactor(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] work) { throw new NotImplementedException(); } @@ -2377,14 +2465,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolve(int columnsOfB, Complex32[] r, Complex32[] q, Complex32[] b, Complex32[] x) + public void QRSolve(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } @@ -2392,17 +2482,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using QR factorization of A. /// - /// The number of columns of B. /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// On exit, A M by M matrix that holds the Q matrix of the + /// it is overwritten with the R matrix of the QR factorization. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// The B matrix. + /// The number of columns of B. /// On exit, the solution 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. - public void QRSolve(int columnsOfB, Complex32[] r, Complex32[] q, Complex32[] b, Complex32[] x, Complex32[] work) + public void QRSolve(Complex32[] r, int rRows, int rColumns, Complex32[] q, Complex32[] b, int bColumns, Complex32[] x, Complex32[] work) { throw new NotImplementedException(); } @@ -2410,12 +2502,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The number of columns of B. - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . + /// The Q matrix obtained by calling . + /// The R matrix obtained by calling . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void QRSolveFactored(int columnsOfB, Complex32[] q, Complex32[] r, Complex32[] b, Complex32[] x) + public void QRSolveFactored(Complex32[] q, Complex32[] r, int rRows, int rColumns, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } @@ -2425,13 +2519,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt) + public void SingularValueDecomposition(bool computeVectors, Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt) { throw new NotImplementedException(); } @@ -2441,6 +2537,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Compute the singular U and VT vectors or not. /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// If is true, on exit U contains the left /// singular vectors. @@ -2450,7 +2548,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. - public void SingularValueDecomposition(bool computeVectors, Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) + public void SingularValueDecomposition(bool computeVectors, Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) { throw new NotImplementedException(); } @@ -2459,12 +2557,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolve(Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x) + public void SvdSolve(Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } @@ -2473,15 +2574,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// Solves A*X=B for X using the singular value decomposition of A. /// /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. /// The singular values of A in ascending value. /// On exit U contains the left singular vectors. /// On exit VT contains the transposed right singular vectors. /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. /// The work array. For real matrices, the work array should be at least /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). /// On exit, work[0] contains the optimal work size value. - public void SvdSolve(Complex32[] a, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x, Complex32[] work) + public void SvdSolve(Complex32[] a, int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x, Complex32[] work) { throw new NotImplementedException(); } @@ -2489,13 +2593,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.<#=library#> /// /// Solves A*X=B for X using a previously SVD decomposed matrix. /// - /// The number of columns of B. - /// The s values returned by . - /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The number of rows in the A matrix. + /// The number of columns in the A matrix. + /// The s values returned by . + /// The left singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix. + /// The number of columns of B. /// On exit, the solution matrix. - public void SvdSolveFactored(int columnsOfB, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, Complex32[] x) + public void SvdSolveFactored(int aRows, int aColumns, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] b, int bColumns, Complex32[] x) { throw new NotImplementedException(); } diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs b/src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs index 4fd3370e..e41f8755 100644 --- a/src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs +++ b/src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs @@ -32,7 +32,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization { using System; using Properties; - using Threading; /// /// A class which encapsulates the functionality of the QR decomposition. @@ -65,7 +64,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization MatrixR = matrix.Clone(); MatrixQ = new DenseMatrix(matrix.RowCount); - Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, ((DenseMatrix)MatrixQ).Data); + Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount, ((DenseMatrix)MatrixQ).Data); } /// @@ -116,18 +115,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization throw new NotImplementedException("Can only do QR factorization for dense matrices at the moment."); } - var solution = new double[dinput.Data.Length]; - Control.LinearAlgebraProvider.QRSolveFactored(input.ColumnCount, ((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, dinput.Data, solution); - CommonParallel.For( - 0, - dresult.RowCount, - row => - { - for (var col = 0; col < dresult.ColumnCount; col++) - { - dresult[row, col] = solution[row + (col * dinput.RowCount)]; - } - }); + Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, dinput.Data, input.ColumnCount, dresult.Data); } /// @@ -172,12 +160,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization throw new NotImplementedException("Can only do QR factorization for dense vectors at the moment."); } - var solution = new double[dinput.Data.Length]; - Control.LinearAlgebraProvider.QRSolveFactored(1, ((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, dinput.Data, solution); - CommonParallel.For( - 0, - dresult.Count, - index => { dresult[index] = solution[index]; }); + Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, dinput.Data, 1, dresult.Data); } } } diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/DenseSvd.cs b/src/Numerics/LinearAlgebra/Double/Factorization/DenseSvd.cs new file mode 100644 index 00000000..db81cfac --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/Factorization/DenseSvd.cs @@ -0,0 +1,180 @@ +// +// 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 the singular value decomposition (SVD) for . + /// Suppose M is an m-by-n matrix whose entries are real numbers. + /// Then there exists a factorization of the form M = UΣVT where: + /// - U is an m-by-m unitary matrix; + /// - Σ is m-by-n diagonal matrix with nonnegative real numbers on the diagonal; + /// - VT denotes transpose of V, an n-by-n unitary matrix; + /// Such a factorization is called a singular-value decomposition of M. A common convention is to order the diagonal + /// entries Σ(i,i) in descending order. In this case, the diagonal matrix Σ is uniquely determined + /// by M (though the matrices U and V are not). The diagonal entries of Σ are known as the singular values of M. + /// + /// + /// The computation of the singular value decomposition is done at construction time. + /// + public class DenseSvd : Svd + { + /// + /// Initializes a new instance of the class. This object will compute the + /// the singular value decomposition when the constructor is called and cache it's decomposition. + /// + /// The matrix to factor. + /// Compute the singular U and VT vectors or not. + /// If is null. + /// If SVD algorithm failed to converge with matrix . + public DenseSvd(DenseMatrix matrix, bool computeVectors) + { + if (matrix == null) + { + throw new ArgumentNullException("matrix"); + } + + ComputeVectors = computeVectors; + var nm = Math.Min(matrix.RowCount, matrix.ColumnCount); + VectorS = new DenseVector(nm); + MatrixU = new DenseMatrix(matrix.RowCount); + MatrixVT = new DenseMatrix(matrix.ColumnCount); + Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data); + } + + /// + /// Solves a system of linear equations, AX = B, with A SVD 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"); + } + + if (!ComputeVectors) + { + throw new InvalidOperationException(Resources.SingularVectorsNotComputed); + } + + // The solution X should have the same number of columns as B + if (input.ColumnCount != result.ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); + } + + // The dimension compatibility conditions for X = A\B require the two matrices A and B to have the same number of rows + if (MatrixU.RowCount != input.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); + } + + // The solution X row dimension is equal to the column dimension of A + if (MatrixVT.ColumnCount != result.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); + } + + var dinput = input as DenseMatrix; + if (dinput == null) + { + throw new NotImplementedException("Can only do SVD factorization for dense matrices at the moment."); + } + + var dresult = result as DenseMatrix; + if (dresult == null) + { + throw new NotImplementedException("Can only do SVD factorization for dense matrices at the moment."); + } + + Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data); + } + + /// + /// Solves a system of linear equations, Ax = b, with A SVD factorized. + /// + /// The right hand side vector, b. + /// The left hand side , x. + public override void Solve(Vector input, Vector result) + { + if (input == null) + { + throw new ArgumentNullException("input"); + } + + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (!ComputeVectors) + { + throw new InvalidOperationException(Resources.SingularVectorsNotComputed); + } + + // Ax=b where A is an m x n matrix + // Check that b is a column vector with m entries + if (MatrixU.RowCount != input.Count) + { + throw new ArgumentException(Resources.ArgumentVectorsSameLength); + } + + // Check that x is a column vector with n entries + if (MatrixVT.ColumnCount != result.Count) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions); + } + + var dinput = input as DenseVector; + if (dinput == null) + { + throw new NotImplementedException("Can only do QR factorization for dense vectors at the moment."); + } + + var dresult = result as DenseVector; + if (dresult == null) + { + throw new NotImplementedException("Can only do QR factorization for dense vectors at the moment."); + } + + Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, 1, dresult.Data); + } + } +} diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/ExtensionMethods.cs b/src/Numerics/LinearAlgebra/Double/Factorization/ExtensionMethods.cs index 3eba5289..efd621ea 100644 --- a/src/Numerics/LinearAlgebra/Double/Factorization/ExtensionMethods.cs +++ b/src/Numerics/LinearAlgebra/Double/Factorization/ExtensionMethods.cs @@ -64,5 +64,16 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization { return Factorization.QR.Create(matrix); } + + /// + /// Computes the SVD decomposition for a matrix. + /// + /// The matrix to factor. + /// Compute the singular U and VT vectors or not. + /// The QR decomposition object. + public static Svd Svd(this Matrix matrix, bool computeVectors) + { + return Factorization.Svd.Create(matrix, computeVectors); + } } } diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/QR.cs b/src/Numerics/LinearAlgebra/Double/Factorization/QR.cs index f4f216c6..e52326fe 100644 --- a/src/Numerics/LinearAlgebra/Double/Factorization/QR.cs +++ b/src/Numerics/LinearAlgebra/Double/Factorization/QR.cs @@ -77,11 +77,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization /// /// Gets orthogonal Q matrix /// - public virtual Matrix Q + public virtual Matrix Q { get { - return MatrixQ; + return MatrixQ.Clone(); } } diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/Svd.cs b/src/Numerics/LinearAlgebra/Double/Factorization/Svd.cs new file mode 100644 index 00000000..bb5f9962 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/Factorization/Svd.cs @@ -0,0 +1,283 @@ +// +// 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 the singular value decomposition (SVD). + /// Suppose M is an m-by-n matrix whose entries are real numbers. + /// Then there exists a factorization of the form M = UΣVT where: + /// - U is an m-by-m unitary matrix; + /// - Σ is m-by-n diagonal matrix with nonnegative real numbers on the diagonal; + /// - VT denotes transpose of V, an n-by-n unitary matrix; + /// Such a factorization is called a singular-value decomposition of M. A common convention is to order the diagonal + /// entries Σ(i,i) in descending order. In this case, the diagonal matrix Σ is uniquely determined + /// by M (though the matrices U and V are not). The diagonal entries of Σ are known as the singular values of M. + /// + /// + /// The computation of the singular value decomposition is done at construction time. + /// + public abstract class Svd : ISolver + { + /// + /// Gets or sets a value indicating whether to compute U and VT matrices during SVD factorization or not + /// + protected bool ComputeVectors + { + get; + set; + } + + /// + /// Gets or sets the singular values (Σ) of matrix in ascending value. + /// + protected Vector VectorS + { + get; + set; + } + + /// + /// Gets or sets left singular vectors (U - m-by-m unitary matrix) + /// + protected Matrix MatrixU + { + get; + set; + } + + /// + /// Gets or sets transpose right singular vectors (transpose of V, an n-by-n unitary matrix + /// + protected Matrix MatrixVT + { + get; + set; + } + + /// + /// Gets the effective numerical matrix rank. + /// + /// The number of non-negligible singular values. + public virtual int Rank + { + get + { + var eps = Math.Pow(2.0, -52.0); + var tol = Math.Max(MatrixU.RowCount, MatrixVT.ColumnCount) * VectorS[0] * eps; + var nm = Math.Min(MatrixU.RowCount, MatrixVT.ColumnCount); + var rank = 0; + for (var h = 0; h < nm; h++) + { + if (VectorS[h] > tol) + { + rank++; + } + } + + return rank; + } + } + + /// + /// Internal method which routes the call to perform the singular value decomposition to the appropriate class. + /// + /// The matrix to factor. + /// Compute the singular U and VT vectors or not. + /// An SVD object. + internal static Svd Create(Matrix matrix, bool computeVectors) + { + var dense = matrix as DenseMatrix; + if (dense != null) + { + return new DenseSvd(dense, computeVectors); + } + + throw new NotImplementedException(); + } + + /// + /// Gets the two norm of the . + /// + /// The 2-norm of the . + public virtual double Norm2 + { + get + { + return VectorS[0]; + } + } + + /// + /// Gets the condition number max(S) / min(S) + /// + /// The condition number. + public virtual double ConditionNumber + { + get + { + var tmp = Math.Min(MatrixU.RowCount, MatrixVT.ColumnCount) - 1; + return VectorS[0] / VectorS[tmp]; + } + } + + /// + /// Gets the determinant of the square matrix for which the SVD was computed. + /// + public virtual double Determinant + { + get + { + if (MatrixU.RowCount != MatrixVT.ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + var det = 1.0; + for (var i = 0; i < VectorS.Count; i++) + { + det *= VectorS[i]; + if (Math.Abs(VectorS[i]).AlmostEqualInDecimalPlaces(0.0, 15)) + { + return 0; + } + } + + return Math.Abs(det); + } + } + + /// Returns the left singular vectors as a . + /// The left singular vectors. The matrix will be null, if computeVectors in the constructor is set to false. + public Matrix U() + { + return ComputeVectors ? MatrixU.Clone() : null; + } + + /// Returns the right singular vectors as a . + /// The right singular vectors. The matrix will be null, if computeVectors in the constructor is set to false. + /// This is the transpose of the V matrix. + public Matrix VT() + { + return ComputeVectors ? MatrixVT.Clone() : null; + } + + /// Returns the singular values as a diagonal . + /// The singular values as a diagonal . + public Matrix W() + { + var rows = MatrixU.RowCount; + var columns = MatrixVT.ColumnCount; + var result = MatrixU.CreateMatrix(rows, columns); + for (var i = 0; i < rows; i++) + { + for (var j = 0; j < columns; j++) + { + if (i == j) + { + result.At(i, i, VectorS[i]); + } + } + } + + return result; + } + + /// Returns the singular values as a . + /// the singular values as a . + public Vector S() + { + return VectorS.Clone(); + } + + /// + /// Solves a system of linear equations, AX = B, with A SVD 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"); + } + + if (!ComputeVectors) + { + throw new InvalidOperationException(Resources.SingularVectorsNotComputed); + } + + Matrix result = MatrixU.CreateMatrix(MatrixVT.ColumnCount, input.ColumnCount); + Solve(input, result); + return result; + } + + /// + /// Solves a system of linear equations, AX = B, with A SVD 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 SVD 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"); + } + + if (!ComputeVectors) + { + throw new InvalidOperationException(Resources.SingularVectorsNotComputed); + } + + var x = MatrixU.CreateVector(MatrixVT.ColumnCount); + Solve(input, x); + return x; + } + + /// + /// Solves a system of linear equations, Ax = b, with A SVD 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/Numerics.csproj b/src/Numerics/Numerics.csproj index 39c1e485..7979e567 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -102,8 +102,10 @@ + + diff --git a/src/Numerics/Properties/Resources.Designer.cs b/src/Numerics/Properties/Resources.Designer.cs index ee6eae14..a68693ba 100644 --- a/src/Numerics/Properties/Resources.Designer.cs +++ b/src/Numerics/Properties/Resources.Designer.cs @@ -465,6 +465,15 @@ namespace MathNet.Numerics.Properties { } } + /// + /// Looks up a localized string similar to An algorithm failed to converge.. + /// + internal static string ConvergenceFailed { + get { + return ResourceManager.GetString("ConvergenceFailed", resourceCulture); + } + } + /// /// Looks up a localized string similar to This feature is not implemented yet (but is planned).. /// @@ -591,6 +600,15 @@ namespace MathNet.Numerics.Properties { } } + /// + /// Looks up a localized string similar to The singular vectors were not computed.. + /// + internal static string SingularVectorsNotComputed { + get { + return ResourceManager.GetString("SingularVectorsNotComputed", resourceCulture); + } + } + /// /// Looks up a localized string similar to This special case is not supported yet (but is planned).. /// diff --git a/src/Numerics/Properties/Resources.resx b/src/Numerics/Properties/Resources.resx index 50742f13..3c600f68 100644 --- a/src/Numerics/Properties/Resources.resx +++ b/src/Numerics/Properties/Resources.resx @@ -303,4 +303,10 @@ The integer array does not represent a valid permutation. + + An algorithm failed to converge. + + + The singular vectors were not computed. + \ No newline at end of file diff --git a/src/Silverlight/Silverlight.csproj b/src/Silverlight/Silverlight.csproj index 174d2513..369daafb 100644 --- a/src/Silverlight/Silverlight.csproj +++ b/src/Silverlight/Silverlight.csproj @@ -233,6 +233,9 @@ LinearAlgebra\Double\Factorization\DenseQR.cs + + LinearAlgebra\Double\Factorization\DenseSvd.cs + LinearAlgebra\Double\Factorization\ExtensionMethods.cs @@ -242,6 +245,9 @@ LinearAlgebra\Double\Factorization\QR.cs + + LinearAlgebra\Double\Factorization\Svd.cs + LinearAlgebra\Double\ISolver.cs diff --git a/src/UnitTests/LinearAlgebraTests/Double/Factorization/SvdTests.cs b/src/UnitTests/LinearAlgebraTests/Double/Factorization/SvdTests.cs new file mode 100644 index 00000000..fdc9bb12 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Double/Factorization/SvdTests.cs @@ -0,0 +1,370 @@ +// +// 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.UnitTests.LinearAlgebraTests.Double.Factorization +{ + using System; + using MbUnit.Framework; + using LinearAlgebra.Double; + using LinearAlgebra.Double.Factorization; + + public class SvdTests + { + + [Test] + [ExpectedArgumentNullException] + public void ConstructorNull() + { + new DenseSvd(null, true); + } + + [Test] + [Row(1)] + [Row(10)] + [Row(100)] + public void CanFactorizeIdentity(int order) + { + var I = DenseMatrix.Identity(order); + var factorSvd = I.Svd(true); + + Assert.AreEqual(I.RowCount, factorSvd.U().RowCount); + Assert.AreEqual(I.RowCount, factorSvd.U().ColumnCount); + + Assert.AreEqual(I.ColumnCount, factorSvd.VT().RowCount); + Assert.AreEqual(I.ColumnCount, factorSvd.VT().ColumnCount); + + Assert.AreEqual(I.RowCount, factorSvd.W().RowCount); + Assert.AreEqual(I.ColumnCount, factorSvd.W().ColumnCount); + + for (var i = 0; i < factorSvd.W().RowCount; i++) + { + for (var j = 0; j < factorSvd.W().ColumnCount; j++) + { + Assert.AreEqual(i == j ? 1.0 : 0.0, factorSvd.W()[i, j]); + } + } + } + + [Test] + [Row(1,1)] + [Row(2,2)] + [Row(5,5)] + [Row(10,6)] + [Row(48,52)] + [Row(100,93)] + [MultipleAsserts] + public void CanFactorizeRandomMatrix(int row, int column) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(row, column); + var factorSvd = matrixA.Svd(true); + + // Make sure the U has the right dimensions. + Assert.AreEqual(row, factorSvd.U().RowCount); + Assert.AreEqual(row, factorSvd.U().ColumnCount); + + // Make sure the VT has the right dimensions. + Assert.AreEqual(column, factorSvd.VT().RowCount); + Assert.AreEqual(column, factorSvd.VT().ColumnCount); + + // Make sure the W has the right dimensions. + Assert.AreEqual(row, factorSvd.W().RowCount); + Assert.AreEqual(column, factorSvd.W().ColumnCount); + + // Make sure the U*W*VT is the original matrix. + var matrix = factorSvd.U() * factorSvd.W() * factorSvd.VT(); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreApproximatelyEqual(matrixA[i, j], matrix[i, j], 1.0e-11); + } + } + } + + [Test] + [Row(10, 8)] + [Row(48, 52)] + [Row(100, 93)] + [MultipleAsserts] + public void CheckRankOfNonSquare(int row, int column) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(row, column); + var factorSvd = matrixA.Svd(true); + + var mn = Math.Min(row, column); + Assert.AreEqual(factorSvd.Rank, mn); + } + + [Test] + [Row(1)] + [Row(2)] + [Row(5)] + [Row(9)] + [Row(50)] + [Row(90)] + [MultipleAsserts] + public void CheckRankSquare(int order) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(order, order); + var factorSvd = matrixA.Svd(true); + + if (factorSvd.Determinant != 0) + { + Assert.AreEqual(factorSvd.Rank, order); + } + else + { + Assert.AreEqual(factorSvd.Rank, order - 1); + } + } + + [Test] + [Row(10)] + [Row(50)] + [Row(100)] + [MultipleAsserts] + public void CheckRankOfSquareSingular(int order) + { + var matrixA = new DenseMatrix(order, order); + matrixA[0, 0] = 1; + matrixA[order - 1, order - 1] = 1; + for (var i = 1; i < order - 1; i++) + { + matrixA[i, i - 1] = 1; + matrixA[i, i + 1] = 1; + matrixA[i - 1, i] = 1; + matrixA[i + 1, i] = 1; + } + var factorSvd = matrixA.Svd(true); + + Assert.AreEqual(factorSvd.Determinant, 0); + Assert.AreEqual(factorSvd.Rank, order - 1); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void CannotSolveMatrixIfVectorsNotComputed() + { + var matrixA = MatrixLoader.GenerateRandomMatrix(10, 10); + var factorSvd = matrixA.Svd(false); + + var matrixB = MatrixLoader.GenerateRandomMatrix(10, 10); + factorSvd.Solve(matrixB); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void CannotSolveVectorIfVectorsNotComputed() + { + var matrixA = MatrixLoader.GenerateRandomMatrix(10, 10); + var factorSvd = matrixA.Svd(false); + + var vectorb = MatrixLoader.GenerateRandomVector(10); + factorSvd.Solve(vectorb); + } + + [Test] + [Row(1, 1)] + [Row(2, 2)] + [Row(5, 5)] + [Row(9, 10)] + [Row(50, 50)] + [Row(90, 100)] + [MultipleAsserts] + public void CanSolveForRandomVector(int row, int column) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(row, column); + var matrixACopy = matrixA.Clone(); + var factorSvd = matrixA.Svd(true); + + var vectorb = MatrixLoader.GenerateRandomVector(row); + var resultx = factorSvd.Solve(vectorb); + + Assert.AreEqual(matrixA.ColumnCount, 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]); + } + } + } + + [Test] + [Row(1, 1)] + [Row(4, 4)] + [Row(7, 8)] + [Row(10, 10)] + [Row(45, 50)] + [Row(80, 100)] + [MultipleAsserts] + public void CanSolveForRandomMatrix(int row, int count) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(row, count); + var matrixACopy = matrixA.Clone(); + var factorSvd = matrixA.Svd(true); + + var matrixB = MatrixLoader.GenerateRandomMatrix(row, count); + var matrixX = factorSvd.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 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]); + } + } + } + + [Test] + [Row(1, 1)] + [Row(2, 2)] + [Row(5, 5)] + [Row(9, 10)] + [Row(50, 50)] + [Row(90, 100)] + [MultipleAsserts] + public void CanSolveForRandomVectorWhenResultVectorGiven(int row, int column) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(row, column); + var matrixACopy = matrixA.Clone(); + var factorSvd = matrixA.Svd(true); + var vectorb = MatrixLoader.GenerateRandomVector(row); + var vectorbCopy = vectorb.Clone(); + var resultx = new DenseVector(column); + factorSvd.Solve(vectorb,resultx); + + 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, 1)] + [Row(4, 4)] + [Row(7, 8)] + [Row(10, 10)] + [Row(45, 50)] + [Row(80, 100)] + [MultipleAsserts] + public void CanSolveForRandomMatrixWhenResultMatrixGiven(int row, int column) + { + var matrixA = MatrixLoader.GenerateRandomMatrix(row, column); + var matrixACopy = matrixA.Clone(); + var factorSvd = matrixA.Svd(true); + + var matrixB = MatrixLoader.GenerateRandomMatrix(row, column); + var matrixBCopy = matrixB.Clone(); + + var matrixX = new DenseMatrix(column, column); + factorSvd.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]); + } + } + } + } +} diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index 67624be3..528eedac 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -90,6 +90,7 @@ +