csharpfftfsharpintegrationinterpolationlinear-algebramathdifferentiationmatrixnumericsrandomregressionstatisticsmathnet
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1125 lines
46 KiB
1125 lines
46 KiB
// <copyright file="LinearAlgebraProviderTests.cs" company="Math.NET">
|
|
// Math.NET Numerics, part of the Math.NET Project
|
|
// http://numerics.mathdotnet.com
|
|
// http://github.com/mathnet/mathnet-numerics
|
|
// http://mathnetnumerics.codeplex.com
|
|
//
|
|
// Copyright (c) 2009-2015 Math.NET
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person
|
|
// obtaining a copy of this software and associated documentation
|
|
// files (the "Software"), to deal in the Software without
|
|
// restriction, including without limitation the rights to use,
|
|
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the
|
|
// Software is furnished to do so, subject to the following
|
|
// conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
// OTHER DEALINGS IN THE SOFTWARE.
|
|
// </copyright>
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using MathNet.Numerics.Distributions;
|
|
using MathNet.Numerics.LinearAlgebra;
|
|
using MathNet.Numerics.LinearAlgebra.Complex;
|
|
using MathNet.Numerics.LinearAlgebra.Factorization;
|
|
using MathNet.Numerics.Providers.LinearAlgebra;
|
|
using NUnit.Framework;
|
|
|
|
namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex
|
|
{
|
|
#if NOSYSNUMERICS
|
|
using Complex = Numerics.Complex;
|
|
#else
|
|
using Complex = System.Numerics.Complex;
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Base class for linear algebra provider tests.
|
|
/// </summary>
|
|
[TestFixture, Category("LAProvider")]
|
|
public class LinearAlgebraProviderTests
|
|
{
|
|
/// <summary>
|
|
/// The Y Complex test vector.
|
|
/// </summary>
|
|
readonly Complex[] _y = {new Complex(1.1, 0), 2.2, 3.3, 4.4, 5.5};
|
|
|
|
/// <summary>
|
|
/// The X Complex test vector.
|
|
/// </summary>
|
|
readonly Complex[] _x = {new Complex(6.6, 0), 7.7, 8.8, 9.9, 10.1};
|
|
|
|
static readonly IContinuousDistribution Dist = new Normal();
|
|
|
|
/// <summary>
|
|
/// Test matrix to use.
|
|
/// </summary>
|
|
readonly IDictionary<string, DenseMatrix> _matrices = new Dictionary<string, DenseMatrix>
|
|
{
|
|
{"Singular3x3", DenseMatrix.OfArray(new[,] {{new Complex(1.0, 0), 1.0, 2.0}, {1.0, 1.0, 2.0}, {1.0, 1.0, 2.0}})},
|
|
{"Square3x3", DenseMatrix.OfArray(new[,] {{new Complex(-1.1, 0), -2.2, -3.3}, {0.0, 1.1, 2.2}, {-4.4, 5.5, 6.6}})},
|
|
{"Square4x4", DenseMatrix.OfArray(new[,] {{new Complex(-1.1, 0), -2.2, -3.3, -4.4}, {0.0, 1.1, 2.2, 3.3}, {1.0, 2.1, 6.2, 4.3}, {-4.4, 5.5, 6.6, -7.7}})},
|
|
{"Singular4x4", DenseMatrix.OfArray(new[,] {{new Complex(-1.1, 0), -2.2, -3.3, -4.4}, {-1.1, -2.2, -3.3, -4.4}, {-1.1, -2.2, -3.3, -4.4}, {-1.1, -2.2, -3.3, -4.4}})},
|
|
{"Tall3x2", DenseMatrix.OfArray(new[,] {{new Complex(-1.1, 0), -2.2}, {0.0, 1.1}, {-4.4, 5.5}})},
|
|
{"Wide2x3", DenseMatrix.OfArray(new[,] {{new Complex(-1.1, 0), -2.2, -3.3}, {0.0, 1.1, 2.2}})},
|
|
{"Tall50000x10", DenseMatrix.CreateRandom(50000, 10, Dist)},
|
|
{"Wide10x50000", DenseMatrix.CreateRandom(10, 50000, Dist)},
|
|
{"Square1000x1000", DenseMatrix.CreateRandom(1000, 1000, Dist)}
|
|
};
|
|
|
|
/// <summary>
|
|
/// Can add a vector to scaled vector
|
|
/// </summary>
|
|
[Test]
|
|
public void CanAddVectorToScaledVectorComplex()
|
|
{
|
|
var result = new Complex[_y.Length];
|
|
|
|
Control.LinearAlgebraProvider.AddVectorToScaledVector(_y, 0, _x, result);
|
|
for (var i = 0; i < _y.Length; i++)
|
|
{
|
|
Assert.AreEqual(_y[i], result[i]);
|
|
}
|
|
|
|
Array.Copy(_y, result, _y.Length);
|
|
Control.LinearAlgebraProvider.AddVectorToScaledVector(result, 1, _x, result);
|
|
for (var i = 0; i < _y.Length; i++)
|
|
{
|
|
Assert.AreEqual(_y[i] + _x[i], result[i]);
|
|
}
|
|
|
|
Array.Copy(_y, result, _y.Length);
|
|
Control.LinearAlgebraProvider.AddVectorToScaledVector(result, Math.PI, _x, result);
|
|
for (var i = 0; i < _y.Length; i++)
|
|
{
|
|
Assert.AreEqual(_y[i] + (Math.PI*_x[i]), result[i]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can scale an array.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanScaleArray()
|
|
{
|
|
var result = new Complex[_y.Length];
|
|
|
|
Control.LinearAlgebraProvider.ScaleArray(1, _y, result);
|
|
for (var i = 0; i < _y.Length; i++)
|
|
{
|
|
Assert.AreEqual(_y[i], result[i]);
|
|
}
|
|
|
|
Array.Copy(_y, result, _y.Length);
|
|
Control.LinearAlgebraProvider.ScaleArray(Math.PI, result, result);
|
|
for (var i = 0; i < _y.Length; i++)
|
|
{
|
|
Assert.AreEqual(_y[i]*Math.PI, result[i]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute the dot product.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeDotProduct()
|
|
{
|
|
var result = Control.LinearAlgebraProvider.DotProduct(_x, _y);
|
|
AssertHelpers.AlmostEqualRelative(152.35, result, 15);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can add two arrays.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanAddArrays()
|
|
{
|
|
var result = new Complex[_y.Length];
|
|
Control.LinearAlgebraProvider.AddArrays(_x, _y, result);
|
|
for (var i = 0; i < result.Length; i++)
|
|
{
|
|
Assert.AreEqual(_x[i] + _y[i], result[i]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can subtract two arrays.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSubtractArrays()
|
|
{
|
|
var result = new Complex[_y.Length];
|
|
Control.LinearAlgebraProvider.SubtractArrays(_x, _y, result);
|
|
for (var i = 0; i < result.Length; i++)
|
|
{
|
|
Assert.AreEqual(_x[i] - _y[i], result[i]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can pointwise multiply two arrays.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanPointWiseMultiplyArrays()
|
|
{
|
|
var result = new Complex[_y.Length];
|
|
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_x, _y, result);
|
|
for (var i = 0; i < result.Length; i++)
|
|
{
|
|
Assert.AreEqual(_x[i]*_y[i], result[i]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can pointwise divide two arrays.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanPointWiseDivideArrays()
|
|
{
|
|
var result = new Complex[_y.Length];
|
|
Control.LinearAlgebraProvider.PointWiseDivideArrays(_x, _y, result);
|
|
for (var i = 0; i < result.Length; i++)
|
|
{
|
|
Assert.AreEqual(_x[i]/_y[i], result[i]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute L1 norm.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeMatrixL1Norm()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var norm = Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, matrix.RowCount, matrix.ColumnCount, matrix.Values);
|
|
AssertHelpers.AlmostEqualRelative(12.1, norm, 6);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute Frobenius norm.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeMatrixFrobeniusNorm()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var norm = Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, matrix.RowCount, matrix.ColumnCount, matrix.Values);
|
|
AssertHelpers.AlmostEqualRelative(10.777754868246, norm, 8);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute Infinity norm.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeMatrixInfinityNorm()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var norm = Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, matrix.RowCount, matrix.ColumnCount, matrix.Values);
|
|
Assert.AreEqual(16.5, norm);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can multiply two square matrices.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanMultiplySquareMatrices()
|
|
{
|
|
var x = _matrices["Singular3x3"];
|
|
var y = _matrices["Square3x3"];
|
|
var c = new DenseMatrix(x.RowCount, y.ColumnCount);
|
|
|
|
Control.LinearAlgebraProvider.MatrixMultiply(x.Values, x.RowCount, x.ColumnCount, y.Values, y.RowCount, y.ColumnCount, c.Values);
|
|
|
|
for (var i = 0; i < c.RowCount; i++)
|
|
{
|
|
for (var j = 0; j < c.ColumnCount; j++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(x.Row(i)*y.Column(j), c[i, j], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can multiply a wide and tall matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanMultiplyWideAndTallMatrices()
|
|
{
|
|
var x = _matrices["Wide2x3"];
|
|
var y = _matrices["Tall3x2"];
|
|
var c = new DenseMatrix(x.RowCount, y.ColumnCount);
|
|
|
|
Control.LinearAlgebraProvider.MatrixMultiply(x.Values, x.RowCount, x.ColumnCount, y.Values, y.RowCount, y.ColumnCount, c.Values);
|
|
|
|
for (var i = 0; i < c.RowCount; i++)
|
|
{
|
|
for (var j = 0; j < c.ColumnCount; j++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(x.Row(i)*y.Column(j), c[i, j], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can multiply a tall and wide matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanMultiplyTallAndWideMatrices()
|
|
{
|
|
var x = _matrices["Tall3x2"];
|
|
var y = _matrices["Wide2x3"];
|
|
var c = new DenseMatrix(x.RowCount, y.ColumnCount);
|
|
|
|
Control.LinearAlgebraProvider.MatrixMultiply(x.Values, x.RowCount, x.ColumnCount, y.Values, y.RowCount, y.ColumnCount, c.Values);
|
|
|
|
for (var i = 0; i < c.RowCount; i++)
|
|
{
|
|
for (var j = 0; j < c.ColumnCount; j++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(x.Row(i)*y.Column(j), c[i, j], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can multiply two square matrices.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanMultiplySquareMatricesWithUpdate()
|
|
{
|
|
var x = _matrices["Singular3x3"];
|
|
var y = _matrices["Square3x3"];
|
|
var c = new DenseMatrix(x.RowCount, y.ColumnCount);
|
|
|
|
Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(Transpose.DontTranspose, Transpose.DontTranspose, 2.2, x.Values, x.RowCount, x.ColumnCount, y.Values, y.RowCount, y.ColumnCount, 1.0, c.Values);
|
|
|
|
for (var i = 0; i < c.RowCount; i++)
|
|
{
|
|
for (var j = 0; j < c.ColumnCount; j++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(2.2*x.Row(i)*y.Column(j), c[i, j], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can multiply a wide and tall matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanMultiplyWideAndTallMatricesWithUpdate()
|
|
{
|
|
var x = _matrices["Wide2x3"];
|
|
var y = _matrices["Tall3x2"];
|
|
var c = new DenseMatrix(x.RowCount, y.ColumnCount);
|
|
|
|
Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(Transpose.DontTranspose, Transpose.DontTranspose, 2.2, x.Values, x.RowCount, x.ColumnCount, y.Values, y.RowCount, y.ColumnCount, 1.0, c.Values);
|
|
|
|
for (var i = 0; i < c.RowCount; i++)
|
|
{
|
|
for (var j = 0; j < c.ColumnCount; j++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(2.2*x.Row(i)*y.Column(j), c[i, j], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can multiply a tall and wide matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanMultiplyTallAndWideMatricesWithUpdate()
|
|
{
|
|
var x = _matrices["Tall3x2"];
|
|
var y = _matrices["Wide2x3"];
|
|
var c = new DenseMatrix(x.RowCount, y.ColumnCount);
|
|
|
|
Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(Transpose.DontTranspose, Transpose.DontTranspose, 2.2, x.Values, x.RowCount, x.ColumnCount, y.Values, y.RowCount, y.ColumnCount, 1.0, c.Values);
|
|
|
|
for (var i = 0; i < c.RowCount; i++)
|
|
{
|
|
for (var j = 0; j < c.ColumnCount; j++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(2.2*x.Row(i)*y.Column(j), c[i, j], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute the LU factor of a matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeLuFactor()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.RowCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var ipiv = new int[matrix.RowCount];
|
|
|
|
Control.LinearAlgebraProvider.LUFactor(a, matrix.RowCount, ipiv);
|
|
|
|
AssertHelpers.AlmostEqualRelative(a[0], -4.4, 15);
|
|
AssertHelpers.AlmostEqualRelative(a[1], 0.25, 15);
|
|
AssertHelpers.AlmostEqualRelative(a[2], 0, 15);
|
|
AssertHelpers.AlmostEqualRelative(a[3], 5.5, 15);
|
|
AssertHelpers.AlmostEqualRelative(a[4], -3.575, 15);
|
|
AssertHelpers.AlmostEqualRelative(a[5], -0.307692307692308, 14);
|
|
AssertHelpers.AlmostEqualRelative(a[6], 6.6, 15);
|
|
AssertHelpers.AlmostEqualRelative(a[7], -4.95, 14);
|
|
AssertHelpers.AlmostEqualRelative(a[8], 0.676923076923077, 14);
|
|
Assert.AreEqual(ipiv[0], 2);
|
|
Assert.AreEqual(ipiv[1], 2);
|
|
Assert.AreEqual(ipiv[2], 2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute the inverse of a matrix using LU factorization.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeLuInverse()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.RowCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
Control.LinearAlgebraProvider.LUInverse(a, matrix.RowCount);
|
|
|
|
AssertHelpers.AlmostEqualRelative(a[0], -0.454545454545454, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[1], -0.909090909090908, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[2], 0.454545454545454, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[3], -0.340909090909090, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[4], -2.045454545454543, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[5], 1.477272727272726, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[6], -0.113636363636364, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute the inverse of a matrix using LU factorization
|
|
/// using a previously factored matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeLuInverseOnFactoredMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.RowCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var ipiv = new int[matrix.RowCount];
|
|
|
|
Control.LinearAlgebraProvider.LUFactor(a, matrix.RowCount, ipiv);
|
|
Control.LinearAlgebraProvider.LUInverseFactored(a, matrix.RowCount, ipiv);
|
|
|
|
AssertHelpers.AlmostEqualRelative(a[0], -0.454545454545454, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[1], -0.909090909090908, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[2], 0.454545454545454, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[3], -0.340909090909090, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[4], -2.045454545454543, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[5], 1.477272727272726, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[6], -0.113636363636364, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727, 13);
|
|
AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using LU factorization.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingLU()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.RowCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
Control.LinearAlgebraProvider.LUSolve(2, a, matrix.RowCount, b);
|
|
|
|
AssertHelpers.AlmostEqualRelative(b[0], -1.477272727272726, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[1], -4.318181818181815, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[2], 3.068181818181816, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[3], -4.204545454545451, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[4], -12.499999999999989, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[5], 8.522727272727266, 13);
|
|
|
|
NotModified(matrix.RowCount, matrix.ColumnCount, a, matrix);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using LU factorization using a factored matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingLUOnFactoredMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.RowCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var ipiv = new int[matrix.RowCount];
|
|
Control.LinearAlgebraProvider.LUFactor(a, matrix.RowCount, ipiv);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
Control.LinearAlgebraProvider.LUSolveFactored(2, a, matrix.RowCount, ipiv, b);
|
|
|
|
AssertHelpers.AlmostEqualRelative(b[0], -1.477272727272726, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[1], -4.318181818181815, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[2], 3.068181818181816, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[3], -4.204545454545451, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[4], -12.499999999999989, 13);
|
|
AssertHelpers.AlmostEqualRelative(b[5], 8.522727272727266, 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute the <c>Cholesky</c> factorization.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeCholeskyFactor()
|
|
{
|
|
var matrix = new Complex[] {1, 1, 1, 1, 1, 5, 5, 5, 1, 5, 14, 14, 1, 5, 14, 15};
|
|
Control.LinearAlgebraProvider.CholeskyFactor(matrix, 4);
|
|
Assert.AreEqual(matrix[0].Real, 1);
|
|
Assert.AreEqual(matrix[1].Real, 1);
|
|
Assert.AreEqual(matrix[2].Real, 1);
|
|
Assert.AreEqual(matrix[3].Real, 1);
|
|
Assert.AreEqual(matrix[4].Real, 0);
|
|
Assert.AreEqual(matrix[5].Real, 2);
|
|
Assert.AreEqual(matrix[6].Real, 2);
|
|
Assert.AreEqual(matrix[7].Real, 2);
|
|
Assert.AreEqual(matrix[8].Real, 0);
|
|
Assert.AreEqual(matrix[9].Real, 0);
|
|
Assert.AreEqual(matrix[10].Real, 3);
|
|
Assert.AreEqual(matrix[11].Real, 3);
|
|
Assert.AreEqual(matrix[12].Real, 0);
|
|
Assert.AreEqual(matrix[13].Real, 0);
|
|
Assert.AreEqual(matrix[14].Real, 0);
|
|
Assert.AreEqual(matrix[15].Real, 1);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using Cholesky factorization.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingCholesky()
|
|
{
|
|
var matrix = new DenseMatrix(3, 3, new Complex[] {1, 1, 1, 1, 2, 3, 1, 3, 6});
|
|
var a = new Complex[] {1, 1, 1, 1, 2, 3, 1, 3, 6};
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
Control.LinearAlgebraProvider.CholeskySolve(a, 3, b, 2);
|
|
|
|
AssertHelpers.AlmostEqualRelative(b[0], 0, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[1], 1, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[2], 0, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[3], 3, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[4], 1, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[5], 0, 14);
|
|
|
|
NotModified(3, 3, a, matrix);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using LU factorization using a factored matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingCholeskyOnFactoredMatrix()
|
|
{
|
|
var a = new Complex[] {1, 1, 1, 1, 2, 3, 1, 3, 6};
|
|
|
|
Control.LinearAlgebraProvider.CholeskyFactor(a, 3);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
Control.LinearAlgebraProvider.CholeskySolveFactored(a, 3, b, 2);
|
|
|
|
AssertHelpers.AlmostEqualRelative(b[0], 0, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[1], 1, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[2], 0, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[3], 3, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[4], 1, 14);
|
|
AssertHelpers.AlmostEqualRelative(b[5], 0, 14);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute QR factorization of a square matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeQRFactorSquareMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var r = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, r, r.Length);
|
|
|
|
var tau = new Complex[3];
|
|
var q = new Complex[matrix.RowCount*matrix.RowCount];
|
|
Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau);
|
|
|
|
var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q);
|
|
var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle();
|
|
var a = mq*mr;
|
|
|
|
for (var row = 0; row < matrix.RowCount; row++)
|
|
{
|
|
for (var col = 0; col < matrix.ColumnCount; col++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute QR factorization of a tall matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeQRFactorTallMatrix()
|
|
{
|
|
var matrix = _matrices["Tall3x2"];
|
|
var r = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, r, r.Length);
|
|
|
|
var tau = new Complex[3];
|
|
var q = new Complex[matrix.RowCount*matrix.RowCount];
|
|
Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau);
|
|
|
|
var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle();
|
|
var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q);
|
|
var a = mq*mr;
|
|
|
|
for (var row = 0; row < matrix.RowCount; row++)
|
|
{
|
|
for (var col = 0; col < matrix.ColumnCount; col++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute QR factorization of a wide matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeQRFactorWideMatrix()
|
|
{
|
|
var matrix = _matrices["Wide2x3"];
|
|
var r = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, r, r.Length);
|
|
|
|
var tau = new Complex[3];
|
|
var q = new Complex[matrix.RowCount*matrix.RowCount];
|
|
Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau);
|
|
|
|
var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle();
|
|
var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q);
|
|
var a = mq*mr;
|
|
|
|
for (var row = 0; row < matrix.RowCount; row++)
|
|
{
|
|
for (var col = 0; col < matrix.ColumnCount; col++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute thin QR factorization of a square matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeThinQRFactorSquareMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var r = new Complex[matrix.ColumnCount*matrix.ColumnCount];
|
|
var tau = new Complex[3];
|
|
var q = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, q, q.Length);
|
|
|
|
Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
|
|
|
|
var mq = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, q);
|
|
var mr = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, r);
|
|
var a = mq*mr;
|
|
|
|
for (var row = 0; row < matrix.RowCount; row++)
|
|
{
|
|
for (var col = 0; col < matrix.ColumnCount; col++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute thin QR factorization of a tall matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeThinQRFactorTallMatrix()
|
|
{
|
|
var matrix = _matrices["Tall3x2"];
|
|
var r = new Complex[matrix.ColumnCount*matrix.ColumnCount];
|
|
var tau = new Complex[3];
|
|
var q = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, q, q.Length);
|
|
|
|
Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
|
|
|
|
var mq = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, q);
|
|
var mr = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, r);
|
|
var a = mq*mr;
|
|
|
|
for (var row = 0; row < matrix.RowCount; row++)
|
|
{
|
|
for (var col = 0; col < matrix.ColumnCount; col++)
|
|
{
|
|
AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using QR factorization with a square A matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingQRSquareMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x);
|
|
|
|
NotModified(3, 3, a, matrix);
|
|
|
|
var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
|
|
var mb = matrix*mx;
|
|
AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using QR factorization with a tall A matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingQRTallMatrix()
|
|
{
|
|
var matrix = _matrices["Tall3x2"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x);
|
|
|
|
NotModified(3, 2, a, matrix);
|
|
|
|
var mb = new DenseMatrix(matrix.RowCount, 2, b);
|
|
var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb;
|
|
|
|
AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using QR factorization with a tall A matrix
|
|
/// using a factored A matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingQRTallMatrixOnFactoredMatrix()
|
|
{
|
|
var matrix = _matrices["Tall3x2"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var tau = new Complex[matrix.ColumnCount];
|
|
var q = new Complex[matrix.RowCount*matrix.RowCount];
|
|
Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x);
|
|
|
|
var mb = new DenseMatrix(matrix.RowCount, 2, b);
|
|
var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb;
|
|
|
|
AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using thin QR factorization with a square A matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingThinQRSquareMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, QRMethod.Thin);
|
|
|
|
NotModified(3, 3, a, matrix);
|
|
|
|
var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
|
|
var mb = matrix*mx;
|
|
|
|
AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using thin QR factorization with a tall A matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingThinQRTallMatrix()
|
|
{
|
|
var matrix = _matrices["Tall3x2"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, QRMethod.Thin);
|
|
|
|
NotModified(3, 2, a, matrix);
|
|
|
|
var mb = new DenseMatrix(matrix.RowCount, 2, b);
|
|
var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb;
|
|
|
|
AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using thin QR factorization with a square A matrix
|
|
/// using a factored A matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingThinQRSquareMatrixOnFactoredMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var tau = new Complex[matrix.ColumnCount];
|
|
var r = new Complex[matrix.ColumnCount*matrix.ColumnCount];
|
|
Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, QRMethod.Thin);
|
|
|
|
var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
|
|
var mb = matrix*mx;
|
|
|
|
AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13);
|
|
AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using thin QR factorization with a tall A matrix
|
|
/// using a factored A matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingThinQRTallMatrixOnFactoredMatrix()
|
|
{
|
|
var matrix = _matrices["Tall3x2"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var tau = new Complex[matrix.ColumnCount];
|
|
var r = new Complex[matrix.ColumnCount*matrix.ColumnCount];
|
|
Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, QRMethod.Thin);
|
|
|
|
var mb = new DenseMatrix(matrix.RowCount, 2, b);
|
|
var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb;
|
|
|
|
AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13);
|
|
AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute the SVD factorization of a square matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeSVDFactorizationOfSquareMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var s = new Complex[matrix.RowCount];
|
|
var u = new Complex[matrix.RowCount*matrix.RowCount];
|
|
var vt = new Complex[matrix.ColumnCount*matrix.ColumnCount];
|
|
|
|
Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt);
|
|
|
|
var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount);
|
|
for (var index = 0; index < s.Length; index++)
|
|
{
|
|
w[index, index] = s[index];
|
|
}
|
|
|
|
var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u);
|
|
var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt);
|
|
var result = mU*w*mV;
|
|
|
|
AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 13);
|
|
AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 13);
|
|
AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 13);
|
|
AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 13);
|
|
AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 13);
|
|
AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 13);
|
|
AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 13);
|
|
AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 13);
|
|
AssertHelpers.AlmostEqualRelative(matrix[2, 2], result[2, 2], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute the SVD factorization of a tall matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeSVDFactorizationOfTallMatrix()
|
|
{
|
|
var matrix = _matrices["Tall3x2"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var s = new Complex[matrix.ColumnCount];
|
|
var u = new Complex[matrix.RowCount*matrix.RowCount];
|
|
var vt = new Complex[matrix.ColumnCount*matrix.ColumnCount];
|
|
|
|
Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt);
|
|
|
|
var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount);
|
|
for (var index = 0; index < s.Length; index++)
|
|
{
|
|
w[index, index] = s[index];
|
|
}
|
|
|
|
var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u);
|
|
var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt);
|
|
var result = mU*w*mV;
|
|
|
|
AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 14);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can compute the SVD factorization of a wide matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanComputeSVDFactorizationOfWideMatrix()
|
|
{
|
|
var matrix = _matrices["Wide2x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var s = new Complex[matrix.RowCount];
|
|
var u = new Complex[matrix.RowCount*matrix.RowCount];
|
|
var vt = new Complex[matrix.ColumnCount*matrix.ColumnCount];
|
|
|
|
Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt);
|
|
|
|
var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount);
|
|
for (var index = 0; index < s.Length; index++)
|
|
{
|
|
w[index, index] = s[index];
|
|
}
|
|
|
|
var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u);
|
|
var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt);
|
|
var result = mU*w*mV;
|
|
|
|
AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 14);
|
|
AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 14);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using SVD factorization with a square A matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingSVDSquareMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.SvdSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x);
|
|
|
|
NotModified(3, 3, a, matrix);
|
|
|
|
var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
|
|
var mb = matrix*mx;
|
|
|
|
AssertHelpers.AlmostEqual(mb[0, 0], b[0], 13);
|
|
AssertHelpers.AlmostEqual(mb[1, 0], b[1], 13);
|
|
AssertHelpers.AlmostEqual(mb[2, 0], b[2], 13);
|
|
AssertHelpers.AlmostEqual(mb[0, 1], b[3], 13);
|
|
AssertHelpers.AlmostEqual(mb[1, 1], b[4], 13);
|
|
AssertHelpers.AlmostEqual(mb[2, 1], b[5], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using SVD factorization with a tall A matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingSVDTallMatrix()
|
|
{
|
|
var matrix = _matrices["Tall3x2"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.SvdSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x);
|
|
|
|
NotModified(3, 2, a, matrix);
|
|
|
|
var mb = new DenseMatrix(matrix.RowCount, 2, b);
|
|
var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb;
|
|
|
|
AssertHelpers.AlmostEqual(test[0, 0], x[0], 13);
|
|
AssertHelpers.AlmostEqual(test[1, 0], x[1], 13);
|
|
AssertHelpers.AlmostEqual(test[0, 1], x[2], 13);
|
|
AssertHelpers.AlmostEqual(test[1, 1], x[3], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using SVD factorization with a square A matrix
|
|
/// using a factored matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingSVDSquareMatrixOnFactoredMatrix()
|
|
{
|
|
var matrix = _matrices["Square3x3"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var s = new Complex[matrix.RowCount];
|
|
var u = new Complex[matrix.RowCount*matrix.RowCount];
|
|
var vt = new Complex[matrix.ColumnCount*matrix.ColumnCount];
|
|
|
|
Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.SvdSolveFactored(matrix.RowCount, matrix.ColumnCount, s, u, vt, b, 2, x);
|
|
|
|
var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
|
|
var mb = matrix*mx;
|
|
|
|
AssertHelpers.AlmostEqual(mb[0, 0], b[0], 13);
|
|
AssertHelpers.AlmostEqual(mb[1, 0], b[1], 13);
|
|
AssertHelpers.AlmostEqual(mb[2, 0], b[2], 13);
|
|
AssertHelpers.AlmostEqual(mb[0, 1], b[3], 13);
|
|
AssertHelpers.AlmostEqual(mb[1, 1], b[4], 13);
|
|
AssertHelpers.AlmostEqual(mb[2, 1], b[5], 13);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can solve Ax=b using SVD factorization with a tall A matrix
|
|
/// using a factored matrix.
|
|
/// </summary>
|
|
[Test]
|
|
public void CanSolveUsingSVDTallMatrixOnFactoredMatrix()
|
|
{
|
|
var matrix = _matrices["Tall3x2"];
|
|
var a = new Complex[matrix.RowCount*matrix.ColumnCount];
|
|
Array.Copy(matrix.Values, a, a.Length);
|
|
|
|
var s = new Complex[matrix.ColumnCount];
|
|
var u = new Complex[matrix.RowCount*matrix.RowCount];
|
|
var vt = new Complex[matrix.ColumnCount*matrix.ColumnCount];
|
|
|
|
Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt);
|
|
|
|
var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0};
|
|
var x = new Complex[matrix.ColumnCount*2];
|
|
Control.LinearAlgebraProvider.SvdSolveFactored(matrix.RowCount, matrix.ColumnCount, s, u, vt, b, 2, x);
|
|
|
|
var mb = new DenseMatrix(matrix.RowCount, 2, b);
|
|
var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb;
|
|
|
|
AssertHelpers.AlmostEqual(test[0, 0], x[0], 13);
|
|
AssertHelpers.AlmostEqual(test[1, 0], x[1], 13);
|
|
AssertHelpers.AlmostEqual(test[0, 1], x[2], 13);
|
|
AssertHelpers.AlmostEqual(test[1, 1], x[3], 13);
|
|
}
|
|
|
|
[TestCase("Wide10x50000", "Tall50000x10")]
|
|
[TestCase("Square1000x1000", "Square1000x1000")]
|
|
[Explicit, Timeout(1000*10)]
|
|
public void IsMatrixMultiplicationPerformant(string leftMatrixKey, string rightMatrixKey)
|
|
{
|
|
var leftMatrix = _matrices[leftMatrixKey];
|
|
var rightMatrix = _matrices[rightMatrixKey];
|
|
var result = leftMatrix*rightMatrix;
|
|
Assert.That(result, Is.Not.Null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see if a matrix and array contain the same values.
|
|
/// </summary>
|
|
/// <param name="rows">number of rows.</param>
|
|
/// <param name="columns">number of columns.</param>
|
|
/// <param name="array">array to check.</param>
|
|
/// <param name="matrix">matrix to check against.</param>
|
|
static void NotModified(int rows, int columns, IList<Complex> array, Matrix<Complex> matrix)
|
|
{
|
|
var index = 0;
|
|
for (var col = 0; col < columns; col++)
|
|
{
|
|
for (var row = 0; row < rows; row++)
|
|
{
|
|
Assert.AreEqual(array[index++], matrix[row, col]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|