Browse Source

LA: Simplify SVD decomposition architecture

optimization-1
Christoph Ruegg 13 years ago
parent
commit
f4ea07ce21
  1. 7
      src/Examples/LinearAlgebra/Factorization/Svd.cs
  2. 2
      src/Numerics/LinearAlgebra/Complex/DenseMatrix.cs
  3. 58
      src/Numerics/LinearAlgebra/Complex/Factorization/DenseSvd.cs
  4. 11
      src/Numerics/LinearAlgebra/Complex/Factorization/Svd.cs
  5. 323
      src/Numerics/LinearAlgebra/Complex/Factorization/UserSvd.cs
  6. 2
      src/Numerics/LinearAlgebra/Complex/Matrix.cs
  7. 2
      src/Numerics/LinearAlgebra/Complex32/DenseMatrix.cs
  8. 58
      src/Numerics/LinearAlgebra/Complex32/Factorization/DenseSvd.cs
  9. 11
      src/Numerics/LinearAlgebra/Complex32/Factorization/Svd.cs
  10. 326
      src/Numerics/LinearAlgebra/Complex32/Factorization/UserSvd.cs
  11. 2
      src/Numerics/LinearAlgebra/Complex32/Matrix.cs
  12. 2
      src/Numerics/LinearAlgebra/Double/DenseMatrix.cs
  13. 58
      src/Numerics/LinearAlgebra/Double/Factorization/DenseSvd.cs
  14. 11
      src/Numerics/LinearAlgebra/Double/Factorization/Svd.cs
  15. 322
      src/Numerics/LinearAlgebra/Double/Factorization/UserSvd.cs
  16. 2
      src/Numerics/LinearAlgebra/Double/Matrix.cs
  17. 96
      src/Numerics/LinearAlgebra/Factorization/Svd.cs
  18. 2
      src/Numerics/LinearAlgebra/Single/DenseMatrix.cs
  19. 58
      src/Numerics/LinearAlgebra/Single/Factorization/DenseSvd.cs
  20. 11
      src/Numerics/LinearAlgebra/Single/Factorization/Svd.cs
  21. 326
      src/Numerics/LinearAlgebra/Single/Factorization/UserSvd.cs
  22. 2
      src/Numerics/LinearAlgebra/Single/Matrix.cs
  23. 17
      src/UnitTests/LinearAlgebraTests/Complex/Factorization/SvdTests.cs
  24. 20
      src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserSvdTests.cs
  25. 17
      src/UnitTests/LinearAlgebraTests/Complex32/Factorization/SvdTests.cs
  26. 22
      src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserSvdTests.cs
  27. 17
      src/UnitTests/LinearAlgebraTests/Double/Factorization/SvdTests.cs
  28. 21
      src/UnitTests/LinearAlgebraTests/Double/Factorization/UserSvdTests.cs
  29. 17
      src/UnitTests/LinearAlgebraTests/Single/Factorization/SvdTests.cs
  30. 21
      src/UnitTests/LinearAlgebraTests/Single/Factorization/UserSvdTests.cs

7
src/Examples/LinearAlgebra/Factorization/Svd.cs

@ -26,6 +26,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Double; using MathNet.Numerics.LinearAlgebra.Double;
namespace Examples.LinearAlgebra.FactorizationExamples namespace Examples.LinearAlgebra.FactorizationExamples
@ -97,7 +98,7 @@ namespace Examples.LinearAlgebra.FactorizationExamples
// 3. Singular values as diagonal matrix // 3. Singular values as diagonal matrix
Console.WriteLine(@"3. Singular values as diagonal matrix"); Console.WriteLine(@"3. Singular values as diagonal matrix");
Console.WriteLine(svd.W().ToString("#0.00\t", formatProvider)); Console.WriteLine(svd.W.ToString("#0.00\t", formatProvider));
Console.WriteLine(); Console.WriteLine();
// 4. Right singular vectors // 4. Right singular vectors
@ -118,7 +119,7 @@ namespace Examples.LinearAlgebra.FactorizationExamples
Console.WriteLine(); Console.WriteLine();
// 7. Reconstruct initial matrix: A = U*Σ*VT // 7. Reconstruct initial matrix: A = U*Σ*VT
var reconstruct = svd.U * svd.W() * svd.VT; var reconstruct = svd.U * svd.W * svd.VT;
Console.WriteLine(@"7. Reconstruct initial matrix: A = U*S*VT"); Console.WriteLine(@"7. Reconstruct initial matrix: A = U*S*VT");
Console.WriteLine(reconstruct.ToString("#0.00\t", formatProvider)); Console.WriteLine(reconstruct.ToString("#0.00\t", formatProvider));
Console.WriteLine(); Console.WriteLine();
@ -154,7 +155,7 @@ namespace Examples.LinearAlgebra.FactorizationExamples
// 13. Singular values as diagonal matrix // 13. Singular values as diagonal matrix
Console.WriteLine(@"13. Singular values as diagonal matrix"); Console.WriteLine(@"13. Singular values as diagonal matrix");
Console.WriteLine(svd.W().ToString("#0.00\t", formatProvider)); Console.WriteLine(svd.W.ToString("#0.00\t", formatProvider));
Console.WriteLine(); Console.WriteLine();
// 14. Access to left singular vectors when partial SVD decomposition was performed // 14. Access to left singular vectors when partial SVD decomposition was performed

2
src/Numerics/LinearAlgebra/Complex/DenseMatrix.cs

@ -1031,7 +1031,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override Svd<Complex> Svd(bool computeVectors) public override Svd<Complex> Svd(bool computeVectors)
{ {
return new DenseSvd(this, computeVectors); return DenseSvd.Create(this, computeVectors);
} }
public override Evd<Complex> Evd() public override Evd<Complex> Evd()

58
src/Numerics/LinearAlgebra/Complex/Factorization/DenseSvd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,8 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.Properties;
using System; using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{ {
@ -54,7 +54,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <remarks> /// <remarks>
/// The computation of the singular value decomposition is done at construction time. /// The computation of the singular value decomposition is done at construction time.
/// </remarks> /// </remarks>
public class DenseSvd : Svd public sealed class DenseSvd : Svd
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseSvd"/> class. This object will compute the /// Initializes a new instance of the <see cref="DenseSvd"/> class. This object will compute the
@ -64,19 +64,20 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param> /// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception> /// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception>
public DenseSvd(DenseMatrix matrix, bool computeVectors) public static DenseSvd Create(DenseMatrix matrix, bool computeVectors)
{ {
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
ComputeVectors = computeVectors;
var nm = Math.Min(matrix.RowCount, matrix.ColumnCount); var nm = Math.Min(matrix.RowCount, matrix.ColumnCount);
S = new DenseVector(nm); var s = new DenseVector(nm);
U = new DenseMatrix(matrix.RowCount); var u = new DenseMatrix(matrix.RowCount);
VT = new DenseMatrix(matrix.ColumnCount); var vt = new DenseMatrix(matrix.ColumnCount);
Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Values, matrix.RowCount, matrix.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values); Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix) matrix.Clone()).Values, matrix.RowCount, matrix.ColumnCount, s.Values, u.Values, vt.Values);
return new DenseSvd(s, u, vt, computeVectors);
}
DenseSvd(Vector<Complex> s, Matrix<Complex> u, Matrix<Complex> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
} }
/// <summary> /// <summary>
@ -86,18 +87,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
public override void Solve(Matrix<Complex> input, Matrix<Complex> result) public override void Solve(Matrix<Complex> input, Matrix<Complex> result)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -132,7 +122,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values, dinput.Values, input.ColumnCount, dresult.Values); Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector) S).Values, ((DenseMatrix) U).Values, ((DenseMatrix) VT).Values, dinput.Values, input.ColumnCount, dresult.Values);
} }
/// <summary> /// <summary>
@ -142,17 +132,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
public override void Solve(Vector<Complex> input, Vector<Complex> result) public override void Solve(Vector<Complex> input, Vector<Complex> result)
{ {
if (input == null) if (!VectorsComputed)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -182,7 +162,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values, dinput.Values, 1, dresult.Values); Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector) S).Values, ((DenseMatrix) U).Values, ((DenseMatrix) VT).Values, dinput.Values, 1, dresult.Values);
} }
} }
} }

