Browse Source

fixed QR thin solve bug

native QR full now returns the full Q matrix
v2
Marcus Cuda 14 years ago
parent
commit
b22b5a20aa
  1. 2
      src/NativeWrappers/MKL/lapack.cpp
  2. 3
      src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Common.cs
  3. 5
      src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs
  4. 1
      src/Numerics/LinearAlgebra/Complex/Factorization/UserQR.cs
  5. 5
      src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs
  6. 1
      src/Numerics/LinearAlgebra/Complex32/Factorization/UserQR.cs
  7. 5
      src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs
  8. 1
      src/Numerics/LinearAlgebra/Double/Factorization/UserQR.cs
  9. 10
      src/Numerics/LinearAlgebra/Generic/Factorization/QR.cs
  10. 5
      src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs
  11. 1
      src/Numerics/LinearAlgebra/Single/Factorization/UserQR.cs
  12. 1
      src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs
  13. 37
      src/UnitTests/LinearAlgebraTests/Complex/Factorization/QRTests.cs
  14. 8
      src/UnitTests/LinearAlgebraTests/Complex/MatrixTests.Arithmetic.cs
  15. 11
      src/UnitTests/LinearAlgebraTests/Complex32/Factorization/QRTests.cs
  16. 1
      src/UnitTests/LinearAlgebraTests/Complex32/MatrixTests.cs
  17. 34
      src/UnitTests/LinearAlgebraTests/Double/Factorization/QRTests.cs
  18. 14
      src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs
  19. 35
      src/UnitTests/LinearAlgebraTests/Single/Factorization/QRTests.cs

2
src/NativeWrappers/MKL/lapack.cpp

@ -180,7 +180,7 @@ inline MKL_INT qr_factor(MKL_INT m, MKL_INT n, T r[], T tau[], T q[], T work[],
}
else
{
orgqr(&m, &n, &n, q, &m, tau, work, &len, &info);
orgqr(&m, &m, &n, q, &m, tau, work, &len, &info);
}
return info;

3
src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Common.cs