11
src/Numerics/LinearAlgebra/Complex/Factorization/Svd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,10 +28,10 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
using System; using System;
using System.Linq; using System.Linq;
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{ {
@ -58,6 +58,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// </remarks> /// </remarks>
public abstract class Svd : Svd<Complex> public abstract class Svd : Svd<Complex>
{ {
protected Svd(Vector<Complex> s, Matrix<Complex> u, Matrix<Complex> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
}
/// <summary> /// <summary>
/// Gets the effective numerical matrix rank. /// Gets the effective numerical matrix rank.
/// </summary> /// </summary>

323
src/Numerics/LinearAlgebra/Complex/Factorization/UserSvd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,8 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.Properties;
using System; using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{ {
@ -38,6 +38,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
using Numerics; using Numerics;
#else #else
using System.Numerics; using System.Numerics;
#endif #endif
/// <summary> /// <summary>
@ -54,7 +55,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <remarks> /// <remarks>
/// The computation of the singular value decomposition is done at construction time. /// The computation of the singular value decomposition is done at construction time.
/// </remarks> /// </remarks>
public class UserSvd : Svd public sealed class UserSvd : Svd
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the /// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the
@ -64,20 +65,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param> /// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="NonConvergenceException"></exception> /// <exception cref="NonConvergenceException"></exception>
public UserSvd(Matrix<Complex> matrix, bool computeVectors) public static UserSvd Create(Matrix<Complex> matrix, bool computeVectors)
{ {
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
ComputeVectors = computeVectors;
var nm = Math.Min(matrix.RowCount + 1, matrix.ColumnCount); var nm = Math.Min(matrix.RowCount + 1, matrix.ColumnCount);
var matrixCopy = matrix.Clone(); var matrixCopy = matrix.Clone();
S = matrixCopy.CreateVector(nm); var s = matrixCopy.CreateVector(nm);
U = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount); var u = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount);
VT = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount); var vt = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount);
const int maxiter = 1000; const int maxiter = 1000;
var e = new Complex[matrixCopy.ColumnCount]; var e = new Complex[matrixCopy.ColumnCount];
@ -100,34 +95,34 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
if (l < nct) if (l < nct)
{ {
// Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l]. // Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l].
S[l] = Cnrm2Column(matrixCopy, matrixCopy.RowCount, l, l); s[l] = Cnrm2Column(matrixCopy, matrixCopy.RowCount, l, l);
if (S[l].Magnitude != 0.0) if (s[l].Magnitude != 0.0)
{ {
if (matrixCopy.At(l, l).Magnitude != 0.0) if (matrixCopy.At(l, l).Magnitude != 0.0)
{ {
S[l] = Csign(S[l], matrixCopy.At(l, l)); s[l] = Csign(s[l], matrixCopy.At(l, l));
} }
CscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0 / S[l]); CscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0/s[l]);
matrixCopy.At(l, l, (Complex.One + matrixCopy.At(l, l))); matrixCopy.At(l, l, (Complex.One + matrixCopy.At(l, l)));
} }
S[l] = -S[l]; s[l] = -s[l];
} }
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
if (l < nct) if (l < nct)
{ {
if (S[l].Magnitude != 0.0) if (s[l].Magnitude != 0.0)
{ {
// Apply the transformation. // Apply the transformation.
t = -Cdotc(matrixCopy, matrixCopy.RowCount, l, j, l) / matrixCopy.At(l, l); t = -Cdotc(matrixCopy, matrixCopy.RowCount, l, j, l)/matrixCopy.At(l, l);
if (t != Complex.Zero) if (t != Complex.Zero)
{ {
for (var ii = l; ii < matrixCopy.RowCount; ii++) for (var ii = l; ii < matrixCopy.RowCount; ii++)
{ {
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t * matrixCopy.At(ii, l))); matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t*matrixCopy.At(ii, l)));
} }
} }
} }
@ -138,12 +133,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
e[j] = matrixCopy.At(l, j).Conjugate(); e[j] = matrixCopy.At(l, j).Conjugate();
} }
if (ComputeVectors && l < nct) if (computeVectors && l < nct)
{ {
// Place the transformation in u for subsequent back multiplication. // Place the transformation in u for subsequent back multiplication.
for (i = l; i < matrixCopy.RowCount; i++) for (i = l; i < matrixCopy.RowCount; i++)
{ {
U.At(i, l, matrixCopy.At(i, l)); u.At(i, l, matrixCopy.At(i, l));
} }
} }
@ -162,7 +157,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
e[l] = Csign(e[l], e[lp1]); e[l] = Csign(e[l], e[lp1]);
} }
CscalVector(e, lp1, 1.0 / e[l]); CscalVector(e, lp1, 1.0/e[l]);
e[lp1] = Complex.One + e[lp1]; e[lp1] = Complex.One + e[lp1];
} }
@ -181,30 +176,30 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{ {
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
{ {
work[ii] += e[j] * matrixCopy.At(ii, j); work[ii] += e[j]*matrixCopy.At(ii, j);
} }
} }
} }
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
var ww = (-e[j] / e[lp1]).Conjugate(); var ww = (-e[j]/e[lp1]).Conjugate();
if (ww != Complex.Zero) if (ww != Complex.Zero)
{ {
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
{ {
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww * work[ii])); matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww*work[ii]));
} }
} }
} }
} }
if (ComputeVectors) if (computeVectors)
{ {
// Place the transformation in v for subsequent back multiplication. // Place the transformation in v for subsequent back multiplication.
for (i = lp1; i < matrixCopy.ColumnCount; i++) for (i = lp1; i < matrixCopy.ColumnCount; i++)
{ {
VT.At(i, l, e[i]); vt.At(i, l, e[i]);
} }
} }
} }
@ -215,12 +210,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
var nrtp1 = nrt + 1; var nrtp1 = nrt + 1;
if (nct < matrixCopy.ColumnCount) if (nct < matrixCopy.ColumnCount)
{ {
S[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1)); s[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1));
} }
if (matrixCopy.RowCount < m) if (matrixCopy.RowCount < m)
{ {
S[m - 1] = Complex.Zero; s[m - 1] = Complex.Zero;
} }
if (nrtp1 < m) if (nrtp1 < m)
@ -231,55 +226,55 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
e[m - 1] = Complex.Zero; e[m - 1] = Complex.Zero;
// If required, generate u. // If required, generate u.
if (ComputeVectors) if (computeVectors)
{ {
for (j = nctp1 - 1; j < ncu; j++) for (j = nctp1 - 1; j < ncu; j++)
{ {
for (i = 0; i < matrixCopy.RowCount; i++) for (i = 0; i < matrixCopy.RowCount; i++)
{ {
U.At(i, j, Complex.Zero); u.At(i, j, Complex.Zero);
} }
U.At(j, j, Complex.One); u.At(j, j, Complex.One);
} }
for (l = nct - 1; l >= 0; l--) for (l = nct - 1; l >= 0; l--)
{ {
if (S[l].Magnitude != 0.0) if (s[l].Magnitude != 0.0)
{ {
for (j = l + 1; j < ncu; j++) for (j = l + 1; j < ncu; j++)
{ {
t = -Cdotc(U, matrixCopy.RowCount, l, j, l) / U.At(l, l); t = -Cdotc(u, matrixCopy.RowCount, l, j, l)/u.At(l, l);
if (t != Complex.Zero) if (t != Complex.Zero)
{ {
for (var ii = l; ii < matrixCopy.RowCount; ii++) for (var ii = l; ii < matrixCopy.RowCount; ii++)
{ {
U.At(ii, j, U.At(ii, j) + (t * U.At(ii, l))); u.At(ii, j, u.At(ii, j) + (t*u.At(ii, l)));
} }
} }
} }
CscalColumn(U, matrixCopy.RowCount, l, l, -1.0); CscalColumn(u, matrixCopy.RowCount, l, l, -1.0);
U.At(l, l, Complex.One + U.At(l, l)); u.At(l, l, Complex.One + u.At(l, l));
for (i = 0; i < l; i++) for (i = 0; i < l; i++)
{ {
U.At(i, l, Complex.Zero); u.At(i, l, Complex.Zero);
} }
} }
else else
{ {
for (i = 0; i < matrixCopy.RowCount; i++) for (i = 0; i < matrixCopy.RowCount; i++)
{ {
U.At(i, l, Complex.Zero); u.At(i, l, Complex.Zero);
} }
U.At(l, l, Complex.One); u.At(l, l, Complex.One);
} }
} }
} }
// If it is required, generate v. // If it is required, generate v.
if (ComputeVectors) if (computeVectors)
{ {
for (l = matrixCopy.ColumnCount - 1; l >= 0; l--) for (l = matrixCopy.ColumnCount - 1; l >= 0; l--)
{ {
@ -290,12 +285,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{ {
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
t = -Cdotc(VT, matrixCopy.ColumnCount, l, j, lp1) / VT.At(lp1, l); t = -Cdotc(vt, matrixCopy.ColumnCount, l, j, lp1)/vt.At(lp1, l);
if (t != Complex.Zero) if (t != Complex.Zero)
{ {
for (var ii = l; ii < matrixCopy.ColumnCount; ii++) for (var ii = l; ii < matrixCopy.ColumnCount; ii++)
{ {
VT.At(ii, j, VT.At(ii, j) + (t * VT.At(ii, l))); vt.At(ii, j, vt.At(ii, j) + (t*vt.At(ii, l)));
} }
} }
} }
@ -304,10 +299,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
for (i = 0; i < matrixCopy.ColumnCount; i++) for (i = 0; i < matrixCopy.ColumnCount; i++)
{ {
VT.At(i, l, Complex.Zero); vt.At(i, l, Complex.Zero);
} }
VT.At(l, l, Complex.One); vt.At(l, l, Complex.One);
} }
} }
@ -315,19 +310,19 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
for (i = 0; i < m; i++) for (i = 0; i < m; i++)
{ {
Complex r; Complex r;
if (S[i].Magnitude != 0.0) if (s[i].Magnitude != 0.0)
{ {
t = S[i].Magnitude; t = s[i].Magnitude;
r = S[i] / t; r = s[i]/t;
S[i] = t; s[i] = t;
if (i < m - 1) if (i < m - 1)
{ {
e[i] = e[i] / r; e[i] = e[i]/r;
} }
if (ComputeVectors) if (computeVectors)
{ {
CscalColumn(U, matrixCopy.RowCount, i, 0, r); CscalColumn(u, matrixCopy.RowCount, i, 0, r);
} }
} }
@ -340,12 +335,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
if (e[i].Magnitude != 0.0) if (e[i].Magnitude != 0.0)
{ {
t = e[i].Magnitude; t = e[i].Magnitude;
r = t / e[i]; r = t/e[i];
e[i] = t; e[i] = t;
S[i + 1] = S[i + 1] * r; s[i + 1] = s[i + 1]*r;
if (ComputeVectors) if (computeVectors)
{ {
CscalColumn(VT, matrixCopy.ColumnCount, i + 1, 0, r); CscalColumn(vt, matrixCopy.ColumnCount, i + 1, 0, r);
} }
} }
} }
@ -373,7 +368,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
double test; double test;
for (l = m - 2; l >= 0; l--) for (l = m - 2; l >= 0; l--)
{ {
test = S[l].Magnitude + S[l + 1].Magnitude; test = s[l].Magnitude + s[l + 1].Magnitude;
ztest = test + e[l].Magnitude; ztest = test + e[l].Magnitude;
if (ztest.AlmostEqualInDecimalPlaces(test, 15)) if (ztest.AlmostEqualInDecimalPlaces(test, 15))
{ {
@ -403,10 +398,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
test = test + e[ls - 1].Magnitude; test = test + e[ls - 1].Magnitude;
} }
ztest = test + S[ls].Magnitude; ztest = test + s[ls].Magnitude;
if (ztest.AlmostEqualInDecimalPlaces(test, 15)) if (ztest.AlmostEqualInDecimalPlaces(test, 15))
{ {
S[ls] = Complex.Zero; s[ls] = Complex.Zero;
break; break;
} }
} }
@ -435,7 +430,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
double sn; double sn;
switch (kase) switch (kase)
{ {
// Deflate negligible VectorS[m]. // Deflate negligible VectorS[m].
case 1: case 1:
f = e[m - 2].Real; f = e[m - 2].Real;
e[m - 2] = Complex.Zero; e[m - 2] = Complex.Zero;
@ -443,73 +438,73 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
for (var kk = l; kk < m - 1; kk++) for (var kk = l; kk < m - 1; kk++)
{ {
k = m - 2 - kk + l; k = m - 2 - kk + l;
t1 = S[k].Real; t1 = s[k].Real;
Srotg(ref t1, ref f, out cs, out sn); Srotg(ref t1, ref f, out cs, out sn);
S[k] = t1; s[k] = t1;
if (k != l) if (k != l)
{ {
f = -sn * e[k - 1].Real; f = -sn*e[k - 1].Real;
e[k - 1] = cs * e[k - 1]; e[k - 1] = cs*e[k - 1];
} }
if (ComputeVectors) if (computeVectors)
{ {
Csrot(VT, matrixCopy.ColumnCount, k, m - 1, cs, sn); Csrot(vt, matrixCopy.ColumnCount, k, m - 1, cs, sn);
} }
} }
break; break;
// Split at negligible VectorS[l]. // Split at negligible VectorS[l].
case 2: case 2:
f = e[l - 1].Real; f = e[l - 1].Real;
e[l - 1] = Complex.Zero; e[l - 1] = Complex.Zero;
for (k = l; k < m; k++) for (k = l; k < m; k++)
{ {
t1 = S[k].Real; t1 = s[k].Real;
Srotg(ref t1, ref f, out cs, out sn); Srotg(ref t1, ref f, out cs, out sn);
S[k] = t1; s[k] = t1;
f = -sn * e[k].Real; f = -sn*e[k].Real;
e[k] = cs * e[k]; e[k] = cs*e[k];
if (ComputeVectors) if (computeVectors)
{ {
Csrot(U, matrixCopy.RowCount, k, l - 1, cs, sn); Csrot(u, matrixCopy.RowCount, k, l - 1, cs, sn);
} }
} }
break; break;
// Perform one qr step. // Perform one qr step.
case 3: case 3:
// Calculate the shift. // Calculate the shift.
var scale = 0.0; var scale = 0.0;
scale = Math.Max(scale, S[m - 1].Magnitude); scale = Math.Max(scale, s[m - 1].Magnitude);
scale = Math.Max(scale, S[m - 2].Magnitude); scale = Math.Max(scale, s[m - 2].Magnitude);
scale = Math.Max(scale, e[m - 2].Magnitude); scale = Math.Max(scale, e[m - 2].Magnitude);
scale = Math.Max(scale, S[l].Magnitude); scale = Math.Max(scale, s[l].Magnitude);
scale = Math.Max(scale, e[l].Magnitude); scale = Math.Max(scale, e[l].Magnitude);
var sm = S[m - 1].Real / scale; var sm = s[m - 1].Real/scale;
var smm1 = S[m - 2].Real / scale; var smm1 = s[m - 2].Real/scale;
var emm1 = e[m - 2].Real / scale; var emm1 = e[m - 2].Real/scale;
var sl = S[l].Real / scale; var sl = s[l].Real/scale;
var el = e[l].Real / scale; var el = e[l].Real/scale;
var b = (((smm1 + sm) * (smm1 - sm)) + (emm1 * emm1)) / 2.0; var b = (((smm1 + sm)*(smm1 - sm)) + (emm1*emm1))/2.0;
var c = (sm * emm1) * (sm * emm1); var c = (sm*emm1)*(sm*emm1);
var shift = 0.0; var shift = 0.0;
if (b != 0.0 || c != 0.0) if (b != 0.0 || c != 0.0)
{ {
shift = Math.Sqrt((b * b) + c); shift = Math.Sqrt((b*b) + c);
if (b < 0.0) if (b < 0.0)
{ {
shift = -shift; shift = -shift;
} }
shift = c / (b + shift); shift = c/(b + shift);
} }
f = ((sl + sm) * (sl - sm)) + shift; f = ((sl + sm)*(sl - sm)) + shift;
var g = sl * el; var g = sl*el;
// Chase zeros. // Chase zeros.
for (k = l; k < m - 1; k++) for (k = l; k < m - 1; k++)
@ -520,24 +515,24 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
e[k - 1] = f; e[k - 1] = f;
} }
f = (cs * S[k].Real) + (sn * e[k].Real); f = (cs*s[k].Real) + (sn*e[k].Real);
e[k] = (cs * e[k]) - (sn * S[k]); e[k] = (cs*e[k]) - (sn*s[k]);
g = sn * S[k + 1].Real; g = sn*s[k + 1].Real;
S[k + 1] = cs * S[k + 1]; s[k + 1] = cs*s[k + 1];
if (ComputeVectors) if (computeVectors)
{ {
Csrot(VT, matrixCopy.ColumnCount, k, k + 1, cs, sn); Csrot(vt, matrixCopy.ColumnCount, k, k + 1, cs, sn);
} }
Srotg(ref f, ref g, out cs, out sn); Srotg(ref f, ref g, out cs, out sn);
S[k] = f; s[k] = f;
f = (cs * e[k].Real) + (sn * S[k + 1].Real); f = (cs*e[k].Real) + (sn*s[k + 1].Real);
S[k + 1] = (-sn * e[k]) + (cs * S[k + 1]); s[k + 1] = (-sn*e[k]) + (cs*s[k + 1]);
g = sn * e[k + 1].Real; g = sn*e[k + 1].Real;
e[k + 1] = cs * e[k + 1]; e[k + 1] = cs*e[k + 1];
if (ComputeVectors && k < matrixCopy.RowCount) if (computeVectors && k < matrixCopy.RowCount)
{ {
Csrot(U, matrixCopy.RowCount, k, k + 1, cs, sn); Csrot(u, matrixCopy.RowCount, k, k + 1, cs, sn);
} }
} }
@ -545,37 +540,37 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
iter = iter + 1; iter = iter + 1;
break; break;
// Convergence. // Convergence.
case 4: case 4:
// Make the singular value positive // Make the singular value positive
if (S[l].Real < 0.0) if (s[l].Real < 0.0)
{ {
S[l] = -S[l]; s[l] = -s[l];
if (ComputeVectors) if (computeVectors)
{ {
CscalColumn(VT, matrixCopy.ColumnCount, l, 0, -1.0); CscalColumn(vt, matrixCopy.ColumnCount, l, 0, -1.0);
} }
} }
// Order the singular value. // Order the singular value.
while (l != mn - 1) while (l != mn - 1)
{ {
if (S[l].Real >= S[l + 1].Real) if (s[l].Real >= s[l + 1].Real)
{ {
break; break;
} }
t = S[l]; t = s[l];
S[l] = S[l + 1]; s[l] = s[l + 1];
S[l + 1] = t; s[l + 1] = t;
if (ComputeVectors && l < matrixCopy.ColumnCount) if (computeVectors && l < matrixCopy.ColumnCount)
{ {
Swap(VT, matrixCopy.ColumnCount, l, l + 1); Swap(vt, matrixCopy.ColumnCount, l, l + 1);
} }
if (ComputeVectors && l < matrixCopy.RowCount) if (computeVectors && l < matrixCopy.RowCount)
{ {
Swap(U, matrixCopy.RowCount, l, l + 1); Swap(u, matrixCopy.RowCount, l, l + 1);
} }
l = l + 1; l = l + 1;
@ -587,9 +582,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
} }
} }
if (ComputeVectors) if (computeVectors)
{ {
VT = VT.ConjugateTranspose(); vt = vt.ConjugateTranspose();
} }
// Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses // Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses
@ -601,11 +596,18 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
var tmp = matrixCopy.CreateVector(nm); var tmp = matrixCopy.CreateVector(nm);
for (i = 0; i < nm; i++) for (i = 0; i < nm; i++)
{ {
tmp[i] = S[i]; tmp[i] = s[i];
} }
S = tmp; s = tmp;
} }
return new UserSvd(s, u, vt, computeVectors);
}
UserSvd(Vector<Complex> s, Matrix<Complex> u, Matrix<Complex> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
} }
/// <summary> /// <summary>
@ -614,9 +616,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="z1">Complex value z1</param> /// <param name="z1">Complex value z1</param>
/// <param name="z2">Complex value z2</param> /// <param name="z2">Complex value z2</param>
/// <returns>Result multiplication of signum function and absolute value</returns> /// <returns>Result multiplication of signum function and absolute value</returns>
private static Complex Csign(Complex z1, Complex z2) static Complex Csign(Complex z1, Complex z2)
{ {
return z1.Magnitude * (z2 / z2.Magnitude); return z1.Magnitude*(z2/z2.Magnitude);
} }
/// <summary> /// <summary>
@ -626,7 +628,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="rowCount">The number of rows in <paramref name="a"/></param> /// <param name="rowCount">The number of rows in <paramref name="a"/></param>
/// <param name="columnA">Column A index to swap</param> /// <param name="columnA">Column A index to swap</param>
/// <param name="columnB">Column B index to swap</param> /// <param name="columnB">Column B index to swap</param>
private static void Swap(Matrix<Complex> a, int rowCount, int columnA, int columnB) static void Swap(Matrix<Complex> a, int rowCount, int columnA, int columnB)
{ {
for (var i = 0; i < rowCount; i++) for (var i = 0; i < rowCount; i++)
{ {
@ -644,11 +646,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="column">Column to scale</param> /// <param name="column">Column to scale</param>
/// <param name="rowStart">Row to scale from</param> /// <param name="rowStart">Row to scale from</param>
/// <param name="z">Scale value</param> /// <param name="z">Scale value</param>
private static void CscalColumn(Matrix<Complex> a, int rowCount, int column, int rowStart, Complex z) static void CscalColumn(Matrix<Complex> a, int rowCount, int column, int rowStart, Complex z)
{ {
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
a.At(i, column, a.At(i, column) * z); a.At(i, column, a.At(i, column)*z);
} }
} }
@ -658,11 +660,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="a">Source vector</param> /// <param name="a">Source vector</param>
/// <param name="start">Row to scale from</param> /// <param name="start">Row to scale from</param>
/// <param name="z">Scale value</param> /// <param name="z">Scale value</param>
private static void CscalVector(Complex[] a, int start, Complex z) static void CscalVector(Complex[] a, int start, Complex z)
{ {
for (var i = start; i < a.Length; i++) for (var i = start; i < a.Length; i++)
{ {
a[i] = a[i] * z; a[i] = a[i]*z;
} }
} }
@ -675,7 +677,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="c">Contains the parameter c associated with the Givens rotation</param> /// <param name="c">Contains the parameter c associated with the Givens rotation</param>
/// <param name="s">Contains the parameter s associated with the Givens rotation</param> /// <param name="s">Contains the parameter s associated with the Givens rotation</param>
/// <remarks>This is equivalent to the DROTG LAPACK routine.</remarks> /// <remarks>This is equivalent to the DROTG LAPACK routine.</remarks>
private static void Srotg(ref double da, ref double db, out double c, out double s) static void Srotg(ref double da, ref double db, out double c, out double s)
{ {
double r, z; double r, z;
@ -697,16 +699,16 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
} }
else else
{ {
var sda = da / scale; var sda = da/scale;
var sdb = db / scale; var sdb = db/scale;
r = scale * Math.Sqrt((sda * sda) + (sdb * sdb)); r = scale*Math.Sqrt((sda*sda) + (sdb*sdb));
if (roe < 0.0) if (roe < 0.0)
{ {
r = -r; r = -r;
} }
c = da / r; c = da/r;
s = db / r; s = db/r;
z = 1.0; z = 1.0;
if (absda > absdb) if (absda > absdb)
{ {
@ -715,7 +717,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
if (absdb >= absda && c != 0.0) if (absdb >= absda && c != 0.0)
{ {
z = 1.0 / c; z = 1.0/c;
} }
} }
@ -731,12 +733,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="column">Column index</param> /// <param name="column">Column index</param>
/// <param name="rowStart">Start row index</param> /// <param name="rowStart">Start row index</param>
/// <returns>Norm2 (Euclidean norm) of the column</returns> /// <returns>Norm2 (Euclidean norm) of the column</returns>
private static double Cnrm2Column(Matrix<Complex> a, int rowCount, int column, int rowStart) static double Cnrm2Column(Matrix<Complex> a, int rowCount, int column, int rowStart)
{ {
var s = 0.0; var s = 0.0;
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
s += a.At(i, column).Magnitude * a.At(i, column).Magnitude; s += a.At(i, column).Magnitude*a.At(i, column).Magnitude;
} }
return Math.Sqrt(s); return Math.Sqrt(s);
@ -748,12 +750,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="a">Source vector</param> /// <param name="a">Source vector</param>
/// <param name="rowStart">Start index</param> /// <param name="rowStart">Start index</param>
/// <returns>Norm2 (Euclidean norm) of the vector</returns> /// <returns>Norm2 (Euclidean norm) of the vector</returns>
private static double Cnrm2Vector(Complex[] a, int rowStart) static double Cnrm2Vector(Complex[] a, int rowStart)
{ {
var s = 0.0; var s = 0.0;
for (var i = rowStart; i < a.Length; i++) for (var i = rowStart; i < a.Length; i++)
{ {
s += a[i].Magnitude * a[i].Magnitude; s += a[i].Magnitude*a[i].Magnitude;
} }
return Math.Sqrt(s); return Math.Sqrt(s);
@ -768,12 +770,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="columnB">Index of column B</param> /// <param name="columnB">Index of column B</param>
/// <param name="rowStart">Starting row index</param> /// <param name="rowStart">Starting row index</param>
/// <returns>Dot product value</returns> /// <returns>Dot product value</returns>
private static Complex Cdotc(Matrix<Complex> a, int rowCount, int columnA, int columnB, int rowStart) static Complex Cdotc(Matrix<Complex> a, int rowCount, int columnA, int columnB, int rowStart)
{ {
var z = Complex.Zero; var z = Complex.Zero;
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
z += a.At(i, columnA).Conjugate() * a.At(i, columnB); z += a.At(i, columnA).Conjugate()*a.At(i, columnB);
} }
return z; return z;
@ -789,17 +791,17 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="columnB">Index of column B</param> /// <param name="columnB">Index of column B</param>
/// <param name="c">scalar cos value</param> /// <param name="c">scalar cos value</param>
/// <param name="s">scalar sin value</param> /// <param name="s">scalar sin value</param>
private static void Csrot(Matrix<Complex> a, int rowCount, int columnA, int columnB, double c, double s) static void Csrot(Matrix<Complex> a, int rowCount, int columnA, int columnB, double c, double s)
{ {
for (var i = 0; i < rowCount; i++) for (var i = 0; i < rowCount; i++)
{ {
var z = (c * a.At(i, columnA)) + (s * a.At(i, columnB)); var z = (c*a.At(i, columnA)) + (s*a.At(i, columnB));
var tmp = (c * a.At(i, columnB)) - (s * a.At(i, columnA)); var tmp = (c*a.At(i, columnB)) - (s*a.At(i, columnA));
a.At(i, columnB, tmp); a.At(i, columnB, tmp);
a.At(i, columnA, z); a.At(i, columnA, z);
} }
} }
/// <summary> /// <summary>
/// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized. /// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized.
/// </summary> /// </summary>
@ -807,18 +809,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
public override void Solve(Matrix<Complex> input, Matrix<Complex> result) public override void Solve(Matrix<Complex> input, Matrix<Complex> result)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -855,7 +846,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{ {
for (var i = 0; i < U.RowCount; i++) for (var i = 0; i < U.RowCount; i++)
{ {
value += U.At(i, j).Conjugate() * input.At(i, k); value += U.At(i, j).Conjugate()*input.At(i, k);
} }
value /= S[j]; value /= S[j];
@ -869,7 +860,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
var value = Complex.Zero; var value = Complex.Zero;
for (var i = 0; i < VT.ColumnCount; i++) for (var i = 0; i < VT.ColumnCount; i++)
{ {
value += VT.At(i, j).Conjugate() * tmp[i]; value += VT.At(i, j).Conjugate()*tmp[i];
} }
result.At(j, k, value); result.At(j, k, value);
@ -884,17 +875,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
public override void Solve(Vector<Complex> input, Vector<Complex> result) public override void Solve(Vector<Complex> input, Vector<Complex> result)
{ {
if (input == null) if (!VectorsComputed)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -921,7 +902,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{ {
for (var i = 0; i < U.RowCount; i++) for (var i = 0; i < U.RowCount; i++)
{ {
value += U.At(i, j).Conjugate() * input[i]; value += U.At(i, j).Conjugate()*input[i];
} }
value /= S[j]; value /= S[j];
@ -935,7 +916,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
var value = Complex.Zero; var value = Complex.Zero;
for (var i = 0; i < VT.ColumnCount; i++) for (var i = 0; i < VT.ColumnCount; i++)
{ {
value += VT.At(i, j).Conjugate() * tmp[i]; value += VT.At(i, j).Conjugate()*tmp[i];
} }
result[j] = value; result[j] = value;

2
src/Numerics/LinearAlgebra/Complex/Matrix.cs

@ -480,7 +480,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override Svd<Complex> Svd(bool computeVectors) public override Svd<Complex> Svd(bool computeVectors)
{ {
return new UserSvd(this, computeVectors); return UserSvd.Create(this, computeVectors);
} }
public override Evd<Complex> Evd() public override Evd<Complex> Evd()

2
src/Numerics/LinearAlgebra/Complex32/DenseMatrix.cs

@ -1026,7 +1026,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override Svd<Complex32> Svd(bool computeVectors) public override Svd<Complex32> Svd(bool computeVectors)
{ {
return new DenseSvd(this, computeVectors); return DenseSvd.Create(this, computeVectors);
} }
public override Evd<Complex32> Evd() public override Evd<Complex32> Evd()

58
src/Numerics/LinearAlgebra/Complex32/Factorization/DenseSvd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,8 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.Properties;
using System; using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{ {
@ -49,7 +49,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <remarks> /// <remarks>
/// The computation of the singular value decomposition is done at construction time. /// The computation of the singular value decomposition is done at construction time.
/// </remarks> /// </remarks>
public class DenseSvd : Svd public sealed class DenseSvd : Svd
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseSvd"/> class. This object will compute the /// Initializes a new instance of the <see cref="DenseSvd"/> class. This object will compute the
@ -59,19 +59,20 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param> /// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception> /// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception>
public DenseSvd(DenseMatrix matrix, bool computeVectors) public static DenseSvd Create(DenseMatrix matrix, bool computeVectors)
{ {
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
ComputeVectors = computeVectors;
var nm = Math.Min(matrix.RowCount, matrix.ColumnCount); var nm = Math.Min(matrix.RowCount, matrix.ColumnCount);
S = new DenseVector(nm); var s = new DenseVector(nm);
U = new DenseMatrix(matrix.RowCount); var u = new DenseMatrix(matrix.RowCount);
VT = new DenseMatrix(matrix.ColumnCount); var vt = new DenseMatrix(matrix.ColumnCount);
Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Values, matrix.RowCount, matrix.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values); Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix) matrix.Clone()).Values, matrix.RowCount, matrix.ColumnCount, s.Values, u.Values, vt.Values);
return new DenseSvd(s, u, vt, computeVectors);
}
DenseSvd(Vector<Complex32> s, Matrix<Complex32> u, Matrix<Complex32> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
} }
/// <summary> /// <summary>
@ -81,18 +82,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
public override void Solve(Matrix<Complex32> input, Matrix<Complex32> result) public override void Solve(Matrix<Complex32> input, Matrix<Complex32> result)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -127,7 +117,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values, dinput.Values, input.ColumnCount, dresult.Values); Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector) S).Values, ((DenseMatrix) U).Values, ((DenseMatrix) VT).Values, dinput.Values, input.ColumnCount, dresult.Values);
} }
/// <summary> /// <summary>
@ -137,17 +127,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
public override void Solve(Vector<Complex32> input, Vector<Complex32> result) public override void Solve(Vector<Complex32> input, Vector<Complex32> result)
{ {
if (input == null) if (!VectorsComputed)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -177,7 +157,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values, dinput.Values, 1, dresult.Values); Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector) S).Values, ((DenseMatrix) U).Values, ((DenseMatrix) VT).Values, dinput.Values, 1, dresult.Values);
} }
} }
} }

11
src/Numerics/LinearAlgebra/Complex32/Factorization/Svd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,10 +28,10 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
using System; using System;
using System.Linq; using System.Linq;
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{ {
@ -53,6 +53,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// </remarks> /// </remarks>
public abstract class Svd : Svd<Complex32> public abstract class Svd : Svd<Complex32>
{ {
protected Svd(Vector<Complex32> s, Matrix<Complex32> u, Matrix<Complex32> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
}
/// <summary> /// <summary>
/// Gets the effective numerical matrix rank. /// Gets the effective numerical matrix rank.
/// </summary> /// </summary>

326
src/Numerics/LinearAlgebra/Complex32/Factorization/UserSvd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,8 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.Properties;
using System; using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{ {
@ -49,7 +49,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <remarks> /// <remarks>
/// The computation of the singular value decomposition is done at construction time. /// The computation of the singular value decomposition is done at construction time.
/// </remarks> /// </remarks>
public class UserSvd : Svd public sealed class UserSvd : Svd
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the /// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the
@ -59,20 +59,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param> /// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="NonConvergenceException"></exception> /// <exception cref="NonConvergenceException"></exception>
public UserSvd(Matrix<Complex32> matrix, bool computeVectors) public static UserSvd Create(Matrix<Complex32> matrix, bool computeVectors)
{ {
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
ComputeVectors = computeVectors;
var nm = Math.Min(matrix.RowCount + 1, matrix.ColumnCount); var nm = Math.Min(matrix.RowCount + 1, matrix.ColumnCount);
var matrixCopy = matrix.Clone(); var matrixCopy = matrix.Clone();
S = matrixCopy.CreateVector(nm); var s = matrixCopy.CreateVector(nm);
U = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount); var u = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount);
VT = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount); var vt = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount);
const int maxiter = 1000; const int maxiter = 1000;
var e = new Complex32[matrixCopy.ColumnCount]; var e = new Complex32[matrixCopy.ColumnCount];
@ -95,34 +89,34 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
if (l < nct) if (l < nct)
{ {
// Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l]. // Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l].
S[l] = Cnrm2Column(matrixCopy, matrixCopy.RowCount, l, l); s[l] = Cnrm2Column(matrixCopy, matrixCopy.RowCount, l, l);
if (S[l].Magnitude != 0.0f) if (s[l].Magnitude != 0.0f)
{ {
if (matrixCopy.At(l, l).Magnitude != 0.0f) if (matrixCopy.At(l, l).Magnitude != 0.0f)
{ {
S[l] = Csign(S[l], matrixCopy.At(l, l)); s[l] = Csign(s[l], matrixCopy.At(l, l));
} }
CscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0f / S[l]); CscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0f/s[l]);
matrixCopy.At(l, l, (Complex32.One + matrixCopy.At(l, l))); matrixCopy.At(l, l, (Complex32.One + matrixCopy.At(l, l)));
} }
S[l] = -S[l]; s[l] = -s[l];
} }
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
if (l < nct) if (l < nct)
{ {
if (S[l].Magnitude != 0.0f) if (s[l].Magnitude != 0.0f)
{ {
// Apply the transformation. // Apply the transformation.
t = -Cdotc(matrixCopy, matrixCopy.RowCount, l, j, l) / matrixCopy.At(l, l); t = -Cdotc(matrixCopy, matrixCopy.RowCount, l, j, l)/matrixCopy.At(l, l);
if (t != Complex32.Zero) if (t != Complex32.Zero)
{ {
for (var ii = l; ii < matrixCopy.RowCount; ii++) for (var ii = l; ii < matrixCopy.RowCount; ii++)
{ {
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t * matrixCopy.At(ii, l))); matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t*matrixCopy.At(ii, l)));
} }
} }
} }
@ -133,12 +127,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
e[j] = matrixCopy.At(l, j).Conjugate(); e[j] = matrixCopy.At(l, j).Conjugate();
} }
if (ComputeVectors && l < nct) if (computeVectors && l < nct)
{ {
// Place the transformation in u for subsequent back multiplication. // Place the transformation in u for subsequent back multiplication.
for (i = l; i < matrixCopy.RowCount; i++) for (i = l; i < matrixCopy.RowCount; i++)
{ {
U.At(i, l, matrixCopy.At(i, l)); u.At(i, l, matrixCopy.At(i, l));
} }
} }
@ -157,7 +151,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
e[l] = Csign(e[l], e[lp1]); e[l] = Csign(e[l], e[lp1]);
} }
CscalVector(e, lp1, 1.0f / e[l]); CscalVector(e, lp1, 1.0f/e[l]);
e[lp1] = Complex32.One + e[lp1]; e[lp1] = Complex32.One + e[lp1];
} }
@ -176,30 +170,30 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{ {
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
{ {
work[ii] += e[j] * matrixCopy.At(ii, j); work[ii] += e[j]*matrixCopy.At(ii, j);
} }
} }
} }
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
var ww = (-e[j] / e[lp1]).Conjugate(); var ww = (-e[j]/e[lp1]).Conjugate();
if (ww != Complex32.Zero) if (ww != Complex32.Zero)
{ {
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
{ {
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww * work[ii])); matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww*work[ii]));
} }
} }
} }
} }
if (ComputeVectors) if (computeVectors)
{ {
// Place the transformation in v for subsequent back multiplication. // Place the transformation in v for subsequent back multiplication.
for (i = lp1; i < matrixCopy.ColumnCount; i++) for (i = lp1; i < matrixCopy.ColumnCount; i++)
{ {
VT.At(i, l, e[i]); vt.At(i, l, e[i]);
} }
} }
} }
@ -210,12 +204,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
var nrtp1 = nrt + 1; var nrtp1 = nrt + 1;
if (nct < matrixCopy.ColumnCount) if (nct < matrixCopy.ColumnCount)
{ {
S[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1)); s[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1));
} }
if (matrixCopy.RowCount < m) if (matrixCopy.RowCount < m)
{ {
S[m - 1] = Complex32.Zero; s[m - 1] = Complex32.Zero;
} }
if (nrtp1 < m) if (nrtp1 < m)
@ -226,55 +220,55 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
e[m - 1] = Complex32.Zero; e[m - 1] = Complex32.Zero;
// If required, generate u. // If required, generate u.
if (ComputeVectors) if (computeVectors)
{ {
for (j = nctp1 - 1; j < ncu; j++) for (j = nctp1 - 1; j < ncu; j++)
{ {
for (i = 0; i < matrixCopy.RowCount; i++) for (i = 0; i < matrixCopy.RowCount; i++)
{ {
U.At(i, j, Complex32.Zero); u.At(i, j, Complex32.Zero);
} }
U.At(j, j, Complex32.One); u.At(j, j, Complex32.One);
} }
for (l = nct - 1; l >= 0; l--) for (l = nct - 1; l >= 0; l--)
{ {
if (S[l].Magnitude != 0.0f) if (s[l].Magnitude != 0.0f)
{ {
for (j = l + 1; j < ncu; j++) for (j = l + 1; j < ncu; j++)
{ {
t = -Cdotc(U, matrixCopy.RowCount, l, j, l) / U.At(l, l); t = -Cdotc(u, matrixCopy.RowCount, l, j, l)/u.At(l, l);
if (t != Complex32.Zero) if (t != Complex32.Zero)
{ {
for (var ii = l; ii < matrixCopy.RowCount; ii++) for (var ii = l; ii < matrixCopy.RowCount; ii++)
{ {
U.At(ii, j, U.At(ii, j) + (t * U.At(ii, l))); u.At(ii, j, u.At(ii, j) + (t*u.At(ii, l)));
} }
} }
} }
CscalColumn(U, matrixCopy.RowCount, l, l, -1.0f); CscalColumn(u, matrixCopy.RowCount, l, l, -1.0f);
U.At(l, l, Complex32.One + U.At(l, l)); u.At(l, l, Complex32.One + u.At(l, l));
for (i = 0; i < l; i++) for (i = 0; i < l; i++)
{ {
U.At(i, l, Complex32.Zero); u.At(i, l, Complex32.Zero);
} }
} }
else else
{ {
for (i = 0; i < matrixCopy.RowCount; i++) for (i = 0; i < matrixCopy.RowCount; i++)
{ {
U.At(i, l, Complex32.Zero); u.At(i, l, Complex32.Zero);
} }
U.At(l, l, Complex32.One); u.At(l, l, Complex32.One);
} }
} }
} }
// If it is required, generate v. // If it is required, generate v.
if (ComputeVectors) if (computeVectors)
{ {
for (l = matrixCopy.ColumnCount - 1; l >= 0; l--) for (l = matrixCopy.ColumnCount - 1; l >= 0; l--)
{ {
@ -285,12 +279,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{ {
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
t = -Cdotc(VT, matrixCopy.ColumnCount, l, j, lp1) / VT.At(lp1, l); t = -Cdotc(vt, matrixCopy.ColumnCount, l, j, lp1)/vt.At(lp1, l);
if (t != Complex32.Zero) if (t != Complex32.Zero)
{ {
for (var ii = l; ii < matrixCopy.ColumnCount; ii++) for (var ii = l; ii < matrixCopy.ColumnCount; ii++)
{ {
VT.At(ii, j, VT.At(ii, j) + (t * VT.At(ii, l))); vt.At(ii, j, vt.At(ii, j) + (t*vt.At(ii, l)));
} }
} }
} }
@ -299,10 +293,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
for (i = 0; i < matrixCopy.ColumnCount; i++) for (i = 0; i < matrixCopy.ColumnCount; i++)
{ {
VT.At(i, l, Complex32.Zero); vt.At(i, l, Complex32.Zero);
} }
VT.At(l, l, Complex32.One); vt.At(l, l, Complex32.One);
} }
} }
@ -310,19 +304,19 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
for (i = 0; i < m; i++) for (i = 0; i < m; i++)
{ {
Complex32 r; Complex32 r;
if (S[i].Magnitude != 0.0f) if (s[i].Magnitude != 0.0f)
{ {
t = S[i].Magnitude; t = s[i].Magnitude;
r = S[i] / t; r = s[i]/t;
S[i] = t; s[i] = t;
if (i < m - 1) if (i < m - 1)
{ {
e[i] = e[i] / r; e[i] = e[i]/r;
} }
if (ComputeVectors) if (computeVectors)
{ {
CscalColumn(U, matrixCopy.RowCount, i, 0, r); CscalColumn(u, matrixCopy.RowCount, i, 0, r);
} }
} }
@ -335,12 +329,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
if (e[i].Magnitude != 0.0f) if (e[i].Magnitude != 0.0f)
{ {
t = e[i].Magnitude; t = e[i].Magnitude;
r = t / e[i]; r = t/e[i];
e[i] = t; e[i] = t;
S[i + 1] = S[i + 1] * r; s[i + 1] = s[i + 1]*r;
if (ComputeVectors) if (computeVectors)
{ {
CscalColumn(VT, matrixCopy.ColumnCount, i + 1, 0, r); CscalColumn(vt, matrixCopy.ColumnCount, i + 1, 0, r);
} }
} }
} }
@ -368,7 +362,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
float test; float test;
for (l = m - 2; l >= 0; l--) for (l = m - 2; l >= 0; l--)
{ {
test = S[l].Magnitude + S[l + 1].Magnitude; test = s[l].Magnitude + s[l + 1].Magnitude;
ztest = test + e[l].Magnitude; ztest = test + e[l].Magnitude;
if (ztest.AlmostEqualInDecimalPlaces(test, 7)) if (ztest.AlmostEqualInDecimalPlaces(test, 7))
{ {
@ -398,10 +392,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
test = test + e[ls - 1].Magnitude; test = test + e[ls - 1].Magnitude;
} }
ztest = test + S[ls].Magnitude; ztest = test + s[ls].Magnitude;
if (ztest.AlmostEqualInDecimalPlaces(test, 7)) if (ztest.AlmostEqualInDecimalPlaces(test, 7))
{ {
S[ls] = Complex32.Zero; s[ls] = Complex32.Zero;
break; break;
} }
} }
@ -430,7 +424,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
float cs; float cs;
switch (kase) switch (kase)
{ {
// Deflate negligible VectorS[m]. // Deflate negligible VectorS[m].
case 1: case 1:
f = e[m - 2].Real; f = e[m - 2].Real;
e[m - 2] = Complex32.Zero; e[m - 2] = Complex32.Zero;
@ -438,73 +432,73 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
for (var kk = l; kk < m - 1; kk++) for (var kk = l; kk < m - 1; kk++)
{ {
k = m - 2 - kk + l; k = m - 2 - kk + l;
t1 = S[k].Real; t1 = s[k].Real;
Srotg(ref t1, ref f, out cs, out sn); Srotg(ref t1, ref f, out cs, out sn);
S[k] = t1; s[k] = t1;
if (k != l) if (k != l)
{ {
f = -sn * e[k - 1].Real; f = -sn*e[k - 1].Real;
e[k - 1] = cs * e[k - 1]; e[k - 1] = cs*e[k - 1];
} }
if (ComputeVectors) if (computeVectors)
{ {
Csrot(VT, matrixCopy.ColumnCount, k, m - 1, cs, sn); Csrot(vt, matrixCopy.ColumnCount, k, m - 1, cs, sn);
} }
} }
break; break;
// Split at negligible VectorS[l]. // Split at negligible VectorS[l].
case 2: case 2:
f = e[l - 1].Real; f = e[l - 1].Real;
e[l - 1] = Complex32.Zero; e[l - 1] = Complex32.Zero;
for (k = l; k < m; k++) for (k = l; k < m; k++)
{ {
t1 = S[k].Real; t1 = s[k].Real;
Srotg(ref t1, ref f, out cs, out sn); Srotg(ref t1, ref f, out cs, out sn);
S[k] = t1; s[k] = t1;
f = -sn * e[k].Real; f = -sn*e[k].Real;
e[k] = cs * e[k]; e[k] = cs*e[k];
if (ComputeVectors) if (computeVectors)
{ {
Csrot(U, matrixCopy.RowCount, k, l - 1, cs, sn); Csrot(u, matrixCopy.RowCount, k, l - 1, cs, sn);
} }
} }
break; break;
// Perform one qr step. // Perform one qr step.
case 3: case 3:
// Calculate the shift. // Calculate the shift.
var scale = 0.0f; var scale = 0.0f;
scale = Math.Max(scale, S[m - 1].Magnitude); scale = Math.Max(scale, s[m - 1].Magnitude);
scale = Math.Max(scale, S[m - 2].Magnitude); scale = Math.Max(scale, s[m - 2].Magnitude);
scale = Math.Max(scale, e[m - 2].Magnitude); scale = Math.Max(scale, e[m - 2].Magnitude);
scale = Math.Max(scale, S[l].Magnitude); scale = Math.Max(scale, s[l].Magnitude);
scale = Math.Max(scale, e[l].Magnitude); scale = Math.Max(scale, e[l].Magnitude);
var sm = S[m - 1].Real / scale; var sm = s[m - 1].Real/scale;
var smm1 = S[m - 2].Real / scale; var smm1 = s[m - 2].Real/scale;
var emm1 = e[m - 2].Real / scale; var emm1 = e[m - 2].Real/scale;
var sl = S[l].Real / scale; var sl = s[l].Real/scale;
var el = e[l].Real / scale; var el = e[l].Real/scale;
var b = (((smm1 + sm) * (smm1 - sm)) + (emm1 * emm1)) / 2.0f; var b = (((smm1 + sm)*(smm1 - sm)) + (emm1*emm1))/2.0f;
var c = (sm * emm1) * (sm * emm1); var c = (sm*emm1)*(sm*emm1);
var shift = 0.0f; var shift = 0.0f;
if (b != 0.0f || c != 0.0f) if (b != 0.0f || c != 0.0f)
{ {
shift = (float)Math.Sqrt((b * b) + c); shift = (float) Math.Sqrt((b*b) + c);
if (b < 0.0f) if (b < 0.0f)
{ {
shift = -shift; shift = -shift;
} }
shift = c / (b + shift); shift = c/(b + shift);
} }
f = ((sl + sm) * (sl - sm)) + shift; f = ((sl + sm)*(sl - sm)) + shift;
var g = sl * el; var g = sl*el;
// Chase zeros. // Chase zeros.
for (k = l; k < m - 1; k++) for (k = l; k < m - 1; k++)
@ -515,24 +509,24 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
e[k - 1] = f; e[k - 1] = f;
} }
f = (cs * S[k].Real) + (sn * e[k].Real); f = (cs*s[k].Real) + (sn*e[k].Real);
e[k] = (cs * e[k]) - (sn * S[k]); e[k] = (cs*e[k]) - (sn*s[k]);
g = sn * S[k + 1].Real; g = sn*s[k + 1].Real;
S[k + 1] = cs * S[k + 1]; s[k + 1] = cs*s[k + 1];
if (ComputeVectors) if (computeVectors)
{ {
Csrot(VT, matrixCopy.ColumnCount, k, k + 1, cs, sn); Csrot(vt, matrixCopy.ColumnCount, k, k + 1, cs, sn);
} }
Srotg(ref f, ref g, out cs, out sn); Srotg(ref f, ref g, out cs, out sn);
S[k] = f; s[k] = f;
f = (cs * e[k].Real) + (sn * S[k + 1].Real); f = (cs*e[k].Real) + (sn*s[k + 1].Real);
S[k + 1] = (-sn * e[k]) + (cs * S[k + 1]); s[k + 1] = (-sn*e[k]) + (cs*s[k + 1]);
g = sn * e[k + 1].Real; g = sn*e[k + 1].Real;
e[k + 1] = cs * e[k + 1]; e[k + 1] = cs*e[k + 1];
if (ComputeVectors && k < matrixCopy.RowCount) if (computeVectors && k < matrixCopy.RowCount)
{ {
Csrot(U, matrixCopy.RowCount, k, k + 1, cs, sn); Csrot(u, matrixCopy.RowCount, k, k + 1, cs, sn);
} }
} }
@ -540,37 +534,37 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
iter = iter + 1; iter = iter + 1;
break; break;
// Convergence. // Convergence.
case 4: case 4:
// Make the singular value positive // Make the singular value positive
if (S[l].Real < 0.0f) if (s[l].Real < 0.0f)
{ {
S[l] = -S[l]; s[l] = -s[l];
if (ComputeVectors) if (computeVectors)
{ {
CscalColumn(VT, matrixCopy.ColumnCount, l, 0, -1.0f); CscalColumn(vt, matrixCopy.ColumnCount, l, 0, -1.0f);
} }
} }
// Order the singular value. // Order the singular value.
while (l != mn - 1) while (l != mn - 1)
{ {
if (S[l].Real >= S[l + 1].Real) if (s[l].Real >= s[l + 1].Real)
{ {
break; break;
} }
t = S[l]; t = s[l];
S[l] = S[l + 1]; s[l] = s[l + 1];
S[l + 1] = t; s[l + 1] = t;
if (ComputeVectors && l < matrixCopy.ColumnCount) if (computeVectors && l < matrixCopy.ColumnCount)
{ {
Swap(VT, matrixCopy.ColumnCount, l, l + 1); Swap(vt, matrixCopy.ColumnCount, l, l + 1);
} }
if (ComputeVectors && l < matrixCopy.RowCount) if (computeVectors && l < matrixCopy.RowCount)
{ {
Swap(U, matrixCopy.RowCount, l, l + 1); Swap(u, matrixCopy.RowCount, l, l + 1);
} }
l = l + 1; l = l + 1;
@ -582,9 +576,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
} }
} }
if (ComputeVectors) if (computeVectors)
{ {
VT = VT.ConjugateTranspose(); vt = vt.ConjugateTranspose();
} }
// Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses // Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses
@ -596,11 +590,18 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
var tmp = matrixCopy.CreateVector(nm); var tmp = matrixCopy.CreateVector(nm);
for (i = 0; i < nm; i++) for (i = 0; i < nm; i++)
{ {
tmp[i] = S[i]; tmp[i] = s[i];
} }
S = tmp; s = tmp;
} }
return new UserSvd(s, u, vt, computeVectors);
}
UserSvd(Vector<Complex32> s, Matrix<Complex32> u, Matrix<Complex32> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
} }
/// <summary> /// <summary>
@ -609,9 +610,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="z1">Complex32 value z1</param> /// <param name="z1">Complex32 value z1</param>
/// <param name="z2">Complex32 value z2</param> /// <param name="z2">Complex32 value z2</param>
/// <returns>Result multiplication of signum function and absolute value</returns> /// <returns>Result multiplication of signum function and absolute value</returns>
private static Complex32 Csign(Complex32 z1, Complex32 z2) static Complex32 Csign(Complex32 z1, Complex32 z2)
{ {
return z1.Magnitude * (z2 / z2.Magnitude); return z1.Magnitude*(z2/z2.Magnitude);
} }
/// <summary> /// <summary>
@ -621,7 +622,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="rowCount">The number of rows in <paramref name="a"/></param> /// <param name="rowCount">The number of rows in <paramref name="a"/></param>
/// <param name="columnA">Column A index to swap</param> /// <param name="columnA">Column A index to swap</param>
/// <param name="columnB">Column B index to swap</param> /// <param name="columnB">Column B index to swap</param>
private static void Swap(Matrix<Complex32> a, int rowCount, int columnA, int columnB) static void Swap(Matrix<Complex32> a, int rowCount, int columnA, int columnB)
{ {
for (var i = 0; i < rowCount; i++) for (var i = 0; i < rowCount; i++)
{ {
@ -639,11 +640,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="column">Column to scale</param> /// <param name="column">Column to scale</param>
/// <param name="rowStart">Row to scale from</param> /// <param name="rowStart">Row to scale from</param>
/// <param name="z">Scale value</param> /// <param name="z">Scale value</param>
private static void CscalColumn(Matrix<Complex32> a, int rowCount, int column, int rowStart, Complex32 z) static void CscalColumn(Matrix<Complex32> a, int rowCount, int column, int rowStart, Complex32 z)
{ {
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
a.At(i, column, a.At(i, column) * z); a.At(i, column, a.At(i, column)*z);
} }
} }
@ -653,11 +654,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="a">Source vector</param> /// <param name="a">Source vector</param>
/// <param name="start">Row to scale from</param> /// <param name="start">Row to scale from</param>
/// <param name="z">Scale value</param> /// <param name="z">Scale value</param>
private static void CscalVector(Complex32[] a, int start, Complex32 z) static void CscalVector(Complex32[] a, int start, Complex32 z)
{ {
for (var i = start; i < a.Length; i++) for (var i = start; i < a.Length; i++)
{ {
a[i] = a[i] * z; a[i] = a[i]*z;
} }
} }
@ -670,7 +671,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="c">Contains the parameter c associated with the Givens rotation</param> /// <param name="c">Contains the parameter c associated with the Givens rotation</param>
/// <param name="s">Contains the parameter s associated with the Givens rotation</param> /// <param name="s">Contains the parameter s associated with the Givens rotation</param>
/// <remarks>This is equivalent to the DROTG LAPACK routine.</remarks> /// <remarks>This is equivalent to the DROTG LAPACK routine.</remarks>
private static void Srotg(ref float da, ref float db, out float c, out float s) static void Srotg(ref float da, ref float db, out float c, out float s)
{ {
float r, z; float r, z;
@ -692,16 +693,16 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
} }
else else
{ {
var sda = da / scale; var sda = da/scale;
var sdb = db / scale; var sdb = db/scale;
r = scale * (float)Math.Sqrt((sda * sda) + (sdb * sdb)); r = scale*(float) Math.Sqrt((sda*sda) + (sdb*sdb));
if (roe < 0.0f) if (roe < 0.0f)
{ {
r = -r; r = -r;
} }
c = da / r; c = da/r;
s = db / r; s = db/r;
z = 1.0f; z = 1.0f;
if (absda > absdb) if (absda > absdb)
{ {
@ -710,7 +711,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
if (absdb >= absda && c != 0.0f) if (absdb >= absda && c != 0.0f)
{ {
z = 1.0f / c; z = 1.0f/c;
} }
} }
@ -726,15 +727,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="column">Column index</param> /// <param name="column">Column index</param>
/// <param name="rowStart">Start row index</param> /// <param name="rowStart">Start row index</param>
/// <returns>Norm2 (Euclidean norm) of the column</returns> /// <returns>Norm2 (Euclidean norm) of the column</returns>
private static float Cnrm2Column(Matrix<Complex32> a, int rowCount, int column, int rowStart) static float Cnrm2Column(Matrix<Complex32> a, int rowCount, int column, int rowStart)
{ {
var s = 0.0f; var s = 0.0f;
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
s += a.At(i, column).Magnitude * a.At(i, column).Magnitude; s += a.At(i, column).Magnitude*a.At(i, column).Magnitude;
} }
return (float)Math.Sqrt(s); return (float) Math.Sqrt(s);
} }
/// <summary> /// <summary>
@ -743,15 +744,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="a">Source vector</param> /// <param name="a">Source vector</param>
/// <param name="rowStart">Start index</param> /// <param name="rowStart">Start index</param>
/// <returns>Norm2 (Euclidean norm) of the vector</returns> /// <returns>Norm2 (Euclidean norm) of the vector</returns>
private static float Cnrm2Vector(Complex32[] a, int rowStart) static float Cnrm2Vector(Complex32[] a, int rowStart)
{ {
var s = 0.0f; var s = 0.0f;
for (var i = rowStart; i < a.Length; i++) for (var i = rowStart; i < a.Length; i++)
{ {
s += a[i].Magnitude * a[i].Magnitude; s += a[i].Magnitude*a[i].Magnitude;
} }
return (float)Math.Sqrt(s); return (float) Math.Sqrt(s);
} }
/// <summary> /// <summary>
@ -763,12 +764,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="columnB">Index of column B</param> /// <param name="columnB">Index of column B</param>
/// <param name="rowStart">Starting row index</param> /// <param name="rowStart">Starting row index</param>
/// <returns>Dot product value</returns> /// <returns>Dot product value</returns>
private static Complex32 Cdotc(Matrix<Complex32> a, int rowCount, int columnA, int columnB, int rowStart) static Complex32 Cdotc(Matrix<Complex32> a, int rowCount, int columnA, int columnB, int rowStart)
{ {
var z = Complex32.Zero; var z = Complex32.Zero;
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
z += a.At(i, columnA).Conjugate() * a.At(i, columnB); z += a.At(i, columnA).Conjugate()*a.At(i, columnB);
} }
return z; return z;
@ -784,17 +785,17 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="columnB">Index of column B</param> /// <param name="columnB">Index of column B</param>
/// <param name="c">scalar cos value</param> /// <param name="c">scalar cos value</param>
/// <param name="s">scalar sin value</param> /// <param name="s">scalar sin value</param>
private static void Csrot(Matrix<Complex32> a, int rowCount, int columnA, int columnB, float c, float s) static void Csrot(Matrix<Complex32> a, int rowCount, int columnA, int columnB, float c, float s)
{ {
for (var i = 0; i < rowCount; i++) for (var i = 0; i < rowCount; i++)
{ {
var z = (c * a.At(i, columnA)) + (s * a.At(i, columnB)); var z = (c*a.At(i, columnA)) + (s*a.At(i, columnB));
var tmp = (c * a.At(i, columnB)) - (s * a.At(i, columnA)); var tmp = (c*a.At(i, columnB)) - (s*a.At(i, columnA));
a.At(i, columnB, tmp); a.At(i, columnB, tmp);
a.At(i, columnA, z); a.At(i, columnA, z);
} }
} }
/// <summary> /// <summary>
/// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized. /// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized.
/// </summary> /// </summary>
@ -802,18 +803,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
public override void Solve(Matrix<Complex32> input, Matrix<Complex32> result) public override void Solve(Matrix<Complex32> input, Matrix<Complex32> result)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -850,7 +840,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{ {
for (var i = 0; i < U.RowCount; i++) for (var i = 0; i < U.RowCount; i++)
{ {
value += U.At(i, j).Conjugate() * input.At(i, k); value += U.At(i, j).Conjugate()*input.At(i, k);
} }
value /= S[j]; value /= S[j];
@ -864,7 +854,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
var value = Complex32.Zero; var value = Complex32.Zero;
for (var i = 0; i < VT.ColumnCount; i++) for (var i = 0; i < VT.ColumnCount; i++)
{ {
value += VT.At(i, j).Conjugate() * tmp[i]; value += VT.At(i, j).Conjugate()*tmp[i];
} }
result.At(j, k, value); result.At(j, k, value);
@ -879,17 +869,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
public override void Solve(Vector<Complex32> input, Vector<Complex32> result) public override void Solve(Vector<Complex32> input, Vector<Complex32> result)
{ {
if (input == null) if (!VectorsComputed)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -916,7 +896,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{ {
for (var i = 0; i < U.RowCount; i++) for (var i = 0; i < U.RowCount; i++)
{ {
value += U.At(i, j).Conjugate() * input[i]; value += U.At(i, j).Conjugate()*input[i];
} }
value /= S[j]; value /= S[j];
@ -930,7 +910,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
var value = Complex32.Zero; var value = Complex32.Zero;
for (var i = 0; i < VT.ColumnCount; i++) for (var i = 0; i < VT.ColumnCount; i++)
{ {
value += VT.At(i, j).Conjugate() * tmp[i]; value += VT.At(i, j).Conjugate()*tmp[i];
} }
result[j] = value; result[j] = value;

2
src/Numerics/LinearAlgebra/Complex32/Matrix.cs

@ -475,7 +475,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override Svd<Complex32> Svd(bool computeVectors) public override Svd<Complex32> Svd(bool computeVectors)
{ {
return new UserSvd(this, computeVectors); return UserSvd.Create(this, computeVectors);
} }
public override Evd<Complex32> Evd() public override Evd<Complex32> Evd()

2
src/Numerics/LinearAlgebra/Double/DenseMatrix.cs

@ -1057,7 +1057,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override Svd<double> Svd(bool computeVectors) public override Svd<double> Svd(bool computeVectors)
{ {
return new DenseSvd(this, computeVectors); return DenseSvd.Create(this, computeVectors);
} }
public override Evd<double> Evd() public override Evd<double> Evd()

58
src/Numerics/LinearAlgebra/Double/Factorization/DenseSvd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,8 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.Properties;
using System; using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Double.Factorization namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{ {
@ -47,7 +47,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <remarks> /// <remarks>
/// The computation of the singular value decomposition is done at construction time. /// The computation of the singular value decomposition is done at construction time.
/// </remarks> /// </remarks>
public class DenseSvd : Svd public sealed class DenseSvd : Svd
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseSvd"/> class. This object will compute the /// Initializes a new instance of the <see cref="DenseSvd"/> class. This object will compute the
@ -57,19 +57,20 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param> /// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception> /// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception>
public DenseSvd(DenseMatrix matrix, bool computeVectors) public static DenseSvd Create(DenseMatrix matrix, bool computeVectors)
{ {
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
ComputeVectors = computeVectors;
var nm = Math.Min(matrix.RowCount, matrix.ColumnCount); var nm = Math.Min(matrix.RowCount, matrix.ColumnCount);
S = new DenseVector(nm); var s = new DenseVector(nm);
U = new DenseMatrix(matrix.RowCount); var u = new DenseMatrix(matrix.RowCount);
VT = new DenseMatrix(matrix.ColumnCount); var vt = new DenseMatrix(matrix.ColumnCount);
Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Values, matrix.RowCount, matrix.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values); Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix) matrix.Clone()).Values, matrix.RowCount, matrix.ColumnCount, s.Values, u.Values, vt.Values);
return new DenseSvd(s, u, vt, computeVectors);
}
DenseSvd(Vector<double> s, Matrix<double> u, Matrix<double> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
} }
/// <summary> /// <summary>
@ -79,18 +80,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
public override void Solve(Matrix<double> input, Matrix<double> result) public override void Solve(Matrix<double> input, Matrix<double> result)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -125,7 +115,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values, dinput.Values, input.ColumnCount, dresult.Values); Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector) S).Values, ((DenseMatrix) U).Values, ((DenseMatrix) VT).Values, dinput.Values, input.ColumnCount, dresult.Values);
} }
/// <summary> /// <summary>
@ -135,17 +125,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
public override void Solve(Vector<double> input, Vector<double> result) public override void Solve(Vector<double> input, Vector<double> result)
{ {
if (input == null) if (!VectorsComputed)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -175,7 +155,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values, dinput.Values, 1, dresult.Values); Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector) S).Values, ((DenseMatrix) U).Values, ((DenseMatrix) VT).Values, dinput.Values, 1, dresult.Values);
} }
} }
} }