@ -40,7 +40,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// </summary>
public partial class MklLinearAlgebraProvider : ManagedLinearAlgebraProvider
{
/* /// <summary>
/// <summary>
/// Computes the requested <see cref="Norm"/> of the matrix.
/// </summary>
/// <param name="norm">The type of norm to compute.</param>
@ -200,6 +200,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
return SafeNativeMethods.d_matrix_norm((byte)norm, rows, columns, matrix, work);
}
/* BUG in MKL'S ZLANGE routine. Using managed code until it is fixed.
/// <summary>
/// Computes the requested <see cref="Norm"/> of the matrix.
/// </summary>

5
src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs

@ -77,6 +77,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix);
}
QrMethod = method;
Tau = new Complex[Math.Min(matrix.RowCount, matrix.ColumnCount)];
if (method == QRMethod.Full)
@ -143,7 +144,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw new NotSupportedException("Can only do QR factorization for dense matrices at the moment.");
}
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, input.ColumnCount, dresult.Values);
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, input.ColumnCount, dresult.Values, QrMethod);
}
/// <summary>
@ -188,7 +189,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment.");
}
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values);
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values, QrMethod);
}
}
}

1
src/Numerics/LinearAlgebra/Complex/Factorization/UserQR.cs

@ -69,6 +69,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix);
}
QrMethod = method;
var minmn = Math.Min(matrix.RowCount, matrix.ColumnCount);
var u = new Complex[minmn][];

5
src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs

@ -77,6 +77,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix);
}
QrMethod = method;
Tau = new Complex32[Math.Min(matrix.RowCount, matrix.ColumnCount)];
if (method == QRMethod.Full)
@ -143,7 +144,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw new NotSupportedException("Can only do QR factorization for dense matrices at the moment.");
}
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, input.ColumnCount, dresult.Values);
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, input.ColumnCount, dresult.Values, QrMethod);
}
/// <summary>
@ -188,7 +189,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment.");
}
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values);
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values, QrMethod);
}
}
}

1
src/Numerics/LinearAlgebra/Complex32/Factorization/UserQR.cs

@ -69,6 +69,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix);
}
QrMethod = method;
var minmn = Math.Min(matrix.RowCount, matrix.ColumnCount);
var u = new Complex32[minmn][];

5
src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs

@ -76,6 +76,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix);
}
QrMethod = method;
Tau = new double[Math.Min(matrix.RowCount, matrix.ColumnCount)];
if (method == QRMethod.Full)
@ -143,7 +144,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw new NotSupportedException("Can only do QR factorization for dense matrices at the moment.");
}
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, input.ColumnCount, dresult.Values);
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, input.ColumnCount, dresult.Values, QrMethod);
}
/// <summary>
@ -188,7 +189,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment.");
}
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values);
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values, QrMethod);
}
}
}

1
src/Numerics/LinearAlgebra/Double/Factorization/UserQR.cs

@ -68,6 +68,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix);
}
QrMethod = method;
var minmn = Math.Min(matrix.RowCount, matrix.ColumnCount);
var u = new double[minmn][];

10
src/Numerics/LinearAlgebra/Generic/Factorization/QR.cs

@ -81,6 +81,15 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
set;
}
/// <summary>
/// The QR factorization method.
/// </summary>
protected QRMethod QrMethod
{
get;
set;
}
/// <summary>
/// Internal method which routes the call to perform the QR factorization to the appropriate class.
/// </summary>
@ -89,6 +98,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
/// <returns>A QR factorization object.</returns>
internal static QR<T> Create(Matrix<T> matrix, QRMethod method = QRMethod.Full)
{
if (typeof(T) == typeof(double))
{
var dense = matrix as LinearAlgebra.Double.DenseMatrix;

5
src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs

@ -76,6 +76,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix);
}
QrMethod = method;
Tau = new float[Math.Min(matrix.RowCount, matrix.ColumnCount)];
if (method == QRMethod.Full)
@ -142,7 +143,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw new NotSupportedException("Can only do QR factorization for dense matrices at the moment.");
}
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, input.ColumnCount, dresult.Values);
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, input.ColumnCount, dresult.Values, QrMethod);
}
/// <summary>
@ -187,7 +188,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw new NotSupportedException("Can only do QR factorization for dense vectors at the moment.");
}
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values);
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Values, ((DenseMatrix)MatrixR).Values, MatrixR.RowCount, MatrixR.ColumnCount, Tau, dinput.Values, 1, dresult.Values, QrMethod);
}
}
}

1
src/Numerics/LinearAlgebra/Single/Factorization/UserQR.cs

@ -68,6 +68,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix);
}
QrMethod = method;
var minmn = Math.Min(matrix.RowCount, matrix.ColumnCount);
var u = new float[minmn][];

1
src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs

@ -919,7 +919,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex
var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
var mb = matrix * mx;
Console.WriteLine(mx);
AssertHelpers.AlmostEqual(mb[0, 0], b[0], 14);
AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);

37
src/UnitTests/LinearAlgebraTests/Complex/Factorization/QRTests.cs

@ -181,6 +181,25 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
AssertHelpers.AlmostEqual(matrixA[i, j], matrixQfromR[i, j], 9);
}
}
// Make sure the Q is unitary --> (Q*)x(Q) = I
var matrixQсtQ = q.ConjugateTranspose() * q;
for (var i = 0; i < matrixQсtQ.RowCount; i++)
{
for (var j = 0; j < matrixQсtQ.ColumnCount; j++)
{
if (i == j)
{
Assert.AreEqual(matrixQсtQ[i, j].Real, 1.0, 1e-3);
Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0, 1e-3);
}
else
{
Assert.AreEqual(matrixQсtQ[i, j].Real, 0.0, 1e-3);
Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0, 1e-3);
}
}
}
}
/// <summary>
@ -221,6 +240,16 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
// Make sure the Q*R is the original matrix.
var matrixQfromR = q * r;
for (var i = 0; i < matrixQfromR.RowCount; i++)
{
for (var j = 0; j < matrixQfromR.ColumnCount; j++)
{
AssertHelpers.AlmostEqual(matrixA[i, j], matrixQfromR[i, j], 9);
}
}
// Make sure the Q is unitary --> (Q*)x(Q) = I
var matrixQсtQ = q.ConjugateTranspose() * q;
for (var i = 0; i < matrixQсtQ.RowCount; i++)
@ -229,13 +258,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
{
if (i == j)
{
Assert.AreEqual(matrixQсtQ[i, j].Real, 1.0f, 1e-3f);
Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f);
Assert.AreEqual(matrixQсtQ[i, j].Real, 1.0, 1e-3);
Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0, 1e-3);
}
else
{
Assert.AreEqual(matrixQсtQ[i, j].Real, 0.0f, 1e-3f);
Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f);
Assert.AreEqual(matrixQсtQ[i, j].Real, 0.0, 1e-3);
Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0, 1e-3);
}
}
}

8
src/UnitTests/LinearAlgebraTests/Complex/MatrixTests.Arithmetic.cs

@ -1067,7 +1067,9 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
{
for (var j = 0; j < data.ColumnCount; j++)
{
Assert.AreEqual(data[i, j] * other[i, j], result[i, j]);
var value = data[i, j]*other[i, j];
Assert.AreEqual(value.Real, result[i, j].Real, 1e-12);
Assert.AreEqual(value.Imaginary, result[i, j].Imaginary, 1e-12);
}
}
@ -1076,7 +1078,9 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
{
for (var j = 0; j < data.ColumnCount; j++)
{
Assert.AreEqual(data[i, j] * other[i, j], result[i, j]);
var value = data[i, j] * other[i, j];
Assert.AreEqual(value.Real, result[i, j].Real, 1e-12);
Assert.AreEqual(value.Imaginary, result[i, j].Imaginary, 1e-12);
}
}
}

11
src/UnitTests/LinearAlgebraTests/Complex32/Factorization/QRTests.cs

@ -242,6 +242,17 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
// Make sure the Q*R is the original matrix.
var matrixQfromR = q * r;
for (var i = 0; i < matrixQfromR.RowCount; i++)
{
for (var j = 0; j < matrixQfromR.ColumnCount; j++)
{
Assert.AreEqual(matrixA[i, j].Real, matrixQfromR[i, j].Real, 1e-3f);
Assert.AreEqual(matrixA[i, j].Imaginary, matrixQfromR[i, j].Imaginary, 1e-3f);
}
}
// Make sure the Q is unitary --> (Q*)x(Q) = I
var matrixQсtQ = q.ConjugateTranspose() * q;
for (var i = 0; i < matrixQсtQ.RowCount; i++)

1
src/UnitTests/LinearAlgebraTests/Complex32/MatrixTests.cs

@ -27,7 +27,6 @@
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
{
using NUnit.Framework;
using Complex32 = Numerics.Complex32;
/// <summary>
/// Abstract class with the common set of matrix tests

34
src/UnitTests/LinearAlgebraTests/Double/Factorization/QRTests.cs

@ -180,6 +180,23 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
Assert.AreEqual(matrixA[i, j], matrixQfromR[i, j], 1.0e-11);
}
}
// Make sure the Q is unitary --> (Q*)x(Q) =
var matrixQtQ = q.Transpose() * q;
for (var i = 0; i < matrixQtQ.RowCount; i++)
{
for (var j = 0; j < matrixQtQ.ColumnCount; j++)
{
if (i == j)
{
Assert.AreEqual(matrixQtQ[i, j], 1.0, 1e-3);
}
else
{
Assert.AreEqual(matrixQtQ[i, j], 0.0, 1e-3);
}
}
}
}
/// <summary>
@ -229,6 +246,23 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
Assert.AreEqual(matrixA[i, j], matrixQfromR[i, j], 1.0e-11);
}
}
// Make sure the Q is unitary --> (Q*)x(Q) =
var matrixQtQ = q.Transpose() * q;
for (var i = 0; i < matrixQtQ.RowCount; i++)
{
for (var j = 0; j < matrixQtQ.ColumnCount; j++)
{
if (i == j)
{
Assert.AreEqual(matrixQtQ[i, j], 1.0, 1e-3);
}
else
{
Assert.AreEqual(matrixQtQ[i, j], 0.0, 1e-3);
}
}
}
}
/// <summary>

14
src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs

@ -66,13 +66,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
public virtual void CanComputeFrobeniusNorm()
{
var matrix = TestMatrices["Square3x3"];
AssertHelpers.AlmostEqual(10.77775486824598, matrix.FrobeniusNorm(), 14);
AssertHelpers.AlmostEqual(10.77775486824598, matrix.FrobeniusNorm(), 7);
matrix = TestMatrices["Wide2x3"];
AssertHelpers.AlmostEqual(4.79478883789474, matrix.FrobeniusNorm(), 14);
AssertHelpers.AlmostEqual(4.79478883789474, matrix.FrobeniusNorm(), 7);
matrix = TestMatrices["Tall3x2"];
AssertHelpers.AlmostEqual(7.54122006044115, matrix.FrobeniusNorm(), 14);
AssertHelpers.AlmostEqual(7.54122006044115, matrix.FrobeniusNorm(), 7);
}
/// <summary>
@ -85,10 +85,10 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
Assert.AreEqual(16.5, matrix.InfinityNorm());
matrix = TestMatrices["Wide2x3"];
Assert.AreEqual(6.6, matrix.InfinityNorm());
Assert.AreEqual(6.6, matrix.InfinityNorm(), 1e-7);
matrix = TestMatrices["Tall3x2"];
Assert.AreEqual(9.9, matrix.InfinityNorm());
Assert.AreEqual(9.9, matrix.InfinityNorm(), 1e-4);
}
/// <summary>
@ -98,13 +98,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
public virtual void CanComputeL1Norm()
{
var matrix = TestMatrices["Square3x3"];
Assert.AreEqual(12.1, matrix.L1Norm());
Assert.AreEqual(12.1, matrix.L1Norm(), 1e-4);
matrix = TestMatrices["Wide2x3"];
Assert.AreEqual(5.5, matrix.L1Norm());
matrix = TestMatrices["Tall3x2"];
Assert.AreEqual(8.8, matrix.L1Norm());
Assert.AreEqual(8.8, matrix.L1Norm(), 1e-4);
}
/// <summary>

35
src/UnitTests/LinearAlgebraTests/Single/Factorization/QRTests.cs

@ -181,6 +181,24 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
Assert.AreEqual(matrixA[i, j], matrixQfromR[i, j], 1e-4);
}
}
// Make sure the Q is unitary --> (Q*)x(Q) = I
var matrixQtQ = q.Transpose() * q;
for (var i = 0; i < matrixQtQ.RowCount; i++)
{
for (var j = 0; j < matrixQtQ.ColumnCount; j++)
{
if (i == j)
{
Assert.AreEqual(matrixQtQ[i, j], 1.0f, 1e-3f);
}
else
{
Assert.AreEqual(matrixQtQ[i, j], 0.0f, 1e-3f);
}
}
}
}
/// <summary>
@ -230,6 +248,23 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
Assert.AreEqual(matrixA[i, j], matrixQfromR[i, j], 1.0e-4);
}
}
// Make sure the Q is unitary --> (Q*)x(Q) = I
var matrixQtQ = q.Transpose() * q;
for (var i = 0; i < matrixQtQ.RowCount; i++)
{
for (var j = 0; j < matrixQtQ.ColumnCount; j++)
{
if (i == j)
{
Assert.AreEqual(matrixQtQ[i, j], 1.0f, 1e-3f);
}
else
{
Assert.AreEqual(matrixQtQ[i, j], 0.0f, 1e-3f);
}
}
}
}
/// <summary>

Loading…
Cancel
Save