11
src/Numerics/LinearAlgebra/Double/Factorization/Svd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,10 +28,10 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
using System; using System;
using System.Linq; using System.Linq;
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Double.Factorization namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{ {
@ -51,6 +51,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// </remarks> /// </remarks>
public abstract class Svd : Svd<double> public abstract class Svd : Svd<double>
{ {
protected Svd(Vector<double> s, Matrix<double> u, Matrix<double> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
}
/// <summary> /// <summary>
/// Gets the effective numerical matrix rank. /// Gets the effective numerical matrix rank.
/// </summary> /// </summary>

322
src/Numerics/LinearAlgebra/Double/Factorization/UserSvd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,8 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.Properties;
using System; using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Double.Factorization namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{ {
@ -47,7 +47,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <remarks> /// <remarks>
/// The computation of the singular value decomposition is done at construction time. /// The computation of the singular value decomposition is done at construction time.
/// </remarks> /// </remarks>
public class UserSvd : Svd public sealed class UserSvd : Svd
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the /// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the
@ -57,20 +57,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param> /// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="NonConvergenceException"></exception> /// <exception cref="NonConvergenceException"></exception>
public UserSvd(Matrix<double> matrix, bool computeVectors) public static UserSvd Create(Matrix<double> matrix, bool computeVectors)
{ {
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
ComputeVectors = computeVectors;
var nm = Math.Min(matrix.RowCount + 1, matrix.ColumnCount); var nm = Math.Min(matrix.RowCount + 1, matrix.ColumnCount);
var matrixCopy = matrix.Clone(); var matrixCopy = matrix.Clone();
S = matrixCopy.CreateVector(nm); var s = matrixCopy.CreateVector(nm);
U = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount); var u = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount);
VT = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount); var vt = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount);
const int maxiter = 1000; const int maxiter = 1000;
var e = new double[matrixCopy.ColumnCount]; var e = new double[matrixCopy.ColumnCount];
@ -94,32 +88,32 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{ {
// Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l]. // Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l].
var xnorm = Dnrm2Column(matrixCopy, matrixCopy.RowCount, l, l); var xnorm = Dnrm2Column(matrixCopy, matrixCopy.RowCount, l, l);
S[l] = xnorm; s[l] = xnorm;
if (S[l] != 0.0) if (s[l] != 0.0)
{ {
if (matrixCopy.At(l, l) != 0.0) if (matrixCopy.At(l, l) != 0.0)
{ {
S[l] = Dsign(S[l], matrixCopy.At(l, l)); s[l] = Dsign(s[l], matrixCopy.At(l, l));
} }
DscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0 / S[l]); DscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0/s[l]);
matrixCopy.At(l, l, (1.0 + matrixCopy.At(l, l))); matrixCopy.At(l, l, (1.0 + matrixCopy.At(l, l)));
} }
S[l] = -S[l]; s[l] = -s[l];
} }
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
if (l < nct) if (l < nct)
{ {
if (S[l] != 0.0) if (s[l] != 0.0)
{ {
// Apply the transformation. // Apply the transformation.
t = -Ddot(matrixCopy, matrixCopy.RowCount, l, j, l) / matrixCopy.At(l, l); t = -Ddot(matrixCopy, matrixCopy.RowCount, l, j, l)/matrixCopy.At(l, l);
for (var ii = l; ii < matrixCopy.RowCount; ii++) for (var ii = l; ii < matrixCopy.RowCount; ii++)
{ {
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t * matrixCopy.At(ii, l))); matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t*matrixCopy.At(ii, l)));
} }
} }
} }
@ -129,12 +123,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
e[j] = matrixCopy.At(l, j); e[j] = matrixCopy.At(l, j);
} }
if (ComputeVectors && l < nct) if (computeVectors && l < nct)
{ {
// Place the transformation in u for subsequent back multiplication. // Place the transformation in u for subsequent back multiplication.
for (i = l; i < matrixCopy.RowCount; i++) for (i = l; i < matrixCopy.RowCount; i++)
{ {
U.At(i, l, matrixCopy.At(i, l)); u.At(i, l, matrixCopy.At(i, l));
} }
} }
@ -153,7 +147,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
e[l] = Dsign(e[l], e[lp1]); e[l] = Dsign(e[l], e[lp1]);
} }
DscalVector(e, lp1, 1.0 / e[l]); DscalVector(e, lp1, 1.0/e[l]);
e[lp1] = 1.0 + e[lp1]; e[lp1] = 1.0 + e[lp1];
} }
@ -170,26 +164,26 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{ {
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
{ {
work[ii] += e[j] * matrixCopy.At(ii, j); work[ii] += e[j]*matrixCopy.At(ii, j);
} }
} }
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
var ww = -e[j] / e[lp1]; var ww = -e[j]/e[lp1];
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
{ {
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww * work[ii])); matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww*work[ii]));
} }
} }
} }
if (ComputeVectors) if (computeVectors)
{ {
// Place the transformation in v for subsequent back multiplication. // Place the transformation in v for subsequent back multiplication.
for (i = lp1; i < matrixCopy.ColumnCount; i++) for (i = lp1; i < matrixCopy.ColumnCount; i++)
{ {
VT.At(i, l, e[i]); vt.At(i, l, e[i]);
} }
} }
} }
@ -200,12 +194,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
var nrtp1 = nrt + 1; var nrtp1 = nrt + 1;
if (nct < matrixCopy.ColumnCount) if (nct < matrixCopy.ColumnCount)
{ {
S[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1)); s[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1));
} }
if (matrixCopy.RowCount < m) if (matrixCopy.RowCount < m)
{ {
S[m - 1] = 0.0; s[m - 1] = 0.0;
} }
if (nrtp1 < m) if (nrtp1 < m)
@ -216,52 +210,52 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
e[m - 1] = 0.0; e[m - 1] = 0.0;
// If required, generate u. // If required, generate u.
if (ComputeVectors) if (computeVectors)
{ {
for (j = nctp1 - 1; j < ncu; j++) for (j = nctp1 - 1; j < ncu; j++)
{ {
for (i = 0; i < matrixCopy.RowCount; i++) for (i = 0; i < matrixCopy.RowCount; i++)
{ {
U.At(i, j, 0.0); u.At(i, j, 0.0);
} }
U.At(j, j, 1.0); u.At(j, j, 1.0);
} }
for (l = nct - 1; l >= 0; l--) for (l = nct - 1; l >= 0; l--)
{ {
if (S[l] != 0.0) if (s[l] != 0.0)
{ {
for (j = l + 1; j < ncu; j++) for (j = l + 1; j < ncu; j++)
{ {
t = -Ddot(U, matrixCopy.RowCount, l, j, l) / U.At(l, l); t = -Ddot(u, matrixCopy.RowCount, l, j, l)/u.At(l, l);
for (var ii = l; ii < matrixCopy.RowCount; ii++) for (var ii = l; ii < matrixCopy.RowCount; ii++)
{ {
U.At(ii, j, U.At(ii, j) + (t * U.At(ii, l))); u.At(ii, j, u.At(ii, j) + (t*u.At(ii, l)));
} }
} }
DscalColumn(U, matrixCopy.RowCount, l, l, -1.0); DscalColumn(u, matrixCopy.RowCount, l, l, -1.0);
U.At(l, l, 1.0 + U.At(l, l)); u.At(l, l, 1.0 + u.At(l, l));
for (i = 0; i < l; i++) for (i = 0; i < l; i++)
{ {
U.At(i, l, 0.0); u.At(i, l, 0.0);
} }
} }
else else
{ {
for (i = 0; i < matrixCopy.RowCount; i++) for (i = 0; i < matrixCopy.RowCount; i++)
{ {
U.At(i, l, 0.0); u.At(i, l, 0.0);
} }
U.At(l, l, 1.0); u.At(l, l, 1.0);
} }
} }
} }
// If it is required, generate v. // If it is required, generate v.
if (ComputeVectors) if (computeVectors)
{ {
for (l = matrixCopy.ColumnCount - 1; l >= 0; l--) for (l = matrixCopy.ColumnCount - 1; l >= 0; l--)
{ {
@ -272,10 +266,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{ {
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
t = -Ddot(VT, matrixCopy.ColumnCount, l, j, lp1) / VT.At(lp1, l); t = -Ddot(vt, matrixCopy.ColumnCount, l, j, lp1)/vt.At(lp1, l);
for (var ii = l; ii < matrixCopy.ColumnCount; ii++) for (var ii = l; ii < matrixCopy.ColumnCount; ii++)
{ {
VT.At(ii, j, VT.At(ii, j) + (t * VT.At(ii, l))); vt.At(ii, j, vt.At(ii, j) + (t*vt.At(ii, l)));
} }
} }
} }
@ -283,10 +277,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
for (i = 0; i < matrixCopy.ColumnCount; i++) for (i = 0; i < matrixCopy.ColumnCount; i++)
{ {
VT.At(i, l, 0.0); vt.At(i, l, 0.0);
} }
VT.At(l, l, 1.0); vt.At(l, l, 1.0);
} }
} }
@ -294,19 +288,19 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
for (i = 0; i < m; i++) for (i = 0; i < m; i++)
{ {
double r; double r;
if (S[i] != 0.0) if (s[i] != 0.0)
{ {
t = S[i]; t = s[i];
r = S[i] / t; r = s[i]/t;
S[i] = t; s[i] = t;
if (i < m - 1) if (i < m - 1)
{ {
e[i] = e[i] / r; e[i] = e[i]/r;
} }
if (ComputeVectors) if (computeVectors)
{ {
DscalColumn(U, matrixCopy.RowCount, i, 0, r); DscalColumn(u, matrixCopy.RowCount, i, 0, r);
} }
} }
@ -319,12 +313,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
if (e[i] != 0.0) if (e[i] != 0.0)
{ {
t = e[i]; t = e[i];
r = t / e[i]; r = t/e[i];
e[i] = t; e[i] = t;
S[i + 1] = S[i + 1] * r; s[i + 1] = s[i + 1]*r;
if (ComputeVectors) if (computeVectors)
{ {
DscalColumn(VT, matrixCopy.ColumnCount, i + 1, 0, r); DscalColumn(vt, matrixCopy.ColumnCount, i + 1, 0, r);
} }
} }
} }
@ -352,7 +346,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
double test; double test;
for (l = m - 2; l >= 0; l--) for (l = m - 2; l >= 0; l--)
{ {
test = Math.Abs(S[l]) + Math.Abs(S[l + 1]); test = Math.Abs(s[l]) + Math.Abs(s[l + 1]);
ztest = test + Math.Abs(e[l]); ztest = test + Math.Abs(e[l]);
if (ztest.AlmostEqualInDecimalPlaces(test, 15)) if (ztest.AlmostEqualInDecimalPlaces(test, 15))
{ {
@ -382,10 +376,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
test = test + Math.Abs(e[ls - 1]); test = test + Math.Abs(e[ls - 1]);
} }
ztest = test + Math.Abs(S[ls]); ztest = test + Math.Abs(s[ls]);
if (ztest.AlmostEqualInDecimalPlaces(test, 15)) if (ztest.AlmostEqualInDecimalPlaces(test, 15))
{ {
S[ls] = 0.0; s[ls] = 0.0;
break; break;
} }
} }
@ -414,7 +408,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
double cs; double cs;
switch (kase) switch (kase)
{ {
// Deflate negligible VectorS[m]. // Deflate negligible VectorS[m].
case 1: case 1:
f = e[m - 2]; f = e[m - 2];
e[m - 2] = 0.0; e[m - 2] = 0.0;
@ -422,72 +416,72 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
for (var kk = l; kk < m - 1; kk++) for (var kk = l; kk < m - 1; kk++)
{ {
k = m - 2 - kk + l; k = m - 2 - kk + l;
t1 = S[k]; t1 = s[k];
Drotg(ref t1, ref f, out cs, out sn); Drotg(ref t1, ref f, out cs, out sn);
S[k] = t1; s[k] = t1;
if (k != l) if (k != l)
{ {
f = -sn * e[k - 1]; f = -sn*e[k - 1];
e[k - 1] = cs * e[k - 1]; e[k - 1] = cs*e[k - 1];
} }
if (ComputeVectors) if (computeVectors)
{ {
Drot(VT, matrixCopy.ColumnCount, k, m - 1, cs, sn); Drot(vt, matrixCopy.ColumnCount, k, m - 1, cs, sn);
} }
} }
break; break;
// Split at negligible VectorS[l]. // Split at negligible VectorS[l].
case 2: case 2:
f = e[l - 1]; f = e[l - 1];
e[l - 1] = 0.0; e[l - 1] = 0.0;
for (k = l; k < m; k++) for (k = l; k < m; k++)
{ {
t1 = S[k]; t1 = s[k];
Drotg(ref t1, ref f, out cs, out sn); Drotg(ref t1, ref f, out cs, out sn);
S[k] = t1; s[k] = t1;
f = -sn * e[k]; f = -sn*e[k];
e[k] = cs * e[k]; e[k] = cs*e[k];
if (ComputeVectors) if (computeVectors)
{ {
Drot(U, matrixCopy.RowCount, k, l - 1, cs, sn); Drot(u, matrixCopy.RowCount, k, l - 1, cs, sn);
} }
} }
break; break;
// Perform one qr step. // Perform one qr step.
case 3: case 3:
// Calculate the shift. // Calculate the shift.
var scale = 0.0; var scale = 0.0;
scale = Math.Max(scale, Math.Abs(S[m - 1])); scale = Math.Max(scale, Math.Abs(s[m - 1]));
scale = Math.Max(scale, Math.Abs(S[m - 2])); scale = Math.Max(scale, Math.Abs(s[m - 2]));
scale = Math.Max(scale, Math.Abs(e[m - 2])); scale = Math.Max(scale, Math.Abs(e[m - 2]));
scale = Math.Max(scale, Math.Abs(S[l])); scale = Math.Max(scale, Math.Abs(s[l]));
scale = Math.Max(scale, Math.Abs(e[l])); scale = Math.Max(scale, Math.Abs(e[l]));
var sm = S[m - 1] / scale; var sm = s[m - 1]/scale;
var smm1 = S[m - 2] / scale; var smm1 = s[m - 2]/scale;
var emm1 = e[m - 2] / scale; var emm1 = e[m - 2]/scale;
var sl = S[l] / scale; var sl = s[l]/scale;
var el = e[l] / scale; var el = e[l]/scale;
var b = (((smm1 + sm) * (smm1 - sm)) + (emm1 * emm1)) / 2.0; var b = (((smm1 + sm)*(smm1 - sm)) + (emm1*emm1))/2.0;
var c = (sm * emm1) * (sm * emm1); var c = (sm*emm1)*(sm*emm1);
var shift = 0.0; var shift = 0.0;
if (b != 0.0 || c != 0.0) if (b != 0.0 || c != 0.0)
{ {
shift = Math.Sqrt((b * b) + c); shift = Math.Sqrt((b*b) + c);
if (b < 0.0) if (b < 0.0)
{ {
shift = -shift; shift = -shift;
} }
shift = c / (b + shift); shift = c/(b + shift);
} }
f = ((sl + sm) * (sl - sm)) + shift; f = ((sl + sm)*(sl - sm)) + shift;
var g = sl * el; var g = sl*el;
// Chase zeros. // Chase zeros.
for (k = l; k < m - 1; k++) for (k = l; k < m - 1; k++)
@ -498,24 +492,24 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
e[k - 1] = f; e[k - 1] = f;
} }
f = (cs * S[k]) + (sn * e[k]); f = (cs*s[k]) + (sn*e[k]);
e[k] = (cs * e[k]) - (sn * S[k]); e[k] = (cs*e[k]) - (sn*s[k]);
g = sn * S[k + 1]; g = sn*s[k + 1];
S[k + 1] = cs * S[k + 1]; s[k + 1] = cs*s[k + 1];
if (ComputeVectors) if (computeVectors)
{ {
Drot(VT, matrixCopy.ColumnCount, k, k + 1, cs, sn); Drot(vt, matrixCopy.ColumnCount, k, k + 1, cs, sn);
} }
Drotg(ref f, ref g, out cs, out sn); Drotg(ref f, ref g, out cs, out sn);
S[k] = f; s[k] = f;
f = (cs * e[k]) + (sn * S[k + 1]); f = (cs*e[k]) + (sn*s[k + 1]);
S[k + 1] = (-sn * e[k]) + (cs * S[k + 1]); s[k + 1] = (-sn*e[k]) + (cs*s[k + 1]);
g = sn * e[k + 1]; g = sn*e[k + 1];
e[k + 1] = cs * e[k + 1]; e[k + 1] = cs*e[k + 1];
if (ComputeVectors && k < matrixCopy.RowCount) if (computeVectors && k < matrixCopy.RowCount)
{ {
Drot(U, matrixCopy.RowCount, k, k + 1, cs, sn); Drot(u, matrixCopy.RowCount, k, k + 1, cs, sn);
} }
} }
@ -523,37 +517,37 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
iter = iter + 1; iter = iter + 1;
break; break;
// Convergence. // Convergence.
case 4: case 4:
// Make the singular value positive // Make the singular value positive
if (S[l] < 0.0) if (s[l] < 0.0)
{ {
S[l] = -S[l]; s[l] = -s[l];
if (ComputeVectors) if (computeVectors)
{ {
DscalColumn(VT, matrixCopy.ColumnCount, l, 0, -1.0); DscalColumn(vt, matrixCopy.ColumnCount, l, 0, -1.0);
} }
} }
// Order the singular value. // Order the singular value.
while (l != mn - 1) while (l != mn - 1)
{ {
if (S[l] >= S[l + 1]) if (s[l] >= s[l + 1])
{ {
break; break;
} }
t = S[l]; t = s[l];
S[l] = S[l + 1]; s[l] = s[l + 1];
S[l + 1] = t; s[l + 1] = t;
if (ComputeVectors && l < matrixCopy.ColumnCount) if (computeVectors && l < matrixCopy.ColumnCount)
{ {
Dswap(VT, matrixCopy.ColumnCount, l, l + 1); Dswap(vt, matrixCopy.ColumnCount, l, l + 1);
} }
if (ComputeVectors && l < matrixCopy.RowCount) if (computeVectors && l < matrixCopy.RowCount)
{ {
Dswap(U, matrixCopy.RowCount, l, l + 1); Dswap(u, matrixCopy.RowCount, l, l + 1);
} }
l = l + 1; l = l + 1;
@ -565,9 +559,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
} }
} }
if (ComputeVectors) if (computeVectors)
{ {
VT = VT.Transpose(); vt = vt.Transpose();
} }
// Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses // Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses
@ -579,11 +573,18 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
var tmp = matrixCopy.CreateVector(nm); var tmp = matrixCopy.CreateVector(nm);
for (i = 0; i < nm; i++) for (i = 0; i < nm; i++)
{ {
tmp[i] = S[i]; tmp[i] = s[i];
} }
S = tmp; s = tmp;
} }
return new UserSvd(s, u, vt, computeVectors);
}
UserSvd(Vector<double> s, Matrix<double> u, Matrix<double> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
} }
/// <summary> /// <summary>
@ -592,9 +593,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="z1">Double value z1</param> /// <param name="z1">Double value z1</param>
/// <param name="z2">Double value z2</param> /// <param name="z2">Double value z2</param>
/// <returns>Result multiplication of signum function and absolute value</returns> /// <returns>Result multiplication of signum function and absolute value</returns>
private static double Dsign(double z1, double z2) static double Dsign(double z1, double z2)
{ {
return Math.Abs(z1) * (z2 / Math.Abs(z2)); return Math.Abs(z1)*(z2/Math.Abs(z2));
} }
/// <summary> /// <summary>
@ -604,7 +605,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="rowCount">The number of rows in <paramref name="a"/></param> /// <param name="rowCount">The number of rows in <paramref name="a"/></param>
/// <param name="columnA">Column A index to swap</param> /// <param name="columnA">Column A index to swap</param>
/// <param name="columnB">Column B index to swap</param> /// <param name="columnB">Column B index to swap</param>
private static void Dswap(Matrix<double> a, int rowCount, int columnA, int columnB) static void Dswap(Matrix<double> a, int rowCount, int columnA, int columnB)
{ {
for (var i = 0; i < rowCount; i++) for (var i = 0; i < rowCount; i++)
{ {
@ -622,11 +623,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="column">Column to scale</param> /// <param name="column">Column to scale</param>
/// <param name="rowStart">Row to scale from</param> /// <param name="rowStart">Row to scale from</param>
/// <param name="z">Scale value</param> /// <param name="z">Scale value</param>
private static void DscalColumn(Matrix<double> a, int rowCount, int column, int rowStart, double z) static void DscalColumn(Matrix<double> a, int rowCount, int column, int rowStart, double z)
{ {
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
a.At(i, column, a.At(i, column) * z); a.At(i, column, a.At(i, column)*z);
} }
} }
@ -636,11 +637,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="a">Source vector</param> /// <param name="a">Source vector</param>
/// <param name="start">Row to scale from</param> /// <param name="start">Row to scale from</param>
/// <param name="z">Scale value</param> /// <param name="z">Scale value</param>
private static void DscalVector(double[] a, int start, double z) static void DscalVector(double[] a, int start, double z)
{ {
for (var i = start; i < a.Length; i++) for (var i = start; i < a.Length; i++)
{ {
a[i] = a[i] * z; a[i] = a[i]*z;
} }
} }
@ -653,7 +654,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="c">Contains the parameter c associated with the Givens rotation</param> /// <param name="c">Contains the parameter c associated with the Givens rotation</param>
/// <param name="s">Contains the parameter s associated with the Givens rotation</param> /// <param name="s">Contains the parameter s associated with the Givens rotation</param>
/// <remarks>This is equivalent to the DROTG LAPACK routine.</remarks> /// <remarks>This is equivalent to the DROTG LAPACK routine.</remarks>
private static void Drotg(ref double da, ref double db, out double c, out double s) static void Drotg(ref double da, ref double db, out double c, out double s)
{ {
double r, z; double r, z;
@ -675,16 +676,16 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
} }
else else
{ {
var sda = da / scale; var sda = da/scale;
var sdb = db / scale; var sdb = db/scale;
r = scale * Math.Sqrt((sda * sda) + (sdb * sdb)); r = scale*Math.Sqrt((sda*sda) + (sdb*sdb));
if (roe < 0.0) if (roe < 0.0)
{ {
r = -r; r = -r;
} }
c = da / r; c = da/r;
s = db / r; s = db/r;
z = 1.0; z = 1.0;
if (absda > absdb) if (absda > absdb)
{ {
@ -693,7 +694,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
if (absdb >= absda && c != 0.0) if (absdb >= absda && c != 0.0)
{ {
z = 1.0 / c; z = 1.0/c;
} }
} }
@ -709,12 +710,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="column">Column index</param> /// <param name="column">Column index</param>
/// <param name="rowStart">Start row index</param> /// <param name="rowStart">Start row index</param>
/// <returns>Norm2 (Euclidean norm) of the column</returns> /// <returns>Norm2 (Euclidean norm) of the column</returns>
private static double Dnrm2Column(Matrix<double> a, int rowCount, int column, int rowStart) static double Dnrm2Column(Matrix<double> a, int rowCount, int column, int rowStart)
{ {
double s = 0; double s = 0;
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
s += a.At(i, column) * a.At(i, column); s += a.At(i, column)*a.At(i, column);
} }
return Math.Sqrt(s); return Math.Sqrt(s);
@ -726,12 +727,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="a">Source vector</param> /// <param name="a">Source vector</param>
/// <param name="rowStart">Start index</param> /// <param name="rowStart">Start index</param>
/// <returns>Norm2 (Euclidean norm) of the vector</returns> /// <returns>Norm2 (Euclidean norm) of the vector</returns>
private static double Dnrm2Vector(double[] a, int rowStart) static double Dnrm2Vector(double[] a, int rowStart)
{ {
double s = 0; double s = 0;
for (var i = rowStart; i < a.Length; i++) for (var i = rowStart; i < a.Length; i++)
{ {
s += a[i] * a[i]; s += a[i]*a[i];
} }
return Math.Sqrt(s); return Math.Sqrt(s);
@ -746,12 +747,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="columnB">Index of column B</param> /// <param name="columnB">Index of column B</param>
/// <param name="rowStart">Starting row index</param> /// <param name="rowStart">Starting row index</param>
/// <returns>Dot product value</returns> /// <returns>Dot product value</returns>
private static double Ddot(Matrix<double> a, int rowCount, int columnA, int columnB, int rowStart) static double Ddot(Matrix<double> a, int rowCount, int columnA, int columnB, int rowStart)
{ {
var z = 0.0; var z = 0.0;
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
z += a.At(i, columnB) * a.At(i, columnA); z += a.At(i, columnB)*a.At(i, columnA);
} }
return z; return z;
@ -767,17 +768,17 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="columnB">Index of column B</param> /// <param name="columnB">Index of column B</param>
/// <param name="c">Scalar "c" value</param> /// <param name="c">Scalar "c" value</param>
/// <param name="s">Scalar "s" value</param> /// <param name="s">Scalar "s" value</param>
private static void Drot(Matrix<double> a, int rowCount, int columnA, int columnB, double c, double s) static void Drot(Matrix<double> a, int rowCount, int columnA, int columnB, double c, double s)
{ {
for (var i = 0; i < rowCount; i++) for (var i = 0; i < rowCount; i++)
{ {
var z = (c * a.At(i, columnA)) + (s * a.At(i, columnB)); var z = (c*a.At(i, columnA)) + (s*a.At(i, columnB));
var tmp = (c * a.At(i, columnB)) - (s * a.At(i, columnA)); var tmp = (c*a.At(i, columnB)) - (s*a.At(i, columnA));
a.At(i, columnB, tmp); a.At(i, columnB, tmp);
a.At(i, columnA, z); a.At(i, columnA, z);
} }
} }
/// <summary> /// <summary>
/// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized. /// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized.
/// </summary> /// </summary>
@ -785,18 +786,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
public override void Solve(Matrix<double> input, Matrix<double> result) public override void Solve(Matrix<double> input, Matrix<double> result)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -833,7 +823,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{ {
for (var i = 0; i < U.RowCount; i++) for (var i = 0; i < U.RowCount; i++)
{ {
value += U.At(i, j) * input.At(i, k); value += U.At(i, j)*input.At(i, k);
} }
value /= S[j]; value /= S[j];
@ -847,7 +837,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
double value = 0; double value = 0;
for (var i = 0; i < VT.ColumnCount; i++) for (var i = 0; i < VT.ColumnCount; i++)
{ {
value += VT.At(i, j) * tmp[i]; value += VT.At(i, j)*tmp[i];
} }
result.At(j, k, value); result.At(j, k, value);
@ -862,17 +852,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
public override void Solve(Vector<double> input, Vector<double> result) public override void Solve(Vector<double> input, Vector<double> result)
{ {
if (input == null) if (!VectorsComputed)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -900,7 +880,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{ {
for (var i = 0; i < U.RowCount; i++) for (var i = 0; i < U.RowCount; i++)
{ {
value += U.At(i, j) * input[i]; value += U.At(i, j)*input[i];
} }
value /= S[j]; value /= S[j];
@ -914,7 +894,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
value = 0; value = 0;
for (int i = 0; i < VT.ColumnCount; i++) for (int i = 0; i < VT.ColumnCount; i++)
{ {
value += VT.At(i, j) * tmp[i]; value += VT.At(i, j)*tmp[i];
} }
result[j] = value; result[j] = value;

2
src/Numerics/LinearAlgebra/Double/Matrix.cs

@ -481,7 +481,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override Svd<double> Svd(bool computeVectors) public override Svd<double> Svd(bool computeVectors)
{ {
return new UserSvd(this, computeVectors); return UserSvd.Create(this, computeVectors);
} }
public override Evd<double> Evd() public override Evd<double> Evd()

96
src/Numerics/LinearAlgebra/Factorization/Svd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -49,27 +49,66 @@ namespace MathNet.Numerics.LinearAlgebra.Factorization
/// </remarks> /// </remarks>
/// <typeparam name="T">Supported data types are double, single, <see cref="Complex"/>, and <see cref="Complex32"/>.</typeparam> /// <typeparam name="T">Supported data types are double, single, <see cref="Complex"/>, and <see cref="Complex32"/>.</typeparam>
public abstract class Svd<T> : ISolver<T> public abstract class Svd<T> : ISolver<T>
where T : struct, IEquatable<T>, IFormattable where T : struct, IEquatable<T>, IFormattable
{ {
readonly Lazy<Matrix<T>> _lazyW;
/// <summary>Indicating whether U and VT matrices have been computed during SVD factorization.</summary>
protected readonly bool VectorsComputed;
protected Svd(Vector<T> s, Matrix<T> u, Matrix<T> vt, bool vectorsComputed)
{
S = s;
U = u;
VT = vt;
VectorsComputed = vectorsComputed;
_lazyW = new Lazy<Matrix<T>>(ComputeW);
}
Matrix<T> ComputeW()
{
var rows = U.RowCount;
var columns = VT.ColumnCount;
var result = U.CreateMatrix(rows, columns);
for (var i = 0; i < rows; i++)
{
for (var j = 0; j < columns; j++)
{
if (i == j)
{
result.At(i, i, S[i]);
}
}
}
return result;
}
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to compute U and VT matrices during SVD factorization or not /// Gets the singular values (Σ) of matrix in ascending value.
/// </summary> /// </summary>
protected bool ComputeVectors { get; set; } public Vector<T> S { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the singular values (Σ) of matrix in ascending value. /// Gets the left singular vectors (U - m-by-m unitary matrix)
/// </summary> /// </summary>
public Vector<T> S { get; protected set; } public Matrix<T> U { get; private set; }
/// <summary> /// <summary>
/// Gets or sets left singular vectors (U - m-by-m unitary matrix) /// Gets the transpose right singular vectors (transpose of V, an n-by-n unitary matrix)
/// </summary> /// </summary>
public Matrix<T> U { get; protected set; } public Matrix<T> VT { get; private set; }
/// <summary> /// <summary>
/// Gets or sets transpose right singular vectors (transpose of V, an n-by-n unitary matrix /// Returns the singular values as a diagonal <see cref="Matrix{T}"/>.
/// </summary> /// </summary>
public Matrix<T> VT { get; protected set; } /// <returns>The singular values as a diagonal <see cref="Matrix{T}"/>.</returns>
public Matrix<T> W
{
get { return _lazyW.Value; }
}
/// <summary> /// <summary>
/// Gets the effective numerical matrix rank. /// Gets the effective numerical matrix rank.
@ -94,27 +133,6 @@ namespace MathNet.Numerics.LinearAlgebra.Factorization
/// </summary> /// </summary>
public abstract T Determinant { get; } public abstract T Determinant { get; }
/// <summary>Returns the singular values as a diagonal <see cref="Matrix{T}"/>.</summary>
/// <returns>The singular values as a diagonal <see cref="Matrix{T}"/>.</returns>
public Matrix<T> W()
{
var rows = U.RowCount;
var columns = VT.ColumnCount;
var result = U.CreateMatrix(rows, columns);
for (var i = 0; i < rows; i++)
{
for (var j = 0; j < columns; j++)
{
if (i == j)
{
result.At(i, i, S[i]);
}
}
}
return result;
}
/// <summary> /// <summary>
/// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized. /// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized.
/// </summary> /// </summary>
@ -122,13 +140,7 @@ namespace MathNet.Numerics.LinearAlgebra.Factorization
/// <returns>The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</returns> /// <returns>The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</returns>
public virtual Matrix<T> Solve(Matrix<T> input) public virtual Matrix<T> Solve(Matrix<T> input)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -152,13 +164,7 @@ namespace MathNet.Numerics.LinearAlgebra.Factorization
/// <returns>The left hand side <see cref="Vector{T}"/>, <b>x</b>.</returns> /// <returns>The left hand side <see cref="Vector{T}"/>, <b>x</b>.</returns>
public virtual Vector<T> Solve(Vector<T> input) public virtual Vector<T> Solve(Vector<T> input)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }

2
src/Numerics/LinearAlgebra/Single/DenseMatrix.cs

@ -1057,7 +1057,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override Svd<float> Svd(bool computeVectors) public override Svd<float> Svd(bool computeVectors)
{ {
return new DenseSvd(this, computeVectors); return DenseSvd.Create(this, computeVectors);
} }
public override Evd<float> Evd() public override Evd<float> Evd()

58
src/Numerics/LinearAlgebra/Single/Factorization/DenseSvd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,8 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.Properties;
using System; using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Single.Factorization namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{ {
@ -47,7 +47,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <remarks> /// <remarks>
/// The computation of the singular value decomposition is done at construction time. /// The computation of the singular value decomposition is done at construction time.
/// </remarks> /// </remarks>
public class DenseSvd : Svd public sealed class DenseSvd : Svd
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseSvd"/> class. This object will compute the /// Initializes a new instance of the <see cref="DenseSvd"/> class. This object will compute the
@ -57,19 +57,20 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param> /// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception> /// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception>
public DenseSvd(DenseMatrix matrix, bool computeVectors) public static DenseSvd Create(DenseMatrix matrix, bool computeVectors)
{ {
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
ComputeVectors = computeVectors;
var nm = Math.Min(matrix.RowCount, matrix.ColumnCount); var nm = Math.Min(matrix.RowCount, matrix.ColumnCount);
S = new DenseVector(nm); var s = new DenseVector(nm);
U = new DenseMatrix(matrix.RowCount); var u = new DenseMatrix(matrix.RowCount);
VT = new DenseMatrix(matrix.ColumnCount); var vt = new DenseMatrix(matrix.ColumnCount);
Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Values, matrix.RowCount, matrix.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values); Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix) matrix.Clone()).Values, matrix.RowCount, matrix.ColumnCount, s.Values, u.Values, vt.Values);
return new DenseSvd(s, u, vt, computeVectors);
}
DenseSvd(Vector<float> s, Matrix<float> u, Matrix<float> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
} }
/// <summary> /// <summary>
@ -79,18 +80,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
public override void Solve(Matrix<float> input, Matrix<float> result) public override void Solve(Matrix<float> input, Matrix<float> result)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -125,7 +115,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense matrices at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values, dinput.Values, input.ColumnCount, dresult.Values); Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector) S).Values, ((DenseMatrix) U).Values, ((DenseMatrix) VT).Values, dinput.Values, input.ColumnCount, dresult.Values);
} }
/// <summary> /// <summary>
@ -135,17 +125,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
public override void Solve(Vector<float> input, Vector<float> result) public override void Solve(Vector<float> input, Vector<float> result)
{ {
if (input == null) if (!VectorsComputed)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -175,7 +155,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment."); throw new NotSupportedException("Can only do SVD factorization for dense vectors at the moment.");
} }
Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector)S).Values, ((DenseMatrix)U).Values, ((DenseMatrix)VT).Values, dinput.Values, 1, dresult.Values); Control.LinearAlgebraProvider.SvdSolveFactored(U.RowCount, VT.ColumnCount, ((DenseVector) S).Values, ((DenseMatrix) U).Values, ((DenseMatrix) VT).Values, dinput.Values, 1, dresult.Values);
} }
} }
} }

11
src/Numerics/LinearAlgebra/Single/Factorization/Svd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,10 +28,10 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
using System; using System;
using System.Linq; using System.Linq;
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Single.Factorization namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{ {
@ -51,6 +51,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// </remarks> /// </remarks>
public abstract class Svd : Svd<float> public abstract class Svd : Svd<float>
{ {
protected Svd(Vector<float> s, Matrix<float> u, Matrix<float> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
}
/// <summary> /// <summary>
/// Gets the effective numerical matrix rank. /// Gets the effective numerical matrix rank.
/// </summary> /// </summary>

326
src/Numerics/LinearAlgebra/Single/Factorization/UserSvd.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2013 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -28,8 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using MathNet.Numerics.Properties;
using System; using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra.Single.Factorization namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{ {
@ -47,7 +47,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <remarks> /// <remarks>
/// The computation of the singular value decomposition is done at construction time. /// The computation of the singular value decomposition is done at construction time.
/// </remarks> /// </remarks>
public class UserSvd : Svd public sealed class UserSvd : Svd
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the /// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the
@ -57,20 +57,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param> /// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="NonConvergenceException"></exception> /// <exception cref="NonConvergenceException"></exception>
public UserSvd(Matrix<float> matrix, bool computeVectors) public static UserSvd Create(Matrix<float> matrix, bool computeVectors)
{ {
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
ComputeVectors = computeVectors;
var nm = Math.Min(matrix.RowCount + 1, matrix.ColumnCount); var nm = Math.Min(matrix.RowCount + 1, matrix.ColumnCount);
var matrixCopy = matrix.Clone(); var matrixCopy = matrix.Clone();
S = matrixCopy.CreateVector(nm); var s = matrixCopy.CreateVector(nm);
U = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount); var u = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount);
VT = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount); var vt = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount);
const int maxiter = 1000; const int maxiter = 1000;
var e = new float[matrixCopy.ColumnCount]; var e = new float[matrixCopy.ColumnCount];
@ -94,32 +88,32 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{ {
// Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l]. // Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l].
var xnorm = Dnrm2Column(matrixCopy, matrixCopy.RowCount, l, l); var xnorm = Dnrm2Column(matrixCopy, matrixCopy.RowCount, l, l);
S[l] = xnorm; s[l] = xnorm;
if (S[l] != 0.0) if (s[l] != 0.0)
{ {
if (matrixCopy.At(l, l) != 0.0) if (matrixCopy.At(l, l) != 0.0)
{ {
S[l] = Dsign(S[l], matrixCopy.At(l, l)); s[l] = Dsign(s[l], matrixCopy.At(l, l));
} }
DscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0f / S[l]); DscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0f/s[l]);
matrixCopy.At(l, l, (1.0f + matrixCopy.At(l, l))); matrixCopy.At(l, l, (1.0f + matrixCopy.At(l, l)));
} }
S[l] = -S[l]; s[l] = -s[l];
} }
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
if (l < nct) if (l < nct)
{ {
if (S[l] != 0.0) if (s[l] != 0.0)
{ {
// Apply the transformation. // Apply the transformation.
t = -Ddot(matrixCopy, matrixCopy.RowCount, l, j, l) / matrixCopy.At(l, l); t = -Ddot(matrixCopy, matrixCopy.RowCount, l, j, l)/matrixCopy.At(l, l);
for (var ii = l; ii < matrixCopy.RowCount; ii++) for (var ii = l; ii < matrixCopy.RowCount; ii++)
{ {
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t * matrixCopy.At(ii, l))); matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t*matrixCopy.At(ii, l)));
} }
} }
} }
@ -129,12 +123,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
e[j] = matrixCopy.At(l, j); e[j] = matrixCopy.At(l, j);
} }
if (ComputeVectors && l < nct) if (computeVectors && l < nct)
{ {
// Place the transformation in u for subsequent back multiplication. // Place the transformation in u for subsequent back multiplication.
for (i = l; i < matrixCopy.RowCount; i++) for (i = l; i < matrixCopy.RowCount; i++)
{ {
U.At(i, l, matrixCopy.At(i, l)); u.At(i, l, matrixCopy.At(i, l));
} }
} }
@ -153,7 +147,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
e[l] = Dsign(e[l], e[lp1]); e[l] = Dsign(e[l], e[lp1]);
} }
DscalVector(e, lp1, 1.0f / e[l]); DscalVector(e, lp1, 1.0f/e[l]);
e[lp1] = 1.0f + e[lp1]; e[lp1] = 1.0f + e[lp1];
} }
@ -170,26 +164,26 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{ {
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
{ {
work[ii] += e[j] * matrixCopy.At(ii, j); work[ii] += e[j]*matrixCopy.At(ii, j);
} }
} }
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
var ww = -e[j] / e[lp1]; var ww = -e[j]/e[lp1];
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
{ {
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww * work[ii])); matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww*work[ii]));
} }
} }
} }
if (ComputeVectors) if (computeVectors)
{ {
// Place the transformation in v for subsequent back multiplication. // Place the transformation in v for subsequent back multiplication.
for (i = lp1; i < matrixCopy.ColumnCount; i++) for (i = lp1; i < matrixCopy.ColumnCount; i++)
{ {
VT.At(i, l, e[i]); vt.At(i, l, e[i]);
} }
} }
} }
@ -200,12 +194,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
var nrtp1 = nrt + 1; var nrtp1 = nrt + 1;
if (nct < matrixCopy.ColumnCount) if (nct < matrixCopy.ColumnCount)
{ {
S[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1)); s[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1));
} }
if (matrixCopy.RowCount < m) if (matrixCopy.RowCount < m)
{ {
S[m - 1] = 0.0f; s[m - 1] = 0.0f;
} }
if (nrtp1 < m) if (nrtp1 < m)
@ -216,52 +210,52 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
e[m - 1] = 0.0f; e[m - 1] = 0.0f;
// If required, generate u. // If required, generate u.
if (ComputeVectors) if (computeVectors)
{ {
for (j = nctp1 - 1; j < ncu; j++) for (j = nctp1 - 1; j < ncu; j++)
{ {
for (i = 0; i < matrixCopy.RowCount; i++) for (i = 0; i < matrixCopy.RowCount; i++)
{ {
U.At(i, j, 0.0f); u.At(i, j, 0.0f);
} }
U.At(j, j, 1.0f); u.At(j, j, 1.0f);
} }
for (l = nct - 1; l >= 0; l--) for (l = nct - 1; l >= 0; l--)
{ {
if (S[l] != 0.0) if (s[l] != 0.0)
{ {
for (j = l + 1; j < ncu; j++) for (j = l + 1; j < ncu; j++)
{ {
t = -Ddot(U, matrixCopy.RowCount, l, j, l) / U.At(l, l); t = -Ddot(u, matrixCopy.RowCount, l, j, l)/u.At(l, l);
for (var ii = l; ii < matrixCopy.RowCount; ii++) for (var ii = l; ii < matrixCopy.RowCount; ii++)
{ {
U.At(ii, j, U.At(ii, j) + (t * U.At(ii, l))); u.At(ii, j, u.At(ii, j) + (t*u.At(ii, l)));
} }
} }
DscalColumn(U, matrixCopy.RowCount, l, l, -1.0f); DscalColumn(u, matrixCopy.RowCount, l, l, -1.0f);
U.At(l, l, 1.0f + U.At(l, l)); u.At(l, l, 1.0f + u.At(l, l));
for (i = 0; i < l; i++) for (i = 0; i < l; i++)
{ {
U.At(i, l, 0.0f); u.At(i, l, 0.0f);
} }
} }
else else
{ {
for (i = 0; i < matrixCopy.RowCount; i++) for (i = 0; i < matrixCopy.RowCount; i++)
{ {
U.At(i, l, 0.0f); u.At(i, l, 0.0f);
} }
U.At(l, l, 1.0f); u.At(l, l, 1.0f);
} }
} }
} }
// If it is required, generate v. // If it is required, generate v.
if (ComputeVectors) if (computeVectors)
{ {
for (l = matrixCopy.ColumnCount - 1; l >= 0; l--) for (l = matrixCopy.ColumnCount - 1; l >= 0; l--)
{ {
@ -272,10 +266,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{ {
for (j = lp1; j < matrixCopy.ColumnCount; j++) for (j = lp1; j < matrixCopy.ColumnCount; j++)
{ {
t = -Ddot(VT, matrixCopy.ColumnCount, l, j, lp1) / VT.At(lp1, l); t = -Ddot(vt, matrixCopy.ColumnCount, l, j, lp1)/vt.At(lp1, l);
for (var ii = l; ii < matrixCopy.ColumnCount; ii++) for (var ii = l; ii < matrixCopy.ColumnCount; ii++)
{ {
VT.At(ii, j, VT.At(ii, j) + (t * VT.At(ii, l))); vt.At(ii, j, vt.At(ii, j) + (t*vt.At(ii, l)));
} }
} }
} }
@ -283,10 +277,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
for (i = 0; i < matrixCopy.ColumnCount; i++) for (i = 0; i < matrixCopy.ColumnCount; i++)
{ {
VT.At(i, l, 0.0f); vt.At(i, l, 0.0f);
} }
VT.At(l, l, 1.0f); vt.At(l, l, 1.0f);
} }
} }
@ -294,19 +288,19 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
for (i = 0; i < m; i++) for (i = 0; i < m; i++)
{ {
float r; float r;
if (S[i] != 0.0) if (s[i] != 0.0)
{ {
t = S[i]; t = s[i];
r = S[i] / t; r = s[i]/t;
S[i] = t; s[i] = t;
if (i < m - 1) if (i < m - 1)
{ {
e[i] = e[i] / r; e[i] = e[i]/r;
} }
if (ComputeVectors) if (computeVectors)
{ {
DscalColumn(U, matrixCopy.RowCount, i, 0, r); DscalColumn(u, matrixCopy.RowCount, i, 0, r);
} }
} }
@ -319,12 +313,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
if (e[i] != 0.0) if (e[i] != 0.0)
{ {
t = e[i]; t = e[i];
r = t / e[i]; r = t/e[i];
e[i] = t; e[i] = t;
S[i + 1] = S[i + 1] * r; s[i + 1] = s[i + 1]*r;
if (ComputeVectors) if (computeVectors)
{ {
DscalColumn(VT, matrixCopy.ColumnCount, i + 1, 0, r); DscalColumn(vt, matrixCopy.ColumnCount, i + 1, 0, r);
} }
} }
} }
@ -352,7 +346,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
float test; float test;
for (l = m - 2; l >= 0; l--) for (l = m - 2; l >= 0; l--)
{ {
test = Math.Abs(S[l]) + Math.Abs(S[l + 1]); test = Math.Abs(s[l]) + Math.Abs(s[l + 1]);
ztest = test + Math.Abs(e[l]); ztest = test + Math.Abs(e[l]);
if (ztest.AlmostEqualInDecimalPlaces(test, 7)) if (ztest.AlmostEqualInDecimalPlaces(test, 7))
{ {
@ -382,10 +376,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
test = test + Math.Abs(e[ls - 1]); test = test + Math.Abs(e[ls - 1]);
} }
ztest = test + Math.Abs(S[ls]); ztest = test + Math.Abs(s[ls]);
if (ztest.AlmostEqualInDecimalPlaces(test, 7)) if (ztest.AlmostEqualInDecimalPlaces(test, 7))
{ {
S[ls] = 0.0f; s[ls] = 0.0f;
break; break;
} }
} }
@ -414,7 +408,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
float cs; float cs;
switch (kase) switch (kase)
{ {
// Deflate negligible VectorS[m]. // Deflate negligible VectorS[m].
case 1: case 1:
f = e[m - 2]; f = e[m - 2];
e[m - 2] = 0.0f; e[m - 2] = 0.0f;
@ -422,72 +416,72 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
for (var kk = l; kk < m - 1; kk++) for (var kk = l; kk < m - 1; kk++)
{ {
k = m - 2 - kk + l; k = m - 2 - kk + l;
t1 = S[k]; t1 = s[k];
Drotg(ref t1, ref f, out cs, out sn); Drotg(ref t1, ref f, out cs, out sn);
S[k] = t1; s[k] = t1;
if (k != l) if (k != l)
{ {
f = -sn * e[k - 1]; f = -sn*e[k - 1];
e[k - 1] = cs * e[k - 1]; e[k - 1] = cs*e[k - 1];
} }
if (ComputeVectors) if (computeVectors)
{ {
Drot(VT, matrixCopy.ColumnCount, k, m - 1, cs, sn); Drot(vt, matrixCopy.ColumnCount, k, m - 1, cs, sn);
} }
} }
break; break;
// Split at negligible VectorS[l]. // Split at negligible VectorS[l].
case 2: case 2:
f = e[l - 1]; f = e[l - 1];
e[l - 1] = 0.0f; e[l - 1] = 0.0f;
for (k = l; k < m; k++) for (k = l; k < m; k++)
{ {
t1 = S[k]; t1 = s[k];
Drotg(ref t1, ref f, out cs, out sn); Drotg(ref t1, ref f, out cs, out sn);
S[k] = t1; s[k] = t1;
f = -sn * e[k]; f = -sn*e[k];
e[k] = cs * e[k]; e[k] = cs*e[k];
if (ComputeVectors) if (computeVectors)
{ {
Drot(U, matrixCopy.RowCount, k, l - 1, cs, sn); Drot(u, matrixCopy.RowCount, k, l - 1, cs, sn);
} }
} }
break; break;
// Perform one qr step. // Perform one qr step.
case 3: case 3:
// Calculate the shift. // Calculate the shift.
var scale = 0.0f; var scale = 0.0f;
scale = Math.Max(scale, Math.Abs(S[m - 1])); scale = Math.Max(scale, Math.Abs(s[m - 1]));
scale = Math.Max(scale, Math.Abs(S[m - 2])); scale = Math.Max(scale, Math.Abs(s[m - 2]));
scale = Math.Max(scale, Math.Abs(e[m - 2])); scale = Math.Max(scale, Math.Abs(e[m - 2]));
scale = Math.Max(scale, Math.Abs(S[l])); scale = Math.Max(scale, Math.Abs(s[l]));
scale = Math.Max(scale, Math.Abs(e[l])); scale = Math.Max(scale, Math.Abs(e[l]));
var sm = S[m - 1] / scale; var sm = s[m - 1]/scale;
var smm1 = S[m - 2] / scale; var smm1 = s[m - 2]/scale;
var emm1 = e[m - 2] / scale; var emm1 = e[m - 2]/scale;
var sl = S[l] / scale; var sl = s[l]/scale;
var el = e[l] / scale; var el = e[l]/scale;
var b = (((smm1 + sm) * (smm1 - sm)) + (emm1 * emm1)) / 2.0f; var b = (((smm1 + sm)*(smm1 - sm)) + (emm1*emm1))/2.0f;
var c = (sm * emm1) * (sm * emm1); var c = (sm*emm1)*(sm*emm1);
var shift = 0.0f; var shift = 0.0f;
if (b != 0.0 || c != 0.0) if (b != 0.0 || c != 0.0)
{ {
shift = (float)Math.Sqrt((b * b) + c); shift = (float) Math.Sqrt((b*b) + c);
if (b < 0.0) if (b < 0.0)
{ {
shift = -shift; shift = -shift;
} }
shift = c / (b + shift); shift = c/(b + shift);
} }
f = ((sl + sm) * (sl - sm)) + shift; f = ((sl + sm)*(sl - sm)) + shift;
var g = sl * el; var g = sl*el;
// Chase zeros. // Chase zeros.
for (k = l; k < m - 1; k++) for (k = l; k < m - 1; k++)
@ -498,24 +492,24 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
e[k - 1] = f; e[k - 1] = f;
} }
f = (cs * S[k]) + (sn * e[k]); f = (cs*s[k]) + (sn*e[k]);
e[k] = (cs * e[k]) - (sn * S[k]); e[k] = (cs*e[k]) - (sn*s[k]);
g = sn * S[k + 1]; g = sn*s[k + 1];
S[k + 1] = cs * S[k + 1]; s[k + 1] = cs*s[k + 1];
if (ComputeVectors) if (computeVectors)
{ {
Drot(VT, matrixCopy.ColumnCount, k, k + 1, cs, sn); Drot(vt, matrixCopy.ColumnCount, k, k + 1, cs, sn);
} }
Drotg(ref f, ref g, out cs, out sn); Drotg(ref f, ref g, out cs, out sn);
S[k] = f; s[k] = f;
f = (cs * e[k]) + (sn * S[k + 1]); f = (cs*e[k]) + (sn*s[k + 1]);
S[k + 1] = (-sn * e[k]) + (cs * S[k + 1]); s[k + 1] = (-sn*e[k]) + (cs*s[k + 1]);
g = sn * e[k + 1]; g = sn*e[k + 1];
e[k + 1] = cs * e[k + 1]; e[k + 1] = cs*e[k + 1];
if (ComputeVectors && k < matrixCopy.RowCount) if (computeVectors && k < matrixCopy.RowCount)
{ {
Drot(U, matrixCopy.RowCount, k, k + 1, cs, sn); Drot(u, matrixCopy.RowCount, k, k + 1, cs, sn);
} }
} }
@ -523,37 +517,37 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
iter = iter + 1; iter = iter + 1;
break; break;
// Convergence. // Convergence.
case 4: case 4:
// Make the singular value positive // Make the singular value positive
if (S[l] < 0.0) if (s[l] < 0.0)
{ {
S[l] = -S[l]; s[l] = -s[l];
if (ComputeVectors) if (computeVectors)
{ {
DscalColumn(VT, matrixCopy.ColumnCount, l, 0, -1.0f); DscalColumn(vt, matrixCopy.ColumnCount, l, 0, -1.0f);
} }
} }
// Order the singular value. // Order the singular value.
while (l != mn - 1) while (l != mn - 1)
{ {
if (S[l] >= S[l + 1]) if (s[l] >= s[l + 1])
{ {
break; break;
} }
t = S[l]; t = s[l];
S[l] = S[l + 1]; s[l] = s[l + 1];
S[l + 1] = t; s[l + 1] = t;
if (ComputeVectors && l < matrixCopy.ColumnCount) if (computeVectors && l < matrixCopy.ColumnCount)
{ {
Dswap(VT, matrixCopy.ColumnCount, l, l + 1); Dswap(vt, matrixCopy.ColumnCount, l, l + 1);
} }
if (ComputeVectors && l < matrixCopy.RowCount) if (computeVectors && l < matrixCopy.RowCount)
{ {
Dswap(U, matrixCopy.RowCount, l, l + 1); Dswap(u, matrixCopy.RowCount, l, l + 1);
} }
l = l + 1; l = l + 1;
@ -565,9 +559,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
} }
} }
if (ComputeVectors) if (computeVectors)
{ {
VT = VT.Transpose(); vt = vt.Transpose();
} }
// Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses // Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses
@ -579,11 +573,18 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
var tmp = matrixCopy.CreateVector(nm); var tmp = matrixCopy.CreateVector(nm);
for (i = 0; i < nm; i++) for (i = 0; i < nm; i++)
{ {
tmp[i] = S[i]; tmp[i] = s[i];
} }
S = tmp; s = tmp;
} }
return new UserSvd(s, u, vt, computeVectors);
}
UserSvd(Vector<float> s, Matrix<float> u, Matrix<float> vt, bool vectorsComputed)
: base(s, u, vt, vectorsComputed)
{
} }
/// <summary> /// <summary>
@ -592,9 +593,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="z1">Double value z1</param> /// <param name="z1">Double value z1</param>
/// <param name="z2">Double value z2</param> /// <param name="z2">Double value z2</param>
/// <returns>Result multiplication of signum function and absolute value</returns> /// <returns>Result multiplication of signum function and absolute value</returns>
private static float Dsign(float z1, float z2) static float Dsign(float z1, float z2)
{ {
return Math.Abs(z1) * (z2 / Math.Abs(z2)); return Math.Abs(z1)*(z2/Math.Abs(z2));
} }
/// <summary> /// <summary>
@ -604,7 +605,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="rowCount">The number of rows in <paramref name="a"/></param> /// <param name="rowCount">The number of rows in <paramref name="a"/></param>
/// <param name="columnA">Column A index to swap</param> /// <param name="columnA">Column A index to swap</param>
/// <param name="columnB">Column B index to swap</param> /// <param name="columnB">Column B index to swap</param>
private static void Dswap(Matrix<float> a, int rowCount, int columnA, int columnB) static void Dswap(Matrix<float> a, int rowCount, int columnA, int columnB)
{ {
for (var i = 0; i < rowCount; i++) for (var i = 0; i < rowCount; i++)
{ {
@ -622,11 +623,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="column">Column to scale</param> /// <param name="column">Column to scale</param>
/// <param name="rowStart">Row to scale from</param> /// <param name="rowStart">Row to scale from</param>
/// <param name="z">Scale value</param> /// <param name="z">Scale value</param>
private static void DscalColumn(Matrix<float> a, int rowCount, int column, int rowStart, float z) static void DscalColumn(Matrix<float> a, int rowCount, int column, int rowStart, float z)
{ {
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
a.At(i, column, a.At(i, column) * z); a.At(i, column, a.At(i, column)*z);
} }
} }
@ -636,11 +637,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="a">Source vector</param> /// <param name="a">Source vector</param>
/// <param name="start">Row to scale from</param> /// <param name="start">Row to scale from</param>
/// <param name="z">Scale value</param> /// <param name="z">Scale value</param>
private static void DscalVector(float[] a, int start, float z) static void DscalVector(float[] a, int start, float z)
{ {
for (var i = start; i < a.Length; i++) for (var i = start; i < a.Length; i++)
{ {
a[i] = a[i] * z; a[i] = a[i]*z;
} }
} }
@ -653,7 +654,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="c">Contains the parameter c associated with the Givens rotation</param> /// <param name="c">Contains the parameter c associated with the Givens rotation</param>
/// <param name="s">Contains the parameter s associated with the Givens rotation</param> /// <param name="s">Contains the parameter s associated with the Givens rotation</param>
/// <remarks>This is equivalent to the DROTG LAPACK routine.</remarks> /// <remarks>This is equivalent to the DROTG LAPACK routine.</remarks>
private static void Drotg(ref float da, ref float db, out float c, out float s) static void Drotg(ref float da, ref float db, out float c, out float s)
{ {
float r, z; float r, z;
@ -675,16 +676,16 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
} }
else else
{ {
var sda = da / scale; var sda = da/scale;
var sdb = db / scale; var sdb = db/scale;
r = scale * (float)Math.Sqrt((sda * sda) + (sdb * sdb)); r = scale*(float) Math.Sqrt((sda*sda) + (sdb*sdb));
if (roe < 0.0) if (roe < 0.0)
{ {
r = -r; r = -r;
} }
c = da / r; c = da/r;
s = db / r; s = db/r;
z = 1.0f; z = 1.0f;
if (absda > absdb) if (absda > absdb)
{ {
@ -693,7 +694,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
if (absdb >= absda && c != 0.0) if (absdb >= absda && c != 0.0)
{ {
z = 1.0f / c; z = 1.0f/c;
} }
} }
@ -709,15 +710,15 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="column">Column index</param> /// <param name="column">Column index</param>
/// <param name="rowStart">Start row index</param> /// <param name="rowStart">Start row index</param>
/// <returns>Norm2 (Euclidean norm) of the column</returns> /// <returns>Norm2 (Euclidean norm) of the column</returns>
private static float Dnrm2Column(Matrix<float> a, int rowCount, int column, int rowStart) static float Dnrm2Column(Matrix<float> a, int rowCount, int column, int rowStart)
{ {
float s = 0; float s = 0;
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
s += a.At(i, column) * a.At(i, column); s += a.At(i, column)*a.At(i, column);
} }
return (float)Math.Sqrt(s); return (float) Math.Sqrt(s);
} }
/// <summary> /// <summary>
@ -726,15 +727,15 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="a">Source vector</param> /// <param name="a">Source vector</param>
/// <param name="rowStart">Start index</param> /// <param name="rowStart">Start index</param>
/// <returns>Norm2 (Euclidean norm) of the vector</returns> /// <returns>Norm2 (Euclidean norm) of the vector</returns>
private static float Dnrm2Vector(float[] a, int rowStart) static float Dnrm2Vector(float[] a, int rowStart)
{ {
float s = 0; float s = 0;
for (var i = rowStart; i < a.Length; i++) for (var i = rowStart; i < a.Length; i++)
{ {
s += a[i] * a[i]; s += a[i]*a[i];
} }
return (float)Math.Sqrt(s); return (float) Math.Sqrt(s);
} }
/// <summary> /// <summary>
@ -746,12 +747,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="columnB">Index of column B</param> /// <param name="columnB">Index of column B</param>
/// <param name="rowStart">Starting row index</param> /// <param name="rowStart">Starting row index</param>
/// <returns>Dot product value</returns> /// <returns>Dot product value</returns>
private static float Ddot(Matrix<float> a, int rowCount, int columnA, int columnB, int rowStart) static float Ddot(Matrix<float> a, int rowCount, int columnA, int columnB, int rowStart)
{ {
var z = 0.0f; var z = 0.0f;
for (var i = rowStart; i < rowCount; i++) for (var i = rowStart; i < rowCount; i++)
{ {
z += a.At(i, columnB) * a.At(i, columnA); z += a.At(i, columnB)*a.At(i, columnA);
} }
return z; return z;
@ -767,17 +768,17 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="columnB">Index of column B</param> /// <param name="columnB">Index of column B</param>
/// <param name="c">Scalar "c" value</param> /// <param name="c">Scalar "c" value</param>
/// <param name="s">Scalar "s" value</param> /// <param name="s">Scalar "s" value</param>
private static void Drot(Matrix<float> a, int rowCount, int columnA, int columnB, float c, float s) static void Drot(Matrix<float> a, int rowCount, int columnA, int columnB, float c, float s)
{ {
for (var i = 0; i < rowCount; i++) for (var i = 0; i < rowCount; i++)
{ {
var z = (c * a.At(i, columnA)) + (s * a.At(i, columnB)); var z = (c*a.At(i, columnA)) + (s*a.At(i, columnB));
var tmp = (c * a.At(i, columnB)) - (s * a.At(i, columnA)); var tmp = (c*a.At(i, columnB)) - (s*a.At(i, columnA));
a.At(i, columnB, tmp); a.At(i, columnB, tmp);
a.At(i, columnA, z); a.At(i, columnA, z);
} }
} }
/// <summary> /// <summary>
/// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized. /// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized.
/// </summary> /// </summary>
@ -785,18 +786,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
public override void Solve(Matrix<float> input, Matrix<float> result) public override void Solve(Matrix<float> input, Matrix<float> result)
{ {
// Check for proper arguments. if (!VectorsComputed)
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -833,7 +823,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{ {
for (var i = 0; i < U.RowCount; i++) for (var i = 0; i < U.RowCount; i++)
{ {
value += U.At(i, j) * input.At(i, k); value += U.At(i, j)*input.At(i, k);
} }
value /= S[j]; value /= S[j];
@ -847,7 +837,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
float value = 0; float value = 0;
for (var i = 0; i < VT.ColumnCount; i++) for (var i = 0; i < VT.ColumnCount; i++)
{ {
value += VT.At(i, j) * tmp[i]; value += VT.At(i, j)*tmp[i];
} }
result.At(j, k, value); result.At(j, k, value);
@ -862,17 +852,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param> /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
public override void Solve(Vector<float> input, Vector<float> result) public override void Solve(Vector<float> input, Vector<float> result)
{ {
if (input == null) if (!VectorsComputed)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (!ComputeVectors)
{ {
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
} }
@ -900,7 +880,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{ {
for (var i = 0; i < U.RowCount; i++) for (var i = 0; i < U.RowCount; i++)
{ {
value += U.At(i, j) * input[i]; value += U.At(i, j)*input[i];
} }
value /= S[j]; value /= S[j];
@ -914,7 +894,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
value = 0; value = 0;
for (int i = 0; i < VT.ColumnCount; i++) for (int i = 0; i < VT.ColumnCount; i++)
{ {
value += VT.At(i, j) * tmp[i]; value += VT.At(i, j)*tmp[i];
} }
result[j] = value; result[j] = value;

2
src/Numerics/LinearAlgebra/Single/Matrix.cs

@ -481,7 +481,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
public override Svd<float> Svd(bool computeVectors) public override Svd<float> Svd(bool computeVectors)
{ {
return new UserSvd(this, computeVectors); return UserSvd.Create(this, computeVectors);
} }
public override Evd<float> Evd() public override Evd<float> Evd()

17
src/UnitTests/LinearAlgebraTests/Complex/Factorization/SvdTests.cs

@ -24,10 +24,10 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using System;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Complex; using MathNet.Numerics.LinearAlgebra.Complex;
using MathNet.Numerics.LinearAlgebra.Complex.Factorization;
using NUnit.Framework; using NUnit.Framework;
using System;
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
{ {
@ -38,15 +38,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
/// </summary> /// </summary>
public class SvdTests public class SvdTests
{ {
/// <summary>
/// Constructor with <c>null</c> throws <c>ArgumentNullException</c>.
/// </summary>
[Test]
public void ConstructorNull()
{
Assert.Throws<ArgumentNullException>(() => new DenseSvd(null, true));
}
/// <summary> /// <summary>
/// Can factorize identity matrix. /// Can factorize identity matrix.
/// </summary> /// </summary>
@ -60,7 +51,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
var factorSvd = matrixI.Svd(true); var factorSvd = matrixI.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
Assert.AreEqual(matrixI.RowCount, u.RowCount); Assert.AreEqual(matrixI.RowCount, u.RowCount);
Assert.AreEqual(matrixI.RowCount, u.ColumnCount); Assert.AreEqual(matrixI.RowCount, u.ColumnCount);
@ -97,7 +88,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
var factorSvd = matrixA.Svd(true); var factorSvd = matrixA.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
// Make sure the U has the right dimensions. // Make sure the U has the right dimensions.
Assert.AreEqual(row, u.RowCount); Assert.AreEqual(row, u.RowCount);

20
src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserSvdTests.cs

@ -24,27 +24,19 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using System;
using MathNet.Numerics.LinearAlgebra;
using NUnit.Framework;
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
{ {
using System;
using System.Numerics; using System.Numerics;
using LinearAlgebra.Complex.Factorization;
using NUnit.Framework;
/// <summary> /// <summary>
/// Svd factorization tests for a user matrix. /// Svd factorization tests for a user matrix.
/// </summary> /// </summary>
public class UserSvdTests public class UserSvdTests
{ {
/// <summary>
/// Constructor with <c>null</c> throws <c>ArgumentNullException</c>.
/// </summary>
[Test]
public void ConstructorNull()
{
Assert.Throws<ArgumentNullException>(() => new UserSvd(null, true));
}
/// <summary> /// <summary>
/// Can factorize identity matrix. /// Can factorize identity matrix.
/// </summary> /// </summary>
@ -58,7 +50,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
var factorSvd = matrixI.Svd(true); var factorSvd = matrixI.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
Assert.AreEqual(matrixI.RowCount, u.RowCount); Assert.AreEqual(matrixI.RowCount, u.RowCount);
Assert.AreEqual(matrixI.RowCount, u.ColumnCount); Assert.AreEqual(matrixI.RowCount, u.ColumnCount);
@ -95,7 +87,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
var factorSvd = matrixA.Svd(true); var factorSvd = matrixA.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
// Make sure the U has the right dimensions. // Make sure the U has the right dimensions.
Assert.AreEqual(row, u.RowCount); Assert.AreEqual(row, u.RowCount);

17
src/UnitTests/LinearAlgebraTests/Complex32/Factorization/SvdTests.cs

@ -24,10 +24,10 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using System;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Complex32; using MathNet.Numerics.LinearAlgebra.Complex32;
using MathNet.Numerics.LinearAlgebra.Complex32.Factorization;
using NUnit.Framework; using NUnit.Framework;
using System;
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
{ {
@ -38,15 +38,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
/// </summary> /// </summary>
public class SvdTests public class SvdTests
{ {
/// <summary>
/// Constructor with <c>null</c> throws <c>ArgumentNullException</c>.
/// </summary>
[Test]
public void ConstructorNull()
{
Assert.Throws<ArgumentNullException>(() => new DenseSvd(null, true));
}
/// <summary> /// <summary>
/// Can factorize identity matrix. /// Can factorize identity matrix.
/// </summary> /// </summary>
@ -60,7 +51,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
var factorSvd = matrixI.Svd(true); var factorSvd = matrixI.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
Assert.AreEqual(matrixI.RowCount, u.RowCount); Assert.AreEqual(matrixI.RowCount, u.RowCount);
Assert.AreEqual(matrixI.RowCount, u.ColumnCount); Assert.AreEqual(matrixI.RowCount, u.ColumnCount);
@ -97,7 +88,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
var factorSvd = matrixA.Svd(true); var factorSvd = matrixA.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
// Make sure the U has the right dimensions. // Make sure the U has the right dimensions.
Assert.AreEqual(row, u.RowCount); Assert.AreEqual(row, u.RowCount);

22
src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserSvdTests.cs

@ -24,27 +24,19 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using System;
using MathNet.Numerics.LinearAlgebra;
using NUnit.Framework;
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
{ {
using System; using Numerics;
using LinearAlgebra.Complex32.Factorization;
using NUnit.Framework;
using Complex32 = Numerics.Complex32;
/// <summary> /// <summary>
/// Svd factorization tests for a user matrix. /// Svd factorization tests for a user matrix.
/// </summary> /// </summary>
public class UserSvdTests public class UserSvdTests
{ {
/// <summary>
/// Constructor with <c>null</c> throws <c>ArgumentNullException</c>.
/// </summary>
[Test]
public void ConstructorNull()
{
Assert.Throws<ArgumentNullException>(() => new UserSvd(null, true));
}
/// <summary> /// <summary>
/// Can factorize identity matrix. /// Can factorize identity matrix.
/// </summary> /// </summary>
@ -58,7 +50,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
var factorSvd = matrixI.Svd(true); var factorSvd = matrixI.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
Assert.AreEqual(matrixI.RowCount, u.RowCount); Assert.AreEqual(matrixI.RowCount, u.RowCount);
Assert.AreEqual(matrixI.RowCount, u.ColumnCount); Assert.AreEqual(matrixI.RowCount, u.ColumnCount);
@ -95,7 +87,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
var factorSvd = matrixA.Svd(true); var factorSvd = matrixA.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
// Make sure the U has the right dimensions. // Make sure the U has the right dimensions.
Assert.AreEqual(row, u.RowCount); Assert.AreEqual(row, u.RowCount);

17
src/UnitTests/LinearAlgebraTests/Double/Factorization/SvdTests.cs

@ -24,10 +24,10 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using System;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Double; using MathNet.Numerics.LinearAlgebra.Double;
using MathNet.Numerics.LinearAlgebra.Double.Factorization;
using NUnit.Framework; using NUnit.Framework;
using System;
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
{ {
@ -36,15 +36,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
/// </summary> /// </summary>
public class SvdTests public class SvdTests
{ {
/// <summary>
/// Constructor with <c>null</c> throws <c>ArgumentNullException</c>.
/// </summary>
[Test]
public void ConstructorNull()
{
Assert.Throws<ArgumentNullException>(() => new DenseSvd(null, true));
}
/// <summary> /// <summary>
/// Can factorize identity matrix. /// Can factorize identity matrix.
/// </summary> /// </summary>
@ -58,7 +49,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
var factorSvd = matrixI.Svd(true); var factorSvd = matrixI.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
Assert.AreEqual(matrixI.RowCount, u.RowCount); Assert.AreEqual(matrixI.RowCount, u.RowCount);
Assert.AreEqual(matrixI.RowCount, u.ColumnCount); Assert.AreEqual(matrixI.RowCount, u.ColumnCount);
@ -95,7 +86,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
var factorSvd = matrixA.Svd(true); var factorSvd = matrixA.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
// Make sure the U has the right dimensions. // Make sure the U has the right dimensions.
Assert.AreEqual(row, u.RowCount); Assert.AreEqual(row, u.RowCount);

21
src/UnitTests/LinearAlgebraTests/Double/Factorization/UserSvdTests.cs

@ -24,26 +24,17 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using System;
using MathNet.Numerics.LinearAlgebra;
using NUnit.Framework;
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
{ {
using System;
using LinearAlgebra.Double.Factorization;
using NUnit.Framework;
/// <summary> /// <summary>
/// Svd factorization tests for a user matrix. /// Svd factorization tests for a user matrix.
/// </summary> /// </summary>
public class UserSvdTests public class UserSvdTests
{ {
/// <summary>
/// Constructor with <c>null</c> throws <c>ArgumentNullException</c>.
/// </summary>
[Test]
public void ConstructorNull()
{
Assert.Throws<ArgumentNullException>(() => new UserSvd(null, true));
}
/// <summary> /// <summary>
/// Can factorize identity matrix. /// Can factorize identity matrix.
/// </summary> /// </summary>
@ -57,7 +48,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
var factorSvd = matrixI.Svd(true); var factorSvd = matrixI.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
Assert.AreEqual(matrixI.RowCount, u.RowCount); Assert.AreEqual(matrixI.RowCount, u.RowCount);
Assert.AreEqual(matrixI.RowCount, u.ColumnCount); Assert.AreEqual(matrixI.RowCount, u.ColumnCount);
@ -94,7 +85,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
var factorSvd = matrixA.Svd(true); var factorSvd = matrixA.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
// Make sure the U has the right dimensions. // Make sure the U has the right dimensions.
Assert.AreEqual(row, u.RowCount); Assert.AreEqual(row, u.RowCount);

17
src/UnitTests/LinearAlgebraTests/Single/Factorization/SvdTests.cs

@ -24,10 +24,10 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using System;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Single; using MathNet.Numerics.LinearAlgebra.Single;
using MathNet.Numerics.LinearAlgebra.Single.Factorization;
using NUnit.Framework; using NUnit.Framework;
using System;
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
{ {
@ -36,15 +36,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
/// </summary> /// </summary>
public class SvdTests public class SvdTests
{ {
/// <summary>
/// Constructor with <c>null</c> throws <c>ArgumentNullException</c>.
/// </summary>
[Test]
public void ConstructorNull()
{
Assert.Throws<ArgumentNullException>(() => new DenseSvd(null, true));
}
/// <summary> /// <summary>
/// Can factorize identity matrix. /// Can factorize identity matrix.
/// </summary> /// </summary>
@ -58,7 +49,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
var factorSvd = matrixI.Svd(true); var factorSvd = matrixI.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
Assert.AreEqual(matrixI.RowCount, u.RowCount); Assert.AreEqual(matrixI.RowCount, u.RowCount);
Assert.AreEqual(matrixI.RowCount, u.ColumnCount); Assert.AreEqual(matrixI.RowCount, u.ColumnCount);
@ -95,7 +86,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
var factorSvd = matrixA.Svd(true); var factorSvd = matrixA.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
// Make sure the U has the right dimensions. // Make sure the U has the right dimensions.
Assert.AreEqual(row, u.RowCount); Assert.AreEqual(row, u.RowCount);

21
src/UnitTests/LinearAlgebraTests/Single/Factorization/UserSvdTests.cs

@ -24,26 +24,17 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
using System;
using MathNet.Numerics.LinearAlgebra;
using NUnit.Framework;
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
{ {
using System;
using LinearAlgebra.Single.Factorization;
using NUnit.Framework;
/// <summary> /// <summary>
/// Svd factorization tests for a user matrix. /// Svd factorization tests for a user matrix.
/// </summary> /// </summary>
public class UserSvdTests public class UserSvdTests
{ {
/// <summary>
/// Constructor with <c>null</c> throws <c>ArgumentNullException</c>.
/// </summary>
[Test]
public void ConstructorNull()
{
Assert.Throws<ArgumentNullException>(() => new UserSvd(null, true));
}
/// <summary> /// <summary>
/// Can factorize identity matrix. /// Can factorize identity matrix.
/// </summary> /// </summary>
@ -57,7 +48,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
var factorSvd = matrixI.Svd(true); var factorSvd = matrixI.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
Assert.AreEqual(matrixI.RowCount, u.RowCount); Assert.AreEqual(matrixI.RowCount, u.RowCount);
Assert.AreEqual(matrixI.RowCount, u.ColumnCount); Assert.AreEqual(matrixI.RowCount, u.ColumnCount);
@ -94,7 +85,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
var factorSvd = matrixA.Svd(true); var factorSvd = matrixA.Svd(true);
var u = factorSvd.U; var u = factorSvd.U;
var vt = factorSvd.VT; var vt = factorSvd.VT;
var w = factorSvd.W(); var w = factorSvd.W;
// Make sure the U has the right dimensions. // Make sure the U has the right dimensions.
Assert.AreEqual(row, u.RowCount); Assert.AreEqual(row, u.RowCount);

Loading…
Cancel
Save