forked from tsai/mathnet-numerics
87 changed files with 31103 additions and 118 deletions
File diff suppressed because it is too large
@ -0,0 +1,732 @@ |
|||
// <copyright file="DenseMatrix.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-2010 Math.NET
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32 |
|||
{ |
|||
using System; |
|||
using Distributions; |
|||
using Generic; |
|||
using Numerics; |
|||
using Properties; |
|||
using Threading; |
|||
|
|||
/// <summary>
|
|||
/// A Matrix class with dense storage. The underlying storage is a one dimensional array in column-major order.
|
|||
/// </summary>
|
|||
public class DenseMatrix : Matrix<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DenseMatrix"/> class. This matrix is square with a given size.
|
|||
/// </summary>
|
|||
/// <param name="order">the size of the square matrix.</param>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// If <paramref name="order"/> is less than one.
|
|||
/// </exception>
|
|||
public DenseMatrix(int order) |
|||
: base(order) |
|||
{ |
|||
Data = new Complex32[order * order]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DenseMatrix"/> class.
|
|||
/// </summary>
|
|||
/// <param name="rows">
|
|||
/// The number of rows.
|
|||
/// </param>
|
|||
/// <param name="columns">
|
|||
/// The number of columns.
|
|||
/// </param>
|
|||
public DenseMatrix(int rows, int columns) |
|||
: base(rows, columns) |
|||
{ |
|||
Data = new Complex32[rows * columns]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DenseMatrix"/> class with all entries set to a particular value.
|
|||
/// </summary>
|
|||
/// <param name="rows">
|
|||
/// The number of rows.
|
|||
/// </param>
|
|||
/// <param name="columns">
|
|||
/// The number of columns.
|
|||
/// </param>
|
|||
/// <param name="value">The value which we assign to each element of the matrix.</param>
|
|||
public DenseMatrix(int rows, int columns, Complex32 value) |
|||
: base(rows, columns) |
|||
{ |
|||
Data = new Complex32[rows * columns]; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
Data[i] = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DenseMatrix"/> class from a one dimensional array. This constructor
|
|||
/// will reference the one dimensional array and not copy it.
|
|||
/// </summary>
|
|||
/// <param name="rows">The number of rows.</param>
|
|||
/// <param name="columns">The number of columns.</param>
|
|||
/// <param name="array">The one dimensional array to create this matrix from. This array should store the matrix in column-major order. <seealso cref="http://en.wikipedia.org/wiki/Row-major_order"/></param>
|
|||
public DenseMatrix(int rows, int columns, Complex32[] array) |
|||
: base(rows, columns) |
|||
{ |
|||
Data = array; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DenseMatrix"/> class from a 2D array. This constructor
|
|||
/// will allocate a completely new memory block for storing the dense matrix.
|
|||
/// </summary>
|
|||
/// <param name="array">The 2D array to create this matrix from.</param>
|
|||
public DenseMatrix(Complex32[,] array) |
|||
: base(array.GetLength(0), array.GetLength(1)) |
|||
{ |
|||
var rows = array.GetLength(0); |
|||
var columns = array.GetLength(1); |
|||
Data = new Complex32[rows * columns]; |
|||
for (var i = 0; i < rows; i++) |
|||
{ |
|||
for (var j = 0; j < columns; j++) |
|||
{ |
|||
Data[(j * rows) + i] = array[i, j]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the matrix's data.
|
|||
/// </summary>
|
|||
/// <value>The matrix's data.</value>
|
|||
internal Complex32[] Data |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a <c>DenseMatrix</c> for the given number of rows and columns.
|
|||
/// </summary>
|
|||
/// <param name="numberOfRows">
|
|||
/// The number of rows.
|
|||
/// </param>
|
|||
/// <param name="numberOfColumns">
|
|||
/// The number of columns.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A <c>DenseMatrix</c> with the given dimensions.
|
|||
/// </returns>
|
|||
public override Matrix<Complex32> CreateMatrix(int numberOfRows, int numberOfColumns) |
|||
{ |
|||
return new DenseMatrix(numberOfRows, numberOfColumns); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a <see cref="Vector{T}"/> with a the given dimension.
|
|||
/// </summary>
|
|||
/// <param name="size">The size of the vector.</param>
|
|||
/// <returns>
|
|||
/// A <see cref="Vector{T}"/> with the given dimension.
|
|||
/// </returns>
|
|||
public override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new DenseVector(size); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Retrieves the requested element without range checking.
|
|||
/// </summary>
|
|||
/// <param name="row">
|
|||
/// The row of the element.
|
|||
/// </param>
|
|||
/// <param name="column">
|
|||
/// The column of the element.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The requested element.
|
|||
/// </returns>
|
|||
public override Complex32 At(int row, int column) |
|||
{ |
|||
return Data[(column * RowCount) + row]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the given element.
|
|||
/// </summary>
|
|||
/// <param name="row">
|
|||
/// The row of the element.
|
|||
/// </param>
|
|||
/// <param name="column">
|
|||
/// The column of the element.
|
|||
/// </param>
|
|||
/// <param name="value">
|
|||
/// The value to set the element to.
|
|||
/// </param>
|
|||
public override void At(int row, int column, Complex32 value) |
|||
{ |
|||
Data[(column * RowCount) + row] = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets all values to zero.
|
|||
/// </summary>
|
|||
public override void Clear() |
|||
{ |
|||
Array.Clear(Data, 0, Data.Length); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the transpose of this matrix.
|
|||
/// </summary>
|
|||
/// <returns>The transpose of this matrix.</returns>
|
|||
public override Matrix<Complex32> Transpose() |
|||
{ |
|||
var ret = new DenseMatrix(ColumnCount, RowCount); |
|||
for (var j = 0; j < ColumnCount; j++) |
|||
{ |
|||
var index = j * RowCount; |
|||
for (var i = 0; i < RowCount; i++) |
|||
{ |
|||
ret.Data[(i * ColumnCount) + j] = Data[index + i]; |
|||
} |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the conjugate transpose of this matrix.
|
|||
/// </summary>
|
|||
/// <returns>The conjugate transpose of this matrix.</returns>
|
|||
public override Matrix<Complex32> ConjugateTranspose() |
|||
{ |
|||
var ret = new DenseMatrix(ColumnCount, RowCount); |
|||
for (var j = 0; j < ColumnCount; j++) |
|||
{ |
|||
var index = j * RowCount; |
|||
for (var i = 0; i < RowCount; i++) |
|||
{ |
|||
ret.Data[(i * ColumnCount) + j] = Data[index + i].Conjugate(); |
|||
} |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
/// <summary>Calculates the L1 norm.</summary>
|
|||
/// <returns>The L1 norm of the matrix.</returns>
|
|||
public override double L1Norm() |
|||
{ |
|||
var norm = 0.0; |
|||
for (var j = 0; j < ColumnCount; j++) |
|||
{ |
|||
var s = 0.0; |
|||
for (var i = 0; i < RowCount; i++) |
|||
{ |
|||
s += Data[(j * RowCount) + i].Magnitude; |
|||
} |
|||
|
|||
norm = Math.Max(norm, s); |
|||
} |
|||
|
|||
return norm; |
|||
} |
|||
|
|||
/// <summary>Calculates the Frobenius norm of this matrix.</summary>
|
|||
/// <returns>The Frobenius norm of this matrix.</returns>
|
|||
public override double FrobeniusNorm() |
|||
{ |
|||
var transpose = (DenseMatrix)Transpose(); |
|||
var aat = this * transpose; |
|||
|
|||
var norm = 0.0; |
|||
for (var i = 0; i < RowCount; i++) |
|||
{ |
|||
norm += aat.Data[(i * RowCount) + i].Magnitude; |
|||
} |
|||
|
|||
norm = Math.Sqrt(norm); |
|||
return norm; |
|||
} |
|||
|
|||
/// <summary>Calculates the infinity norm of this matrix.</summary>
|
|||
/// <returns>The infinity norm of this matrix.</returns>
|
|||
public override double InfinityNorm() |
|||
{ |
|||
var norm = 0.0; |
|||
for (var i = 0; i < RowCount; i++) |
|||
{ |
|||
var s = 0.0; |
|||
for (var j = 0; j < ColumnCount; j++) |
|||
{ |
|||
s += Data[(j * RowCount) + i].Magnitude; |
|||
} |
|||
|
|||
norm = Math.Max(norm, s); |
|||
} |
|||
|
|||
return norm; |
|||
} |
|||
|
|||
#region Elementary operations
|
|||
|
|||
/// <summary>
|
|||
/// Adds another matrix to this matrix. The result will be written into this matrix.
|
|||
/// </summary>
|
|||
/// <param name="other">The matrix to add to this matrix.</param>
|
|||
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
|
|||
public override void Add(Matrix<Complex32> other) |
|||
{ |
|||
var m = other as DenseMatrix; |
|||
if (m == null) |
|||
{ |
|||
base.Add(other); |
|||
} |
|||
else |
|||
{ |
|||
Add(m); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds another <see cref="DenseMatrix"/> to this matrix. The result will be written into this matrix.
|
|||
/// </summary>
|
|||
/// <param name="other">The <see cref="DenseMatrix"/> to add to this matrix.</param>
|
|||
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
|
|||
public void Add(DenseMatrix other) |
|||
{ |
|||
if (other == null) |
|||
{ |
|||
throw new ArgumentNullException("other"); |
|||
} |
|||
|
|||
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
Control.LinearAlgebraProvider.AddArrays(Data, other.Data, Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Subtracts another matrix from this matrix. The result will be written into this matrix.
|
|||
/// </summary>
|
|||
/// <param name="other">The matrix to subtract.</param>
|
|||
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
|
|||
public override void Subtract(Matrix<Complex32> other) |
|||
{ |
|||
var m = other as DenseMatrix; |
|||
if (m == null) |
|||
{ |
|||
base.Subtract(other); |
|||
} |
|||
else |
|||
{ |
|||
Subtract(m); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Subtracts another <see cref="DenseMatrix"/> from this matrix. The result will be written into this matrix.
|
|||
/// </summary>
|
|||
/// <param name="other">The <see cref="DenseMatrix"/> to subtract.</param>
|
|||
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
|
|||
public void Subtract(DenseMatrix other) |
|||
{ |
|||
if (other == null) |
|||
{ |
|||
throw new ArgumentNullException("other"); |
|||
} |
|||
|
|||
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiplies each element of this matrix with a complex.
|
|||
/// </summary>
|
|||
/// <param name="complex">The complex to multiply with.</param>
|
|||
public override void Multiply(Complex32 complex) |
|||
{ |
|||
Control.LinearAlgebraProvider.ScaleArray(complex, Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiplies this dense matrix with another dense matrix and places the results into the result dense matrix.
|
|||
/// </summary>
|
|||
/// <param name="other">The matrix to multiply with.</param>
|
|||
/// <param name="result">The result of the multiplication.</param>
|
|||
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception>
|
|||
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the this.Rows x other.Columns.</exception>
|
|||
public override void Multiply(Matrix<Complex32> other, Matrix<Complex32> result) |
|||
{ |
|||
if (other == null) |
|||
{ |
|||
throw new ArgumentNullException("other"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (ColumnCount != other.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
if (result.RowCount != RowCount || result.ColumnCount != other.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var m = other as DenseMatrix; |
|||
var r = result as DenseMatrix; |
|||
|
|||
if (m == null || r == null) |
|||
{ |
|||
base.Multiply(other, result); |
|||
} |
|||
else |
|||
{ |
|||
Control.LinearAlgebraProvider.MatrixMultiply( |
|||
Data, |
|||
RowCount, |
|||
ColumnCount, |
|||
m.Data, |
|||
m.RowCount, |
|||
m.ColumnCount, |
|||
r.Data); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiplies this matrix with another matrix and returns the result.
|
|||
/// </summary>
|
|||
/// <param name="other">The matrix to multiply with.</param>
|
|||
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception>
|
|||
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
|
|||
/// <returns>The result of multiplication.</returns>
|
|||
public override Matrix<Complex32> Multiply(Matrix<Complex32> other) |
|||
{ |
|||
if (other == null) |
|||
{ |
|||
throw new ArgumentNullException("other"); |
|||
} |
|||
|
|||
if (ColumnCount != other.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var m = other as DenseMatrix; |
|||
if (m == null) |
|||
{ |
|||
return base.Multiply(other); |
|||
} |
|||
|
|||
var result = (DenseMatrix)CreateMatrix(RowCount, other.ColumnCount); |
|||
Multiply(other, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiplies this dense matrix with transpose of another dense matrix and places the results into the result dense matrix.
|
|||
/// </summary>
|
|||
/// <param name="other">The matrix to multiply with.</param>
|
|||
/// <param name="result">The result of the multiplication.</param>
|
|||
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception>
|
|||
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the this.Rows x other.Columns.</exception>
|
|||
public override void TransposeAndMultiply(Matrix<Complex32> other, Matrix<Complex32> result) |
|||
{ |
|||
var otherDense = other as DenseMatrix; |
|||
var resultDense = result as DenseMatrix; |
|||
|
|||
if (otherDense == null || resultDense == null) |
|||
{ |
|||
base.TransposeAndMultiply(other, result); |
|||
return; |
|||
} |
|||
|
|||
if (ColumnCount != otherDense.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
if ((resultDense.RowCount != RowCount) || (resultDense.ColumnCount != otherDense.RowCount)) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate( |
|||
Algorithms.LinearAlgebra.Transpose.DontTranspose, |
|||
Algorithms.LinearAlgebra.Transpose.Transpose, |
|||
Complex32.One, |
|||
Data, |
|||
RowCount, |
|||
ColumnCount, |
|||
otherDense.Data, |
|||
otherDense.RowCount, |
|||
otherDense.ColumnCount, |
|||
Complex32.One, |
|||
resultDense.Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiplies this matrix with transpose of another matrix and returns the result.
|
|||
/// </summary>
|
|||
/// <param name="other">The matrix to multiply with.</param>
|
|||
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception>
|
|||
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
|
|||
/// <returns>The result of multiplication.</returns>
|
|||
public override Matrix<Complex32> TransposeAndMultiply(Matrix<Complex32> other) |
|||
{ |
|||
var otherDense = other as DenseMatrix; |
|||
if (otherDense == null) |
|||
{ |
|||
return base.TransposeAndMultiply(other); |
|||
} |
|||
|
|||
if (ColumnCount != otherDense.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var result = (DenseMatrix)CreateMatrix(RowCount, other.RowCount); |
|||
TransposeAndMultiply(other, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiplies two dense matrices.
|
|||
/// </summary>
|
|||
/// <param name="leftSide">The left matrix to multiply.</param>
|
|||
/// <param name="rightSide">The right matrix to multiply.</param>
|
|||
/// <returns>The result of multiplication.</returns>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentException">If the dimensions of <paramref name="leftSide"/> or <paramref name="rightSide"/> don't conform.</exception>
|
|||
public static DenseMatrix operator *(DenseMatrix leftSide, DenseMatrix rightSide) |
|||
{ |
|||
if (leftSide == null) |
|||
{ |
|||
throw new ArgumentNullException("leftSide"); |
|||
} |
|||
|
|||
if (rightSide == null) |
|||
{ |
|||
throw new ArgumentNullException("rightSide"); |
|||
} |
|||
|
|||
if (leftSide.ColumnCount != rightSide.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
return (DenseMatrix)leftSide.Multiply(rightSide); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Static constructors for special matrices.
|
|||
|
|||
/// <summary>
|
|||
/// Initializes a square <see cref="DenseMatrix"/> with all zero's except for ones on the diagonal.
|
|||
/// </summary>
|
|||
/// <param name="order">the size of the square matrix.</param>
|
|||
/// <returns>A dense identity matrix.</returns>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// If <paramref name="order"/> is less than one.
|
|||
/// </exception>
|
|||
public static DenseMatrix Identity(int order) |
|||
{ |
|||
var m = new DenseMatrix(order); |
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
m[i, i] = Complex32.One; |
|||
} |
|||
|
|||
return m; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
/// <summary>
|
|||
/// Negate each element of this matrix.
|
|||
/// </summary>
|
|||
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentException">if the result matrix's dimensions are not the same as this matrix.</exception>
|
|||
public override void Negate() |
|||
{ |
|||
Multiply(-1); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Generates matrix with random elements.
|
|||
/// </summary>
|
|||
/// <param name="numberOfRows">Number of rows.</param>
|
|||
/// <param name="numberOfColumns">Number of columns.</param>
|
|||
/// <param name="distribution">Continuous Random Distribution or Source</param>
|
|||
/// <returns>
|
|||
/// An <c>numberOfRows</c>-by-<c>numberOfColumns</c> matrix with elements distributed according to the provided distribution.
|
|||
/// </returns>
|
|||
/// <exception cref="ArgumentException">If the parameter <paramref name="numberOfRows"/> is not positive.</exception>
|
|||
/// <exception cref="ArgumentException">If the parameter <paramref name="numberOfColumns"/> is not positive.</exception>
|
|||
public override Matrix<Complex32> Random(int numberOfRows, int numberOfColumns, IContinuousDistribution distribution) |
|||
{ |
|||
if (numberOfRows < 1) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows"); |
|||
} |
|||
|
|||
if (numberOfColumns < 1) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); |
|||
} |
|||
|
|||
var matrix = CreateMatrix(numberOfRows, numberOfColumns); |
|||
CommonParallel.For( |
|||
0, |
|||
ColumnCount, |
|||
j => |
|||
{ |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
matrix[i, j] = new Complex32((float)distribution.Sample(), (float)distribution.Sample()); |
|||
} |
|||
}); |
|||
|
|||
return matrix; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Generates matrix with random elements.
|
|||
/// </summary>
|
|||
/// <param name="numberOfRows">Number of rows.</param>
|
|||
/// <param name="numberOfColumns">Number of columns.</param>
|
|||
/// <param name="distribution">Continuous Random Distribution or Source</param>
|
|||
/// <returns>
|
|||
/// An <c>numberOfRows</c>-by-<c>numberOfColumns</c> matrix with elements distributed according to the provided distribution.
|
|||
/// </returns>
|
|||
/// <exception cref="ArgumentException">If the parameter <paramref name="numberOfRows"/> is not positive.</exception>
|
|||
/// <exception cref="ArgumentException">If the parameter <paramref name="numberOfColumns"/> is not positive.</exception>
|
|||
public override Matrix<Complex32> Random(int numberOfRows, int numberOfColumns, IDiscreteDistribution distribution) |
|||
{ |
|||
if (numberOfRows < 1) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows"); |
|||
} |
|||
|
|||
if (numberOfColumns < 1) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); |
|||
} |
|||
|
|||
var matrix = CreateMatrix(numberOfRows, numberOfColumns); |
|||
CommonParallel.For( |
|||
0, |
|||
ColumnCount, |
|||
j => |
|||
{ |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
matrix[i, j] = new Complex32(distribution.Sample(), distribution.Sample()); |
|||
} |
|||
}); |
|||
|
|||
return matrix; |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
/// <summary>
|
|||
/// Add two values T+T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of addition</returns>
|
|||
protected sealed override Complex32 AddT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 + val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Subtract two values T-T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of subtract</returns>
|
|||
protected sealed override Complex32 SubtractT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 - val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Divide two values T/T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of divide</returns>
|
|||
protected sealed override Complex32 DivideT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 / val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Take absolute value
|
|||
/// </summary>
|
|||
/// <param name="val1">Source alue</param>
|
|||
/// <returns>True if one; otherwise false</returns>
|
|||
protected sealed override double AbsoluteT(Complex32 val1) |
|||
{ |
|||
return val1.Magnitude; |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,214 @@ |
|||
// <copyright file="DenseCholesky.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Factorization; |
|||
using Numerics; |
|||
using Properties; |
|||
using Threading; |
|||
|
|||
/// <summary>
|
|||
/// <para>A class which encapsulates the functionality of a Cholesky factorization for dense matrices.</para>
|
|||
/// <para>For a symmetric, positive definite matrix A, the Cholesky factorization
|
|||
/// is an lower triangular matrix L so that A = L*L'.</para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The computation of the Cholesky factorization is done at construction time. If the matrix is not symmetric
|
|||
/// or positive definite, the constructor will throw an exception.
|
|||
/// </remarks>
|
|||
public class DenseCholesky : Cholesky<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DenseCholesky"/> class. This object will compute the
|
|||
/// Cholesky factorization when the constructor is called and cache it's factorization.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix to factor.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not positive definite.</exception>
|
|||
public DenseCholesky(DenseMatrix matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare); |
|||
} |
|||
|
|||
// Create a new matrix for the Cholesky factor, then perform factorization (while overwriting).
|
|||
var factor = (DenseMatrix)matrix.Clone(); |
|||
Control.LinearAlgebraProvider.CholeskyFactor(factor.Data, factor.RowCount); |
|||
CholeskyFactor = factor; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>AX = B</b>, with A Cholesky factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side <see cref="Matrix{T}"/>, <b>B</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) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Check for proper dimensions.
|
|||
if (result.RowCount != input.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); |
|||
} |
|||
|
|||
if (result.ColumnCount != input.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
if (input.RowCount != CholeskyFactor.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var dinput = input as DenseMatrix; |
|||
if (dinput == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do Cholesky factorization for dense matrices at the moment."); |
|||
} |
|||
|
|||
var dresult = result as DenseMatrix; |
|||
if (dresult == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do Cholesky factorization for dense matrices at the moment."); |
|||
} |
|||
|
|||
// Copy the contents of input to result.
|
|||
CommonParallel.For(0, dinput.Data.Length, index => dresult.Data[index] = dinput.Data[index]); |
|||
|
|||
// Cholesky solve by overwriting result.
|
|||
var dfactor = (DenseMatrix)CholeskyFactor; |
|||
Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Data, dresult.RowCount, dresult.ColumnCount); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>Ax = b</b>, with A Cholesky factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side vector, <b>b</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) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Check for proper dimensions.
|
|||
if (input.Count != result.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
if (input.Count != CholeskyFactor.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var dinput = input as DenseVector; |
|||
if (dinput == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do Cholesky factorization for dense vectors at the moment."); |
|||
} |
|||
|
|||
var dresult = result as DenseVector; |
|||
if (dresult == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do Cholesky factorization for dense vectors at the moment."); |
|||
} |
|||
|
|||
// Copy the contents of input to result.
|
|||
CommonParallel.For(0, dinput.Data.Length, index => dresult.Data[index] = dinput.Data[index]); |
|||
|
|||
// Cholesky solve by overwriting result.
|
|||
var dfactor = (DenseMatrix)CholeskyFactor; |
|||
Control.LinearAlgebraProvider.CholeskySolveFactored(dfactor.Data, dfactor.RowCount, dresult.Data, dresult.Count, 1); |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
/// <summary>
|
|||
/// Add two values T+T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of addition</returns>
|
|||
protected sealed override Complex32 AddT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 + val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the natural (base e) logarithm of a specified number.
|
|||
/// </summary>
|
|||
/// <param name="val1"> A number whose logarithm is to be found</param>
|
|||
/// <returns>Natural (base e) logarithm </returns>
|
|||
protected sealed override Complex32 LogT(Complex32 val1) |
|||
{ |
|||
return val1.NaturalLogarithm(); |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,206 @@ |
|||
// <copyright file="DenseLU.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Factorization; |
|||
using Numerics; |
|||
using Properties; |
|||
using Threading; |
|||
|
|||
/// <summary>
|
|||
/// <para>A class which encapsulates the functionality of an LU factorization.</para>
|
|||
/// <para>For a matrix A, the LU factorization is a pair of lower triangular matrix L and
|
|||
/// upper triangular matrix U so that A = L*U.</para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The computation of the LU factorization is done at construction time.
|
|||
/// </remarks>
|
|||
public class DenseLU : LU<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DenseLU"/> class. This object will compute the
|
|||
/// LU factorization when the constructor is called and cache it's factorization.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix to factor.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
|
|||
public DenseLU(DenseMatrix matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare); |
|||
} |
|||
|
|||
// Create an array for the pivot indices.
|
|||
Pivots = new int[matrix.RowCount]; |
|||
|
|||
// Create a new matrix for the LU factors, then perform factorization (while overwriting).
|
|||
var factors = (DenseMatrix)matrix.Clone(); |
|||
Control.LinearAlgebraProvider.LUFactor(factors.Data, factors.RowCount, Pivots); |
|||
Factors = factors; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <c>AX = B</c>, with A LU factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side <see cref="Matrix{T}"/>, <c>B</c>.</param>
|
|||
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <c>X</c>.</param>
|
|||
public override void Solve(Matrix<Complex32> input, Matrix<Complex32> result) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Check for proper dimensions.
|
|||
if (result.RowCount != input.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); |
|||
} |
|||
|
|||
if (result.ColumnCount != input.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
if (input.RowCount != Factors.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var dinput = input as DenseMatrix; |
|||
if (dinput == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do LU factorization for dense matrices at the moment."); |
|||
} |
|||
|
|||
var dresult = result as DenseMatrix; |
|||
if (dresult == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do LU factorization for dense matrices at the moment."); |
|||
} |
|||
|
|||
// Copy the contents of input to result.
|
|||
CommonParallel.For(0, dinput.Data.Length, index => dresult.Data[index] = dinput.Data[index]); |
|||
|
|||
// LU solve by overwriting result.
|
|||
var dfactors = (DenseMatrix)Factors; |
|||
Control.LinearAlgebraProvider.LUSolveFactored(input.ColumnCount, dfactors.Data, dfactors.RowCount, Pivots, dresult.Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <c>Ax = b</c>, with A LU factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side vector, <c>b</c>.</param>
|
|||
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <c>x</c>.</param>
|
|||
public override void Solve(Vector<Complex32> input, Vector<Complex32> result) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Check for proper dimensions.
|
|||
if (input.Count != result.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
if (input.Count != Factors.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var dinput = input as DenseVector; |
|||
if (dinput == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do LU factorization for dense vectors at the moment."); |
|||
} |
|||
|
|||
var dresult = result as DenseVector; |
|||
if (dresult == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do LU factorization for dense vectors at the moment."); |
|||
} |
|||
|
|||
// Copy the contents of input to result.
|
|||
CommonParallel.For(0, dinput.Data.Length, index => dresult.Data[index] = dinput.Data[index]); |
|||
|
|||
// LU solve by overwriting result.
|
|||
var dfactors = (DenseMatrix)Factors; |
|||
Control.LinearAlgebraProvider.LUSolveFactored(1, dfactors.Data, dfactors.RowCount, Pivots, dresult.Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the inverse of this matrix. The inverse is calculated using LU decomposition.
|
|||
/// </summary>
|
|||
/// <returns>The inverse of this matrix.</returns>
|
|||
public override Matrix<Complex32> Inverse() |
|||
{ |
|||
var result = (DenseMatrix)Factors.Clone(); |
|||
Control.LinearAlgebraProvider.LUInverseFactored(result.Data, result.RowCount, Pivots); |
|||
return result; |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,195 @@ |
|||
// <copyright file="DenseQR.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Factorization; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// <para>A class which encapsulates the functionality of the QR decomposition.</para>
|
|||
/// <para>Any real square matrix A may be decomposed as A = QR where Q is an orthogonal matrix
|
|||
/// (its columns are orthogonal unit vectors meaning QTQ = I) and R is an upper triangular matrix
|
|||
/// (also called right triangular matrix).</para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The computation of the QR decomposition is done at construction time by Householder transformation.
|
|||
/// </remarks>
|
|||
public class DenseQR : QR<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DenseQR"/> class. This object will compute the
|
|||
/// QR factorization when the constructor is called and cache it's factorization.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix to factor.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> row count is less then column count</exception>
|
|||
public DenseQR(DenseMatrix matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount < matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
MatrixR = matrix.Clone(); |
|||
MatrixQ = new DenseMatrix(matrix.RowCount); |
|||
Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount, ((DenseMatrix)MatrixQ).Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>AX = B</b>, with A QR factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side <see cref="Matrix{T}"/>, <b>B</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) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// The solution X should have the same number of columns as B
|
|||
if (input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
// The dimension compatibility conditions for X = A\B require the two matrices A and B to have the same number of rows
|
|||
if (MatrixR.RowCount != input.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); |
|||
} |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
if (MatrixR.ColumnCount != result.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
var dinput = input as DenseMatrix; |
|||
if (dinput == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do QR factorization for dense matrices at the moment."); |
|||
} |
|||
|
|||
var dresult = result as DenseMatrix; |
|||
if (dresult == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do QR factorization for dense matrices at the moment."); |
|||
} |
|||
|
|||
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, dinput.Data, input.ColumnCount, dresult.Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>Ax = b</b>, with A QR factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side vector, <b>b</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) |
|||
{ |
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Ax=b where A is an m x n matrix
|
|||
// Check that b is a column vector with m entries
|
|||
if (MatrixR.RowCount != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Check that x is a column vector with n entries
|
|||
if (MatrixR.ColumnCount != result.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var dinput = input as DenseVector; |
|||
if (dinput == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do QR factorization for dense vectors at the moment."); |
|||
} |
|||
|
|||
var dresult = result as DenseVector; |
|||
if (dresult == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do QR factorization for dense vectors at the moment."); |
|||
} |
|||
|
|||
Control.LinearAlgebraProvider.QRSolveFactored(((DenseMatrix)MatrixQ).Data, ((DenseMatrix)MatrixR).Data, MatrixR.RowCount, MatrixR.ColumnCount, dinput.Data, 1, dresult.Data); |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the absolute value of a specified number.
|
|||
/// </summary>
|
|||
/// <param name="val1"> A number whose absolute is to be found</param>
|
|||
/// <returns>Absolute value </returns>
|
|||
protected sealed override double AbsoluteT(Complex32 val1) |
|||
{ |
|||
return val1.Magnitude; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,207 @@ |
|||
// <copyright file="DenseSvd.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Factorization; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// <para>A class which encapsulates the functionality of the singular value decomposition (SVD) for <see cref="DenseMatrix"/>.</para>
|
|||
/// <para>Suppose M is an m-by-n matrix whose entries are real numbers.
|
|||
/// Then there exists a factorization of the form M = UΣVT where:
|
|||
/// - U is an m-by-m unitary matrix;
|
|||
/// - Σ is m-by-n diagonal matrix with nonnegative real numbers on the diagonal;
|
|||
/// - VT denotes transpose of V, an n-by-n unitary matrix;
|
|||
/// Such a factorization is called a singular-value decomposition of M. A common convention is to order the diagonal
|
|||
/// entries Σ(i,i) in descending order. In this case, the diagonal matrix Σ is uniquely determined
|
|||
/// by M (though the matrices U and V are not). The diagonal entries of Σ are known as the singular values of M.</para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The computation of the singular value decomposition is done at construction time.
|
|||
/// </remarks>
|
|||
public class DenseSvd : Svd<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DenseSvd"/> class. This object will compute the
|
|||
/// the singular value decomposition when the constructor is called and cache it's decomposition.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix to factor.</param>
|
|||
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <b>null</b>.</exception>
|
|||
/// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception>
|
|||
public DenseSvd(DenseMatrix matrix, bool computeVectors) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
ComputeVectors = computeVectors; |
|||
var nm = Math.Min(matrix.RowCount, matrix.ColumnCount); |
|||
VectorS = new DenseVector(nm); |
|||
MatrixU = new DenseMatrix(matrix.RowCount); |
|||
MatrixVT = new DenseMatrix(matrix.ColumnCount); |
|||
Control.LinearAlgebraProvider.SingularValueDecomposition(computeVectors, ((DenseMatrix)matrix.Clone()).Data, matrix.RowCount, matrix.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side <see cref="Matrix{T}"/>, <b>B</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) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (!ComputeVectors) |
|||
{ |
|||
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); |
|||
} |
|||
|
|||
// The solution X should have the same number of columns as B
|
|||
if (input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
// The dimension compatibility conditions for X = A\B require the two matrices A and B to have the same number of rows
|
|||
if (MatrixU.RowCount != input.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); |
|||
} |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
if (MatrixVT.ColumnCount != result.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
var dinput = input as DenseMatrix; |
|||
if (dinput == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do SVD factorization for dense matrices at the moment."); |
|||
} |
|||
|
|||
var dresult = result as DenseMatrix; |
|||
if (dresult == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do SVD factorization for dense matrices at the moment."); |
|||
} |
|||
|
|||
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, input.ColumnCount, dresult.Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>Ax = b</b>, with A SVD factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side vector, <b>b</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) |
|||
{ |
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (!ComputeVectors) |
|||
{ |
|||
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); |
|||
} |
|||
|
|||
// Ax=b where A is an m x n matrix
|
|||
// Check that b is a column vector with m entries
|
|||
if (MatrixU.RowCount != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Check that x is a column vector with n entries
|
|||
if (MatrixVT.ColumnCount != result.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var dinput = input as DenseVector; |
|||
if (dinput == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do SVD factorization for dense vectors at the moment."); |
|||
} |
|||
|
|||
var dresult = result as DenseVector; |
|||
if (dresult == null) |
|||
{ |
|||
throw new NotImplementedException("Can only do SVD factorization for dense vectors at the moment."); |
|||
} |
|||
|
|||
Control.LinearAlgebraProvider.SvdSolveFactored(MatrixU.RowCount, MatrixVT.ColumnCount, ((DenseVector)VectorS).Data, ((DenseMatrix)MatrixU).Data, ((DenseMatrix)MatrixVT).Data, dinput.Data, 1, dresult.Data); |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the absolute value of a specified number.
|
|||
/// </summary>
|
|||
/// <param name="val1"> A number whose absolute is to be found</param>
|
|||
/// <returns>Absolute value </returns>
|
|||
protected sealed override double AbsoluteT(Complex32 val1) |
|||
{ |
|||
return val1.Magnitude; |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,317 @@ |
|||
// <copyright file="GramSchmidt.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Factorization; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// <para>A class which encapsulates the functionality of the QR decomposition Modified Gram-Schmidt Orthogonalization.</para>
|
|||
/// <para>Any complex square matrix A may be decomposed as A = QR where Q is an unitary mxn matrix and R is an nxn upper triangular matrix.</para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The computation of the QR decomposition is done at construction time by modified Gram-Schmidt Orthogonalization.
|
|||
/// </remarks>
|
|||
public class GramSchmidt : QR<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GramSchmidt"/> class. This object creates an unitary matrix
|
|||
/// using the modified Gram-Schmidt method.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix to factor.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> row count is less then column count</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is rank deficient</exception>
|
|||
public GramSchmidt(Matrix<Complex32> matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount < matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
MatrixQ = matrix.Clone(); |
|||
MatrixR = matrix.CreateMatrix(matrix.ColumnCount, matrix.ColumnCount); |
|||
|
|||
for (var k = 0; k < MatrixQ.ColumnCount; k++) |
|||
{ |
|||
var norm = (float)MatrixQ.Column(k).Norm(2); |
|||
if (norm == 0.0f) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixNotRankDeficient); |
|||
} |
|||
|
|||
MatrixR.At(k, k, norm); |
|||
for (var i = 0; i < MatrixQ.RowCount; i++) |
|||
{ |
|||
MatrixQ.At(i, k, MatrixQ.At(i, k) / norm); |
|||
} |
|||
|
|||
for (var j = k + 1; j < MatrixQ.ColumnCount; j++) |
|||
{ |
|||
var dot = Complex32.Zero; |
|||
for (int i = 0; i < MatrixQ.RowCount; i++) |
|||
{ |
|||
dot += MatrixQ.Column(k)[i].Conjugate() * MatrixQ.Column(j)[i]; |
|||
} |
|||
|
|||
MatrixR.At(k, j, dot); |
|||
for (var i = 0; i < MatrixQ.RowCount; i++) |
|||
{ |
|||
var value = MatrixQ.At(i, j) - (MatrixQ.At(i, k) * dot); |
|||
MatrixQ.At(i, j, value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether the matrix is full rank or not.
|
|||
/// </summary>
|
|||
/// <value><c>true</c> if the matrix is full rank; otherwise <c>false</c>.</value>
|
|||
public override bool IsFullRank |
|||
{ |
|||
get |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the determinant of the matrix for which the QR matrix was computed.
|
|||
/// </summary>
|
|||
public override double Determinant |
|||
{ |
|||
get |
|||
{ |
|||
if (MatrixQ.RowCount != MatrixQ.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare); |
|||
} |
|||
|
|||
var det = Complex32.One; |
|||
for (var i = 0; i < MatrixR.ColumnCount; i++) |
|||
{ |
|||
det *= MatrixR.At(i, i); |
|||
if (MatrixR.At(i, i).Magnitude.AlmostEqualInDecimalPlaces(0.0f, 7)) |
|||
{ |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
return det.Magnitude; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>AX = B</b>, with A QR factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side <see cref="Matrix{T}"/>, <b>B</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) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// The solution X should have the same number of columns as B
|
|||
if (input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
// The dimension compatibility conditions for X = A\B require the two matrices A and B to have the same number of rows
|
|||
if (MatrixQ.RowCount != input.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); |
|||
} |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
if (MatrixQ.ColumnCount != result.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
var inputCopy = input.Clone(); |
|||
|
|||
// Compute Y = transpose(Q)*B
|
|||
var column = new Complex32[MatrixQ.RowCount]; |
|||
for (var j = 0; j < input.ColumnCount; j++) |
|||
{ |
|||
for (var k = 0; k < MatrixQ.RowCount; k++) |
|||
{ |
|||
column[k] = inputCopy.At(k, j); |
|||
} |
|||
|
|||
for (var i = 0; i < MatrixQ.ColumnCount; i++) |
|||
{ |
|||
var s = Complex32.Zero; |
|||
for (var k = 0; k < MatrixQ.RowCount; k++) |
|||
{ |
|||
s += MatrixQ.At(k, i).Conjugate() * column[k]; |
|||
} |
|||
|
|||
inputCopy.At(i, j, s); |
|||
} |
|||
} |
|||
|
|||
// Solve R*X = Y;
|
|||
for (var k = MatrixQ.ColumnCount - 1; k >= 0; k--) |
|||
{ |
|||
for (var j = 0; j < input.ColumnCount; j++) |
|||
{ |
|||
inputCopy.At(k, j, inputCopy.At(k, j) / MatrixR.At(k, k)); |
|||
} |
|||
|
|||
for (var i = 0; i < k; i++) |
|||
{ |
|||
for (var j = 0; j < input.ColumnCount; j++) |
|||
{ |
|||
inputCopy.At(i, j, inputCopy.At(i, j) - (inputCopy.At(k, j) * MatrixR.At(i, k))); |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (var i = 0; i < MatrixR.ColumnCount; i++) |
|||
{ |
|||
for (var j = 0; j < input.ColumnCount; j++) |
|||
{ |
|||
result.At(i, j, inputCopy.At(i, j)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>Ax = b</b>, with A QR factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side vector, <b>b</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) |
|||
{ |
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Ax=b where A is an m x n matrix
|
|||
// Check that b is a column vector with m entries
|
|||
if (MatrixQ.RowCount != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Check that x is a column vector with n entries
|
|||
if (MatrixQ.ColumnCount != result.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var inputCopy = input.Clone(); |
|||
|
|||
// Compute Y = transpose(Q)*B
|
|||
var column = new Complex32[MatrixQ.RowCount]; |
|||
for (var k = 0; k < MatrixQ.RowCount; k++) |
|||
{ |
|||
column[k] = inputCopy[k]; |
|||
} |
|||
|
|||
for (var i = 0; i < MatrixQ.ColumnCount; i++) |
|||
{ |
|||
var s = Complex32.Zero; |
|||
for (var k = 0; k < MatrixQ.RowCount; k++) |
|||
{ |
|||
s += MatrixQ.At(k, i).Conjugate() * column[k]; |
|||
} |
|||
|
|||
inputCopy[i] = s; |
|||
} |
|||
|
|||
// Solve R*X = Y;
|
|||
for (var k = MatrixQ.ColumnCount - 1; k >= 0; k--) |
|||
{ |
|||
inputCopy[k] /= MatrixR.At(k, k); |
|||
for (var i = 0; i < k; i++) |
|||
{ |
|||
inputCopy[i] -= inputCopy[k] * MatrixR.At(i, k); |
|||
} |
|||
} |
|||
|
|||
for (var i = 0; i < MatrixR.ColumnCount; i++) |
|||
{ |
|||
result[i] = inputCopy[i]; |
|||
} |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the absolute value of a specified number.
|
|||
/// </summary>
|
|||
/// <param name="val1"> A number whose absolute is to be found</param>
|
|||
/// <returns>Absolute value </returns>
|
|||
protected sealed override double AbsoluteT(Complex32 val1) |
|||
{ |
|||
return val1.Magnitude; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,259 @@ |
|||
// <copyright file="UserCholesky.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Factorization; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// <para>A class which encapsulates the functionality of a Cholesky factorization for user matrices.</para>
|
|||
/// <para>For a symmetric, positive definite matrix A, the Cholesky factorization
|
|||
/// is an lower triangular matrix L so that A = L*L'.</para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The computation of the Cholesky factorization is done at construction time. If the matrix is not symmetric
|
|||
/// or positive definite, the constructor will throw an exception.
|
|||
/// </remarks>
|
|||
public class UserCholesky : Cholesky<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="UserCholesky"/> class. This object will compute the
|
|||
/// Cholesky factorization when the constructor is called and cache it's factorization.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix to factor.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not positive definite.</exception>
|
|||
public UserCholesky(Matrix<Complex32> matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare); |
|||
} |
|||
|
|||
// Create a new matrix for the Cholesky factor, then perform factorization (while overwriting).
|
|||
CholeskyFactor = matrix.Clone(); |
|||
for (var i = 0; i < CholeskyFactor.RowCount; i++) |
|||
{ |
|||
var d = Complex32.Zero; |
|||
for (var j = 0; j < i; j++) |
|||
{ |
|||
var s = Complex32.Zero; |
|||
for (var k = 0; k < j; k++) |
|||
{ |
|||
s += CholeskyFactor.At(i, k) * CholeskyFactor.At(j, k).Conjugate(); |
|||
} |
|||
|
|||
s = (matrix.At(i, j) - s) / CholeskyFactor.At(j, j); |
|||
CholeskyFactor.At(i, j, s); |
|||
d += s * s.Conjugate(); |
|||
} |
|||
|
|||
d = matrix.At(i, i) - d; |
|||
if (d.Real <= 0) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite); |
|||
} |
|||
|
|||
CholeskyFactor.At(i, i, d.SquareRoot()); |
|||
for (var k = i + 1; k < CholeskyFactor.RowCount; k++) |
|||
{ |
|||
CholeskyFactor.At(i, k, 0.0f); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>AX = B</b>, with A Cholesky factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side <see cref="Matrix{T}"/>, <b>B</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) |
|||
{ |
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Check for proper dimensions.
|
|||
if (result.RowCount != input.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); |
|||
} |
|||
|
|||
if (result.ColumnCount != input.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
if (input.RowCount != CholeskyFactor.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
input.CopyTo(result); |
|||
var order = CholeskyFactor.RowCount; |
|||
|
|||
for (var c = 0; c < result.ColumnCount; c++) |
|||
{ |
|||
// Solve L*Y = B;
|
|||
Complex32 sum; |
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
sum = result.At(i, c); |
|||
for (var k = i - 1; k >= 0; k--) |
|||
{ |
|||
sum -= CholeskyFactor.At(i, k) * result.At(k, c); |
|||
} |
|||
|
|||
result.At(i, c, sum / CholeskyFactor.At(i, i)); |
|||
} |
|||
|
|||
// Solve L'*X = Y;
|
|||
for (var i = order - 1; i >= 0; i--) |
|||
{ |
|||
sum = result.At(i, c); |
|||
for (var k = i + 1; k < order; k++) |
|||
{ |
|||
sum -= CholeskyFactor.At(k, i).Conjugate() * result.At(k, c); |
|||
} |
|||
|
|||
result.At(i, c, sum / CholeskyFactor.At(i, i)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>Ax = b</b>, with A Cholesky factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side vector, <b>b</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) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Check for proper dimensions.
|
|||
if (input.Count != result.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
if (input.Count != CholeskyFactor.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
input.CopyTo(result); |
|||
var order = CholeskyFactor.RowCount; |
|||
|
|||
// Solve L*Y = B;
|
|||
Complex32 sum; |
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
sum = result[i]; |
|||
for (var k = i - 1; k >= 0; k--) |
|||
{ |
|||
sum -= CholeskyFactor.At(i, k) * result[k]; |
|||
} |
|||
|
|||
result[i] = sum / CholeskyFactor.At(i, i); |
|||
} |
|||
|
|||
// Solve L'*X = Y;
|
|||
for (var i = order - 1; i >= 0; i--) |
|||
{ |
|||
sum = result[i]; |
|||
for (var k = i + 1; k < order; k++) |
|||
{ |
|||
sum -= CholeskyFactor.At(k, i).Conjugate() * result[k]; |
|||
} |
|||
|
|||
result[i] = sum / CholeskyFactor.At(i, i); |
|||
} |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
/// <summary>
|
|||
/// Add two values T+T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of addition</returns>
|
|||
protected sealed override Complex32 AddT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 + val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the natural (base e) logarithm of a specified number.
|
|||
/// </summary>
|
|||
/// <param name="val1"> A number whose logarithm is to be found</param>
|
|||
/// <returns>Natural (base e) logarithm </returns>
|
|||
protected sealed override Complex32 LogT(Complex32 val1) |
|||
{ |
|||
return val1.NaturalLogarithm(); |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,317 @@ |
|||
// <copyright file="UserLU.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Factorization; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// <para>A class which encapsulates the functionality of an LU factorization.</para>
|
|||
/// <para>For a matrix A, the LU factorization is a pair of lower triangular matrix L and
|
|||
/// upper triangular matrix U so that A = L*U.</para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The computation of the LU factorization is done at construction time.
|
|||
/// </remarks>
|
|||
public class UserLU : LU<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="UserLU"/> class. This object will compute the
|
|||
/// LU factorization when the constructor is called and cache it's factorization.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix to factor.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
|
|||
public UserLU(Matrix<Complex32> matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare); |
|||
} |
|||
|
|||
// Create an array for the pivot indices.
|
|||
var order = matrix.RowCount; |
|||
Factors = matrix.Clone(); |
|||
Pivots = new int[order]; |
|||
|
|||
// Initialize the pivot matrix to the identity permutation.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Pivots[i] = i; |
|||
} |
|||
|
|||
var vectorLUcolj = new Complex32[order]; |
|||
for (var j = 0; j < order; j++) |
|||
{ |
|||
// Make a copy of the j-th column to localize references.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
vectorLUcolj[i] = Factors.At(i, j); |
|||
} |
|||
|
|||
// Apply previous transformations.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
var kmax = Math.Min(i, j); |
|||
var s = Complex32.Zero; |
|||
for (var k = 0; k < kmax; k++) |
|||
{ |
|||
s += Factors.At(i, k) * vectorLUcolj[k]; |
|||
} |
|||
|
|||
vectorLUcolj[i] -= s; |
|||
Factors.At(i, j, vectorLUcolj[i]); |
|||
} |
|||
|
|||
// Find pivot and exchange if necessary.
|
|||
var p = j; |
|||
for (var i = j + 1; i < order; i++) |
|||
{ |
|||
if (vectorLUcolj[i].Magnitude > vectorLUcolj[p].Magnitude) |
|||
{ |
|||
p = i; |
|||
} |
|||
} |
|||
|
|||
if (p != j) |
|||
{ |
|||
for (var k = 0; k < order; k++) |
|||
{ |
|||
var temp = Factors.At(p, k); |
|||
Factors.At(p, k, Factors.At(j, k)); |
|||
Factors.At(j, k, temp); |
|||
} |
|||
|
|||
Pivots[j] = p; |
|||
} |
|||
|
|||
// Compute multipliers.
|
|||
if (j < order & Factors.At(j, j) != 0.0f) |
|||
{ |
|||
for (var i = j + 1; i < order; i++) |
|||
{ |
|||
Factors.At(i, j, (Factors.At(i, j) / Factors.At(j, j))); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <c>AX = B</c>, with A LU factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side <see cref="Matrix{T}"/>, <c>B</c>.</param>
|
|||
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <c>X</c>.</param>
|
|||
public override void Solve(Matrix<Complex32> input, Matrix<Complex32> result) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Check for proper dimensions.
|
|||
if (result.RowCount != input.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); |
|||
} |
|||
|
|||
if (result.ColumnCount != input.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
if (input.RowCount != Factors.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
// Copy the contents of input to result.
|
|||
input.CopyTo(result); |
|||
for (var i = 0; i < Pivots.Length; i++) |
|||
{ |
|||
if (Pivots[i] == i) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var p = Pivots[i]; |
|||
for (var j = 0; j < result.ColumnCount; j++) |
|||
{ |
|||
var temp = result.At(p, j); |
|||
result.At(p, j, result.At(i, j)); |
|||
result.At(i, j, temp); |
|||
} |
|||
} |
|||
|
|||
var order = Factors.RowCount; |
|||
|
|||
// Solve L*Y = P*B
|
|||
for (var k = 0; k < order; k++) |
|||
{ |
|||
for (var i = k + 1; i < order; i++) |
|||
{ |
|||
for (var j = 0; j < result.ColumnCount; j++) |
|||
{ |
|||
var temp = result.At(k, j) * Factors.At(i, k); |
|||
result.At(i, j, result.At(i, j) - temp); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Solve U*X = Y;
|
|||
for (var k = order - 1; k >= 0; k--) |
|||
{ |
|||
for (var j = 0; j < result.ColumnCount; j++) |
|||
{ |
|||
result.At(k, j, (result.At(k, j) / Factors.At(k, k))); |
|||
} |
|||
|
|||
for (var i = 0; i < k; i++) |
|||
{ |
|||
for (var j = 0; j < result.ColumnCount; j++) |
|||
{ |
|||
var temp = result.At(k, j) * Factors.At(i, k); |
|||
result.At(i, j, result.At(i, j) - temp); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <c>Ax = b</c>, with A LU factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side vector, <c>b</c>.</param>
|
|||
/// <param name="result">The left hand side <see cref="Matrix{T}"/>, <c>x</c>.</param>
|
|||
public override void Solve(Vector<Complex32> input, Vector<Complex32> result) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Check for proper dimensions.
|
|||
if (input.Count != result.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
if (input.Count != Factors.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
// Copy the contents of input to result.
|
|||
input.CopyTo(result); |
|||
for (var i = 0; i < Pivots.Length; i++) |
|||
{ |
|||
if (Pivots[i] == i) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var p = Pivots[i]; |
|||
var temp = result[p]; |
|||
result[p] = result[i]; |
|||
result[i] = temp; |
|||
} |
|||
|
|||
var order = Factors.RowCount; |
|||
|
|||
// Solve L*Y = P*B
|
|||
for (var k = 0; k < order; k++) |
|||
{ |
|||
for (var i = k + 1; i < order; i++) |
|||
{ |
|||
result[i] -= result[k] * Factors.At(i, k); |
|||
} |
|||
} |
|||
|
|||
// Solve U*X = Y;
|
|||
for (var k = order - 1; k >= 0; k--) |
|||
{ |
|||
result[k] /= Factors.At(k, k); |
|||
for (var i = 0; i < k; i++) |
|||
{ |
|||
result[i] -= result[k] * Factors.At(i, k); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the inverse of this matrix. The inverse is calculated using LU decomposition.
|
|||
/// </summary>
|
|||
/// <returns>The inverse of this matrix.</returns>
|
|||
public override Matrix<Complex32> Inverse() |
|||
{ |
|||
var order = Factors.RowCount; |
|||
var inverse = Factors.CreateMatrix(order, order); |
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
inverse.At(i, i, 1.0f); |
|||
} |
|||
|
|||
return Solve(inverse); |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,357 @@ |
|||
// <copyright file="UserQR.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using System.Linq; |
|||
using Generic; |
|||
using Generic.Factorization; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// <para>A class which encapsulates the functionality of the QR decomposition.</para>
|
|||
/// <para>Any real square matrix A may be decomposed as A = QR where Q is an orthogonal matrix
|
|||
/// (its columns are orthogonal unit vectors meaning QTQ = I) and R is an upper triangular matrix
|
|||
/// (also called right triangular matrix).</para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The computation of the QR decomposition is done at construction time by Householder transformation.
|
|||
/// </remarks>
|
|||
public class UserQR : QR<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="UserQR"/> class. This object will compute the
|
|||
/// QR factorization when the constructor is called and cache it's factorization.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix to factor.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
|
|||
public UserQR(Matrix<Complex32> matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount < matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
MatrixR = matrix.Clone(); |
|||
MatrixQ = matrix.CreateMatrix(matrix.RowCount, matrix.RowCount); |
|||
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
MatrixQ.At(i, i, 1.0f); |
|||
} |
|||
|
|||
var minmn = Math.Min(matrix.RowCount, matrix.ColumnCount); |
|||
var u = new Complex32[minmn][]; |
|||
for (var i = 0; i < minmn; i++) |
|||
{ |
|||
u[i] = GenerateColumn(MatrixR, i, matrix.RowCount - 1, i); |
|||
ComputeQR(u[i], MatrixR, i, matrix.RowCount - 1, i + 1, matrix.ColumnCount - 1); |
|||
} |
|||
|
|||
for (var i = minmn - 1; i >= 0; i--) |
|||
{ |
|||
ComputeQR(u[i], MatrixQ, i, matrix.RowCount - 1, i, matrix.RowCount - 1); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Generate column from initial matrix to work array
|
|||
/// </summary>
|
|||
/// <param name="a">Initial matrix</param>
|
|||
/// <param name="rowStart">The firts row</param>
|
|||
/// <param name="rowEnd">The last row</param>
|
|||
/// <param name="column">Column index</param>
|
|||
/// <returns>Generated vector</returns>
|
|||
private static Complex32[] GenerateColumn(Matrix<Complex32> a, int rowStart, int rowEnd, int column) |
|||
{ |
|||
var ru = rowEnd - rowStart + 1; |
|||
var u = new Complex32[ru]; |
|||
|
|||
for (var i = rowStart; i <= rowEnd; i++) |
|||
{ |
|||
u[i - rowStart] = a.At(i, column); |
|||
a.At(i, column, 0.0f); |
|||
} |
|||
|
|||
var norm = u.Aggregate(Complex32.Zero, (current, t) => current + (t.Magnitude * t.Magnitude)); |
|||
norm = norm.SquareRoot(); |
|||
|
|||
if (rowStart == rowEnd || norm.Magnitude == 0) |
|||
{ |
|||
a.At(rowStart, column, -u[0]); |
|||
u[0] = (float)Math.Sqrt(2.0); |
|||
return u; |
|||
} |
|||
|
|||
if (u[0].Magnitude != 0.0f) |
|||
{ |
|||
norm = norm.Magnitude * (u[0] / u[0].Magnitude); |
|||
} |
|||
|
|||
a.At(rowStart, column, -norm); |
|||
|
|||
for (var i = 0; i < ru; i++) |
|||
{ |
|||
u[i] /= norm; |
|||
} |
|||
|
|||
u[0] += 1.0f; |
|||
|
|||
var s = (1.0f / u[0]).SquareRoot(); |
|||
for (var i = 0; i < ru; i++) |
|||
{ |
|||
u[i] = u[i].Conjugate() * s; |
|||
} |
|||
|
|||
return u; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compute matrix Q or R
|
|||
/// </summary>
|
|||
/// <param name="u">H vectors values</param>
|
|||
/// <param name="a">Matrix to calculate</param>
|
|||
/// <param name="rowStart">Starting row index</param>
|
|||
/// <param name="rowEnd">Ending row index</param>
|
|||
/// <param name="columnStart">Starting column index</param>
|
|||
/// <param name="columnEnd">Ending column index</param>
|
|||
private static void ComputeQR(Complex32[] u, Matrix<Complex32> a, int rowStart, int rowEnd, int columnStart, int columnEnd) |
|||
{ |
|||
if (rowEnd < rowStart || columnEnd < columnStart) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var v = new Complex32[columnEnd - columnStart + 1]; |
|||
for (var j = columnStart; j <= columnEnd; j++) |
|||
{ |
|||
v[j - columnStart] = 0.0f; |
|||
} |
|||
|
|||
for (var i = rowStart; i <= rowEnd; i++) |
|||
{ |
|||
for (var j = columnStart; j <= columnEnd; j++) |
|||
{ |
|||
v[j - columnStart] = v[j - columnStart] + (u[i - rowStart] * a.At(i, j)); |
|||
} |
|||
} |
|||
|
|||
for (var i = rowStart; i <= rowEnd; i++) |
|||
{ |
|||
for (var j = columnStart; j <= columnEnd; j++) |
|||
{ |
|||
a.At(i, j, a.At(i, j) - (u[i - rowStart].Conjugate() * v[j - columnStart])); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>AX = B</b>, with A QR factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side <see cref="Matrix{T}"/>, <b>B</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) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// The solution X should have the same number of columns as B
|
|||
if (input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
// The dimension compatibility conditions for X = A\B require the two matrices A and B to have the same number of rows
|
|||
if (MatrixR.RowCount != input.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); |
|||
} |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
if (MatrixR.ColumnCount != result.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
var inputCopy = input.Clone(); |
|||
|
|||
// Compute Y = transpose(Q)*B
|
|||
var column = new Complex32[MatrixR.RowCount]; |
|||
for (var j = 0; j < input.ColumnCount; j++) |
|||
{ |
|||
for (var k = 0; k < MatrixR.RowCount; k++) |
|||
{ |
|||
column[k] = inputCopy.At(k, j); |
|||
} |
|||
|
|||
for (var i = 0; i < MatrixR.RowCount; i++) |
|||
{ |
|||
var s = Complex32.Zero; |
|||
for (var k = 0; k < MatrixR.RowCount; k++) |
|||
{ |
|||
s += MatrixQ.At(k, i).Conjugate() * column[k]; |
|||
} |
|||
|
|||
inputCopy.At(i, j, s); |
|||
} |
|||
} |
|||
|
|||
// Solve R*X = Y;
|
|||
for (var k = MatrixR.ColumnCount - 1; k >= 0; k--) |
|||
{ |
|||
for (var j = 0; j < input.ColumnCount; j++) |
|||
{ |
|||
inputCopy.At(k, j, inputCopy.At(k, j) / MatrixR.At(k, k)); |
|||
} |
|||
|
|||
for (var i = 0; i < k; i++) |
|||
{ |
|||
for (var j = 0; j < input.ColumnCount; j++) |
|||
{ |
|||
inputCopy.At(i, j, inputCopy.At(i, j) - (inputCopy.At(k, j) * MatrixR.At(i, k))); |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (var i = 0; i < MatrixR.ColumnCount; i++) |
|||
{ |
|||
for (var j = 0; j < inputCopy.ColumnCount; j++) |
|||
{ |
|||
result.At(i, j, inputCopy.At(i, j)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>Ax = b</b>, with A QR factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side vector, <b>b</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) |
|||
{ |
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
// Ax=b where A is an m x n matrix
|
|||
// Check that b is a column vector with m entries
|
|||
if (MatrixR.RowCount != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Check that x is a column vector with n entries
|
|||
if (MatrixR.ColumnCount != result.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var inputCopy = input.Clone(); |
|||
|
|||
// Compute Y = transpose(Q)*B
|
|||
var column = new Complex32[MatrixR.RowCount]; |
|||
for (var k = 0; k < MatrixR.RowCount; k++) |
|||
{ |
|||
column[k] = inputCopy[k]; |
|||
} |
|||
|
|||
for (var i = 0; i < MatrixR.RowCount; i++) |
|||
{ |
|||
var s = Complex32.Zero; |
|||
for (var k = 0; k < MatrixR.RowCount; k++) |
|||
{ |
|||
s += MatrixQ.At(k, i).Conjugate() * column[k]; |
|||
} |
|||
|
|||
inputCopy[i] = s; |
|||
} |
|||
|
|||
// Solve R*X = Y;
|
|||
for (var k = MatrixR.ColumnCount - 1; k >= 0; k--) |
|||
{ |
|||
inputCopy[k] /= MatrixR.At(k, k); |
|||
for (var i = 0; i < k; i++) |
|||
{ |
|||
inputCopy[i] -= inputCopy[k] * MatrixR.At(i, k); |
|||
} |
|||
} |
|||
|
|||
for (var i = 0; i < MatrixR.ColumnCount; i++) |
|||
{ |
|||
result[i] = inputCopy[i]; |
|||
} |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the absolute value of a specified number.
|
|||
/// </summary>
|
|||
/// <param name="val1"> A number whose absolute is to be found</param>
|
|||
/// <returns>Absolute value </returns>
|
|||
protected sealed override double AbsoluteT(Complex32 val1) |
|||
{ |
|||
return val1.Magnitude; |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,965 @@ |
|||
// <copyright file="UserSvd.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Factorization; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// <para>A class which encapsulates the functionality of the singular value decomposition (SVD) for <see cref="Matrix{T}"/>.</para>
|
|||
/// <para>Suppose M is an m-by-n matrix whose entries are real numbers.
|
|||
/// Then there exists a factorization of the form M = UΣVT where:
|
|||
/// - U is an m-by-m unitary matrix;
|
|||
/// - Σ is m-by-n diagonal matrix with nonnegative real numbers on the diagonal;
|
|||
/// - VT denotes transpose of V, an n-by-n unitary matrix;
|
|||
/// Such a factorization is called a singular-value decomposition of M. A common convention is to order the diagonal
|
|||
/// entries Σ(i,i) in descending order. In this case, the diagonal matrix Σ is uniquely determined
|
|||
/// by M (though the matrices U and V are not). The diagonal entries of Σ are known as the singular values of M.</para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The computation of the singular value decomposition is done at construction time.
|
|||
/// </remarks>
|
|||
public class UserSvd : Svd<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the
|
|||
/// the singular value decomposition when the constructor is called and cache it's decomposition.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix to factor.</param>
|
|||
/// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <b>null</b>.</exception>
|
|||
/// <exception cref="ArgumentException">If SVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception>
|
|||
public UserSvd(Matrix<Complex32> matrix, bool computeVectors) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
ComputeVectors = computeVectors; |
|||
var nm = Math.Min(matrix.RowCount + 1, matrix.ColumnCount); |
|||
var matrixCopy = matrix.Clone(); |
|||
|
|||
VectorS = matrixCopy.CreateVector(nm); |
|||
MatrixU = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount); |
|||
MatrixVT = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount); |
|||
|
|||
const int Maxiter = 1000; |
|||
var e = new Complex32[matrixCopy.ColumnCount]; |
|||
var work = new Complex32[matrixCopy.RowCount]; |
|||
|
|||
int i, j; |
|||
int l, lp1; |
|||
var cs = 0.0f; |
|||
var sn = 0.0f; |
|||
Complex32 t; |
|||
|
|||
var ncu = matrixCopy.RowCount; |
|||
|
|||
// Reduce matrixCopy to bidiagonal form, storing the diagonal elements
|
|||
// In s and the super-diagonal elements in e.
|
|||
var nct = Math.Min(matrixCopy.RowCount - 1, matrixCopy.ColumnCount); |
|||
var nrt = Math.Max(0, Math.Min(matrixCopy.ColumnCount - 2, matrixCopy.RowCount)); |
|||
var lu = Math.Max(nct, nrt); |
|||
for (l = 0; l < lu; l++) |
|||
{ |
|||
lp1 = l + 1; |
|||
if (l < nct) |
|||
{ |
|||
// Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l].
|
|||
VectorS[l] = Cnrm2Column(matrixCopy, matrixCopy.RowCount, l, l); |
|||
if (VectorS[l].Magnitude != 0.0f) |
|||
{ |
|||
if (matrixCopy.At(l, l).Magnitude != 0.0f) |
|||
{ |
|||
VectorS[l] = Csign(VectorS[l], matrixCopy.At(l, l)); |
|||
} |
|||
|
|||
CscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0f / VectorS[l]); |
|||
matrixCopy.At(l, l, (Complex32.One + matrixCopy.At(l, l))); |
|||
} |
|||
|
|||
VectorS[l] = -VectorS[l]; |
|||
} |
|||
|
|||
for (j = lp1; j < matrixCopy.ColumnCount; j++) |
|||
{ |
|||
if (l < nct) |
|||
{ |
|||
if (VectorS[l].Magnitude != 0.0f) |
|||
{ |
|||
// Apply the transformation.
|
|||
t = -Cdotc(matrixCopy, matrixCopy.RowCount, l, j, l) / matrixCopy.At(l, l); |
|||
if (t != Complex32.Zero) |
|||
{ |
|||
for (var ii = l; ii < matrixCopy.RowCount; ii++) |
|||
{ |
|||
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t * matrixCopy.At(ii, l))); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Place the l-th row of matrixCopy into e for the
|
|||
// Subsequent calculation of the row transformation.
|
|||
e[j] = matrixCopy.At(l, j).Conjugate(); |
|||
} |
|||
|
|||
if (ComputeVectors && l < nct) |
|||
{ |
|||
// Place the transformation in u for subsequent back multiplication.
|
|||
for (i = l; i < matrixCopy.RowCount; i++) |
|||
{ |
|||
MatrixU.At(i, l, matrixCopy.At(i, l)); |
|||
} |
|||
} |
|||
|
|||
if (l >= nrt) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
// Compute the l-th row transformation and place the l-th super-diagonal in e(l).
|
|||
var enorm = Cnrm2Vector(e, lp1); |
|||
e[l] = enorm; |
|||
if (e[l].Magnitude != 0.0f) |
|||
{ |
|||
if (e[lp1].Magnitude != 0.0f) |
|||
{ |
|||
e[l] = Csign(e[l], e[lp1]); |
|||
} |
|||
|
|||
CscalVector(e, lp1, 1.0f / e[l]); |
|||
e[lp1] = Complex32.One + e[lp1]; |
|||
} |
|||
|
|||
e[l] = -e[l].Conjugate(); |
|||
if (lp1 < matrixCopy.RowCount && e[l].Magnitude != 0.0f) |
|||
{ |
|||
// Apply the transformation.
|
|||
for (i = lp1; i < matrixCopy.RowCount; i++) |
|||
{ |
|||
work[i] = Complex32.Zero; |
|||
} |
|||
|
|||
for (j = lp1; j < matrixCopy.ColumnCount; j++) |
|||
{ |
|||
if (e[j] != Complex32.Zero) |
|||
{ |
|||
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) |
|||
{ |
|||
work[ii] += e[j] * matrixCopy.At(ii, j); |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (j = lp1; j < matrixCopy.ColumnCount; j++) |
|||
{ |
|||
var ww = (-e[j] / e[lp1]).Conjugate(); |
|||
if (ww != Complex32.Zero) |
|||
{ |
|||
for (var ii = lp1; ii < matrixCopy.RowCount; ii++) |
|||
{ |
|||
matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww * work[ii])); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (ComputeVectors) |
|||
{ |
|||
// Place the transformation in v for subsequent back multiplication.
|
|||
for (i = lp1; i < matrixCopy.ColumnCount; i++) |
|||
{ |
|||
MatrixVT.At(i, l, e[i]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Set up the final bidiagonal matrixCopy or order m.
|
|||
var m = Math.Min(matrixCopy.ColumnCount, matrixCopy.RowCount + 1); |
|||
var nctp1 = nct + 1; |
|||
var nrtp1 = nrt + 1; |
|||
if (nct < matrixCopy.ColumnCount) |
|||
{ |
|||
VectorS[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1)); |
|||
} |
|||
|
|||
if (matrixCopy.RowCount < m) |
|||
{ |
|||
VectorS[m - 1] = Complex32.Zero; |
|||
} |
|||
|
|||
if (nrtp1 < m) |
|||
{ |
|||
e[nrtp1 - 1] = matrixCopy.At((nrtp1 - 1), (m - 1)); |
|||
} |
|||
|
|||
e[m - 1] = Complex32.Zero; |
|||
|
|||
// If required, generate u.
|
|||
if (ComputeVectors) |
|||
{ |
|||
for (j = nctp1 - 1; j < ncu; j++) |
|||
{ |
|||
for (i = 0; i < matrixCopy.RowCount; i++) |
|||
{ |
|||
MatrixU.At(i, j, Complex32.Zero); |
|||
} |
|||
|
|||
MatrixU.At(j, j, Complex32.One); |
|||
} |
|||
|
|||
for (l = nct - 1; l >= 0; l--) |
|||
{ |
|||
if (VectorS[l].Magnitude != 0.0f) |
|||
{ |
|||
for (j = l + 1; j < ncu; j++) |
|||
{ |
|||
t = -Cdotc(MatrixU, matrixCopy.RowCount, l, j, l) / MatrixU.At(l, l); |
|||
if (t != Complex32.Zero) |
|||
{ |
|||
for (var ii = l; ii < matrixCopy.RowCount; ii++) |
|||
{ |
|||
MatrixU.At(ii, j, MatrixU.At(ii, j) + (t * MatrixU.At(ii, l))); |
|||
} |
|||
} |
|||
} |
|||
|
|||
CscalColumn(MatrixU, matrixCopy.RowCount, l, l, -1.0f); |
|||
MatrixU.At(l, l, Complex32.One + MatrixU.At(l, l)); |
|||
for (i = 0; i < l; i++) |
|||
{ |
|||
MatrixU.At(i, l, Complex32.Zero); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
for (i = 0; i < matrixCopy.RowCount; i++) |
|||
{ |
|||
MatrixU.At(i, l, Complex32.Zero); |
|||
} |
|||
|
|||
MatrixU.At(l, l, Complex32.One); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// If it is required, generate v.
|
|||
if (ComputeVectors) |
|||
{ |
|||
for (l = matrixCopy.ColumnCount - 1; l >= 0; l--) |
|||
{ |
|||
lp1 = l + 1; |
|||
if (l < nrt) |
|||
{ |
|||
if (e[l].Magnitude != 0.0f) |
|||
{ |
|||
for (j = lp1; j < matrixCopy.ColumnCount; j++) |
|||
{ |
|||
t = -Cdotc(MatrixVT, matrixCopy.ColumnCount, l, j, lp1) / MatrixVT.At(lp1, l); |
|||
if (t != Complex32.Zero) |
|||
{ |
|||
for (var ii = l; ii < matrixCopy.ColumnCount; ii++) |
|||
{ |
|||
MatrixVT.At(ii, j, MatrixVT.At(ii, j) + (t * MatrixVT.At(ii, l))); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (i = 0; i < matrixCopy.ColumnCount; i++) |
|||
{ |
|||
MatrixVT.At(i, l, Complex32.Zero); |
|||
} |
|||
|
|||
MatrixVT.At(l, l, Complex32.One); |
|||
} |
|||
} |
|||
|
|||
// Transform s and e so that they are real .
|
|||
for (i = 0; i < m; i++) |
|||
{ |
|||
Complex32 r; |
|||
if (VectorS[i].Magnitude != 0.0f) |
|||
{ |
|||
t = VectorS[i].Magnitude; |
|||
r = VectorS[i] / t; |
|||
VectorS[i] = t; |
|||
if (i < m - 1) |
|||
{ |
|||
e[i] = e[i] / r; |
|||
} |
|||
|
|||
if (ComputeVectors) |
|||
{ |
|||
CscalColumn(MatrixU, matrixCopy.RowCount, i, 0, r); |
|||
} |
|||
} |
|||
|
|||
// Exit
|
|||
if (i == m - 1) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
if (e[i].Magnitude != 0.0f) |
|||
{ |
|||
t = e[i].Magnitude; |
|||
r = t / e[i]; |
|||
e[i] = t; |
|||
VectorS[i + 1] = VectorS[i + 1] * r; |
|||
if (ComputeVectors) |
|||
{ |
|||
CscalColumn(MatrixVT, matrixCopy.ColumnCount, i + 1, 0, r); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Main iteration loop for the singular values.
|
|||
var mn = m; |
|||
var iter = 0; |
|||
|
|||
while (m > 0) |
|||
{ |
|||
// Quit if all the singular values have been found. If too many iterations have been performed,
|
|||
// throw exception that Convergence Failed
|
|||
if (iter >= Maxiter) |
|||
{ |
|||
throw new ArgumentException(Resources.ConvergenceFailed); |
|||
} |
|||
|
|||
// This section of the program inspects for negligible elements in the s and e arrays. On
|
|||
// completion the variables kase and l are set as follows.
|
|||
// Kase = 1 if VectorS[m] and e[l-1] are negligible and l < m
|
|||
// Kase = 2 if VectorS[l] is negligible and l < m
|
|||
// Kase = 3 if e[l-1] is negligible, l < m, and VectorS[l, ..., VectorS[m] are not negligible (qr step).
|
|||
// Лase = 4 if e[m-1] is negligible (convergence).
|
|||
float ztest; |
|||
float test; |
|||
for (l = m - 2; l >= 0; l--) |
|||
{ |
|||
test = VectorS[l].Magnitude + VectorS[l + 1].Magnitude; |
|||
ztest = test + e[l].Magnitude; |
|||
if (ztest.AlmostEqualInDecimalPlaces(test, 7)) |
|||
{ |
|||
e[l] = Complex32.Zero; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
int kase; |
|||
if (l == m - 2) |
|||
{ |
|||
kase = 4; |
|||
} |
|||
else |
|||
{ |
|||
int ls; |
|||
for (ls = m - 1; ls > l; ls--) |
|||
{ |
|||
test = 0.0f; |
|||
if (ls != m - 1) |
|||
{ |
|||
test = test + e[ls].Magnitude; |
|||
} |
|||
|
|||
if (ls != l + 1) |
|||
{ |
|||
test = test + e[ls - 1].Magnitude; |
|||
} |
|||
|
|||
ztest = test + VectorS[ls].Magnitude; |
|||
if (ztest.AlmostEqualInDecimalPlaces(test, 7)) |
|||
{ |
|||
VectorS[ls] = Complex32.Zero; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (ls == l) |
|||
{ |
|||
kase = 3; |
|||
} |
|||
else if (ls == m - 1) |
|||
{ |
|||
kase = 1; |
|||
} |
|||
else |
|||
{ |
|||
kase = 2; |
|||
l = ls; |
|||
} |
|||
} |
|||
|
|||
l = l + 1; |
|||
|
|||
// Perform the task indicated by kase.
|
|||
int k; |
|||
float f; |
|||
switch (kase) |
|||
{ |
|||
// Deflate negligible VectorS[m].
|
|||
case 1: |
|||
f = e[m - 2].Real; |
|||
e[m - 2] = Complex32.Zero; |
|||
float t1; |
|||
for (var kk = l; kk < m - 1; kk++) |
|||
{ |
|||
k = m - 2 - kk + l; |
|||
t1 = VectorS[k].Real; |
|||
Srotg(ref t1, ref f, ref cs, ref sn); |
|||
VectorS[k] = t1; |
|||
if (k != l) |
|||
{ |
|||
f = -sn * e[k - 1].Real; |
|||
e[k - 1] = cs * e[k - 1]; |
|||
} |
|||
|
|||
if (ComputeVectors) |
|||
{ |
|||
Csrot(MatrixVT, matrixCopy.ColumnCount, k, m - 1, cs, sn); |
|||
} |
|||
} |
|||
|
|||
break; |
|||
|
|||
// Split at negligible VectorS[l].
|
|||
case 2: |
|||
f = e[l - 1].Real; |
|||
e[l - 1] = Complex32.Zero; |
|||
for (k = l; k < m; k++) |
|||
{ |
|||
t1 = VectorS[k].Real; |
|||
Srotg(ref t1, ref f, ref cs, ref sn); |
|||
VectorS[k] = t1; |
|||
f = -sn * e[k].Real; |
|||
e[k] = cs * e[k]; |
|||
if (ComputeVectors) |
|||
{ |
|||
Csrot(MatrixU, matrixCopy.RowCount, k, l - 1, cs, sn); |
|||
} |
|||
} |
|||
|
|||
break; |
|||
|
|||
// Perform one qr step.
|
|||
case 3: |
|||
// Calculate the shift.
|
|||
var scale = 0.0f; |
|||
scale = Math.Max(scale, VectorS[m - 1].Magnitude); |
|||
scale = Math.Max(scale, VectorS[m - 2].Magnitude); |
|||
scale = Math.Max(scale, e[m - 2].Magnitude); |
|||
scale = Math.Max(scale, VectorS[l].Magnitude); |
|||
scale = Math.Max(scale, e[l].Magnitude); |
|||
var sm = VectorS[m - 1].Real / scale; |
|||
var smm1 = VectorS[m - 2].Real / scale; |
|||
var emm1 = e[m - 2].Real / scale; |
|||
var sl = VectorS[l].Real / scale; |
|||
var el = e[l].Real / scale; |
|||
var b = (((smm1 + sm) * (smm1 - sm)) + (emm1 * emm1)) / 2.0f; |
|||
var c = (sm * emm1) * (sm * emm1); |
|||
var shift = 0.0f; |
|||
|
|||
if (b != 0.0f || c != 0.0f) |
|||
{ |
|||
shift = (float)Math.Sqrt((b * b) + c); |
|||
if (b < 0.0f) |
|||
{ |
|||
shift = -shift; |
|||
} |
|||
|
|||
shift = c / (b + shift); |
|||
} |
|||
|
|||
f = ((sl + sm) * (sl - sm)) + shift; |
|||
var g = sl * el; |
|||
|
|||
// Chase zeros.
|
|||
for (k = l; k < m - 1; k++) |
|||
{ |
|||
Srotg(ref f, ref g, ref cs, ref sn); |
|||
if (k != l) |
|||
{ |
|||
e[k - 1] = f; |
|||
} |
|||
|
|||
f = (cs * VectorS[k].Real) + (sn * e[k].Real); |
|||
e[k] = (cs * e[k]) - (sn * VectorS[k]); |
|||
g = sn * VectorS[k + 1].Real; |
|||
VectorS[k + 1] = cs * VectorS[k + 1]; |
|||
if (ComputeVectors) |
|||
{ |
|||
Csrot(MatrixVT, matrixCopy.ColumnCount, k, k + 1, cs, sn); |
|||
} |
|||
|
|||
Srotg(ref f, ref g, ref cs, ref sn); |
|||
VectorS[k] = f; |
|||
f = (cs * e[k].Real) + (sn * VectorS[k + 1].Real); |
|||
VectorS[k + 1] = (-sn * e[k]) + (cs * VectorS[k + 1]); |
|||
g = sn * e[k + 1].Real; |
|||
e[k + 1] = cs * e[k + 1]; |
|||
if (ComputeVectors && k < matrixCopy.RowCount) |
|||
{ |
|||
Csrot(MatrixU, matrixCopy.RowCount, k, k + 1, cs, sn); |
|||
} |
|||
} |
|||
|
|||
e[m - 2] = f; |
|||
iter = iter + 1; |
|||
break; |
|||
|
|||
// Convergence.
|
|||
case 4: |
|||
// Make the singular value positive
|
|||
if (VectorS[l].Real < 0.0f) |
|||
{ |
|||
VectorS[l] = -VectorS[l]; |
|||
if (ComputeVectors) |
|||
{ |
|||
CscalColumn(MatrixVT, matrixCopy.ColumnCount, l, 0, -1.0f); |
|||
} |
|||
} |
|||
|
|||
// Order the singular value.
|
|||
while (l != mn - 1) |
|||
{ |
|||
if (VectorS[l].Real >= VectorS[l + 1].Real) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
t = VectorS[l]; |
|||
VectorS[l] = VectorS[l + 1]; |
|||
VectorS[l + 1] = t; |
|||
if (ComputeVectors && l < matrixCopy.ColumnCount) |
|||
{ |
|||
Swap(MatrixVT, matrixCopy.ColumnCount, l, l + 1); |
|||
} |
|||
|
|||
if (ComputeVectors && l < matrixCopy.RowCount) |
|||
{ |
|||
Swap(MatrixU, matrixCopy.RowCount, l, l + 1); |
|||
} |
|||
|
|||
l = l + 1; |
|||
} |
|||
|
|||
iter = 0; |
|||
m = m - 1; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (ComputeVectors) |
|||
{ |
|||
MatrixVT = MatrixVT.ConjugateTranspose(); |
|||
} |
|||
|
|||
// Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses
|
|||
// a singular vector of length mRows+1 when mRows < mColumns. The last element is not used and needs to be removed.
|
|||
// we should port lapack's svd routine to remove this problem.
|
|||
if (matrixCopy.RowCount < matrixCopy.ColumnCount) |
|||
{ |
|||
nm--; |
|||
var tmp = matrixCopy.CreateVector(nm); |
|||
for (i = 0; i < nm; i++) |
|||
{ |
|||
tmp[i] = VectorS[i]; |
|||
} |
|||
|
|||
VectorS = tmp; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates absolute value of <paramref name="z1"/> multiplied on signum function of <paramref name="z2"/>
|
|||
/// </summary>
|
|||
/// <param name="z1">Complex32 value z1</param>
|
|||
/// <param name="z2">Complex32 value z2</param>
|
|||
/// <returns>Result multiplication of signum function and absolute value</returns>
|
|||
private static Complex32 Csign(Complex32 z1, Complex32 z2) |
|||
{ |
|||
return z1.Magnitude * (z2 / z2.Magnitude); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Interchanges two vectors <paramref name="columnA"/> and <paramref name="columnB"/>
|
|||
/// </summary>
|
|||
/// <param name="a">Source matrix</param>
|
|||
/// <param name="rowCount">The number of rows in <paramref name="a"/></param>
|
|||
/// <param name="columnA">Column A 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) |
|||
{ |
|||
for (var i = 0; i < rowCount; i++) |
|||
{ |
|||
var z = a.At(i, columnA); |
|||
a.At(i, columnA, a.At(i, columnB)); |
|||
a.At(i, columnB, z); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Scale column <paramref name="column"/> by <paramref name="z"/> starting from row <paramref name="rowStart"/>
|
|||
/// </summary>
|
|||
/// <param name="a">Source matrix</param>
|
|||
/// <param name="rowCount">The number of rows in <paramref name="a"/> </param>
|
|||
/// <param name="column">Column to scale</param>
|
|||
/// <param name="rowStart">Row to scale from</param>
|
|||
/// <param name="z">Scale value</param>
|
|||
private static void CscalColumn(Matrix<Complex32> a, int rowCount, int column, int rowStart, Complex32 z) |
|||
{ |
|||
for (var i = rowStart; i < rowCount; i++) |
|||
{ |
|||
a.At(i, column, a.At(i, column) * z); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Scale vector <paramref name="a"/> by <paramref name="z"/> starting from index <paramref name="start"/>
|
|||
/// </summary>
|
|||
/// <param name="a">Source vector</param>
|
|||
/// <param name="start">Row to scale from</param>
|
|||
/// <param name="z">Scale value</param>
|
|||
private static void CscalVector(Complex32[] a, int start, Complex32 z) |
|||
{ |
|||
for (var i = start; i < a.Length; i++) |
|||
{ |
|||
a[i] = a[i] * z; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Given the Cartesian coordinates (da, db) of a point p, these fucntion return the parameters da, db, c, and s
|
|||
/// associated with the Givens rotation that zeros the y-coordinate of the point.
|
|||
/// </summary>
|
|||
/// <param name="da">Provides the x-coordinate of the point p. On exit contains the parameter r associated with the Givens rotation</param>
|
|||
/// <param name="db">Provides the y-coordinate of the point p. On exit contains the parameter z 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>
|
|||
/// <remarks>This is equivalent to the DROTG LAPACK routine.</remarks>
|
|||
private static void Srotg(ref float da, ref float db, ref float c, ref float s) |
|||
{ |
|||
float r, z; |
|||
|
|||
var roe = db; |
|||
var absda = Math.Abs(da); |
|||
var absdb = Math.Abs(db); |
|||
if (absda > absdb) |
|||
{ |
|||
roe = da; |
|||
} |
|||
|
|||
var scale = absda + absdb; |
|||
if (scale == 0.0f) |
|||
{ |
|||
c = 1.0f; |
|||
s = 0.0f; |
|||
r = 0.0f; |
|||
z = 0.0f; |
|||
} |
|||
else |
|||
{ |
|||
var sda = da / scale; |
|||
var sdb = db / scale; |
|||
r = scale * (float)Math.Sqrt((sda * sda) + (sdb * sdb)); |
|||
if (roe < 0.0f) |
|||
{ |
|||
r = -r; |
|||
} |
|||
|
|||
c = da / r; |
|||
s = db / r; |
|||
z = 1.0f; |
|||
if (absda > absdb) |
|||
{ |
|||
z = s; |
|||
} |
|||
|
|||
if (absdb >= absda && c != 0.0f) |
|||
{ |
|||
z = 1.0f / c; |
|||
} |
|||
} |
|||
|
|||
da = r; |
|||
db = z; |
|||
} |
|||
|
|||
/// <summary>dded
|
|||
/// Calculate Norm 2 of the column <paramref name="column"/> in matrix <paramref name="a"/> starting from row <paramref name="rowStart"/>
|
|||
/// </summary>
|
|||
/// <param name="a">Source matrix</param>
|
|||
/// <param name="rowCount">The number of rows in <paramref name="a"/></param>
|
|||
/// <param name="column">Column index</param>
|
|||
/// <param name="rowStart">Start row index</param>
|
|||
/// <returns>Norm2 (Euclidean norm) of trhe column</returns>
|
|||
private static float Cnrm2Column(Matrix<Complex32> a, int rowCount, int column, int rowStart) |
|||
{ |
|||
var s = 0.0f; |
|||
for (var i = rowStart; i < rowCount; i++) |
|||
{ |
|||
s += a.At(i, column).Magnitude * a.At(i, column).Magnitude; |
|||
} |
|||
|
|||
return (float)Math.Sqrt(s); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculate Norm 2 of the vector <paramref name="a"/> starting from index <paramref name="rowStart"/>
|
|||
/// </summary>
|
|||
/// <param name="a">Source vector</param>
|
|||
/// <param name="rowStart">Start index</param>
|
|||
/// <returns>Norm2 (Euclidean norm) of the vector</returns>
|
|||
private static float Cnrm2Vector(Complex32[] a, int rowStart) |
|||
{ |
|||
var s = 0.0f; |
|||
for (var i = rowStart; i < a.Length; i++) |
|||
{ |
|||
s += a[i].Magnitude * a[i].Magnitude; |
|||
} |
|||
|
|||
return (float)Math.Sqrt(s); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculate dot product of <paramref name="columnA"/> and <paramref name="columnB"/> conjugating the first vector.
|
|||
/// </summary>
|
|||
/// <param name="a">Source matrix</param>
|
|||
/// <param name="rowCount">The number of rows in <paramref name="a"/></param>
|
|||
/// <param name="columnA">Index of column A</param>
|
|||
/// <param name="columnB">Index of column B</param>
|
|||
/// <param name="rowStart">Starting row index</param>
|
|||
/// <returns>Dot product value</returns>
|
|||
private static Complex32 Cdotc(Matrix<Complex32> a, int rowCount, int columnA, int columnB, int rowStart) |
|||
{ |
|||
var z = Complex32.Zero; |
|||
for (var i = rowStart; i < rowCount; i++) |
|||
{ |
|||
z += a.At(i, columnA).Conjugate() * a.At(i, columnB); |
|||
} |
|||
|
|||
return z; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Performs rotation of points in the plane. Given two vectors x <paramref name="columnA"/> and y <paramref name="columnB"/>,
|
|||
/// each vector element of these vectors is replaced as follows: x(i) = c*x(i) + s*y(i); y(i) = c*y(i) - s*x(i)
|
|||
/// </summary>
|
|||
/// <param name="a">Source matrix</param>
|
|||
/// <param name="rowCount">The number of rows in <paramref name="a"/></param>
|
|||
/// <param name="columnA">Index of column A</param>
|
|||
/// <param name="columnB">Index of column B</param>
|
|||
/// <param name="c">scalar cos 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) |
|||
{ |
|||
for (var i = 0; i < rowCount; i++) |
|||
{ |
|||
var z = (c * a.At(i, columnA)) + (s * a.At(i, columnB)); |
|||
var tmp = (c * a.At(i, columnB)) - (s * a.At(i, columnA)); |
|||
a.At(i, columnB, tmp); |
|||
a.At(i, columnA, z); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side <see cref="Matrix{T}"/>, <b>B</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) |
|||
{ |
|||
// Check for proper arguments.
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (!ComputeVectors) |
|||
{ |
|||
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); |
|||
} |
|||
|
|||
// The solution X should have the same number of columns as B
|
|||
if (input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
// The dimension compatibility conditions for X = A\B require the two matrices A and B to have the same number of rows
|
|||
if (MatrixU.RowCount != input.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); |
|||
} |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
if (MatrixVT.ColumnCount != result.RowCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); |
|||
} |
|||
|
|||
var mn = Math.Min(MatrixU.RowCount, MatrixVT.ColumnCount); |
|||
var bn = input.ColumnCount; |
|||
|
|||
var tmp = new Complex32[MatrixVT.ColumnCount]; |
|||
|
|||
for (var k = 0; k < bn; k++) |
|||
{ |
|||
for (var j = 0; j < MatrixVT.ColumnCount; j++) |
|||
{ |
|||
var value = Complex32.Zero; |
|||
if (j < mn) |
|||
{ |
|||
for (var i = 0; i < MatrixU.RowCount; i++) |
|||
{ |
|||
value += MatrixU.At(i, j).Conjugate() * input.At(i, k); |
|||
} |
|||
|
|||
value /= VectorS[j]; |
|||
} |
|||
|
|||
tmp[j] = value; |
|||
} |
|||
|
|||
for (var j = 0; j < MatrixVT.ColumnCount; j++) |
|||
{ |
|||
var value = Complex32.Zero; |
|||
for (var i = 0; i < MatrixVT.ColumnCount; i++) |
|||
{ |
|||
value += MatrixVT.At(i, j).Conjugate() * tmp[i]; |
|||
} |
|||
|
|||
result[j, k] = value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves a system of linear equations, <b>Ax = b</b>, with A SVD factorized.
|
|||
/// </summary>
|
|||
/// <param name="input">The right hand side vector, <b>b</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) |
|||
{ |
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (!ComputeVectors) |
|||
{ |
|||
throw new InvalidOperationException(Resources.SingularVectorsNotComputed); |
|||
} |
|||
|
|||
// Ax=b where A is an m x n matrix
|
|||
// Check that b is a column vector with m entries
|
|||
if (MatrixU.RowCount != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Check that x is a column vector with n entries
|
|||
if (MatrixVT.ColumnCount != result.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
var mn = Math.Min(MatrixU.RowCount, MatrixVT.ColumnCount); |
|||
var tmp = new Complex32[MatrixVT.ColumnCount]; |
|||
for (var j = 0; j < MatrixVT.ColumnCount; j++) |
|||
{ |
|||
var value = Complex32.Zero; |
|||
if (j < mn) |
|||
{ |
|||
for (var i = 0; i < MatrixU.RowCount; i++) |
|||
{ |
|||
value += MatrixU.At(i, j).Conjugate() * input[i]; |
|||
} |
|||
|
|||
value /= VectorS[j]; |
|||
} |
|||
|
|||
tmp[j] = value; |
|||
} |
|||
|
|||
for (var j = 0; j < MatrixVT.ColumnCount; j++) |
|||
{ |
|||
var value = Complex32.Zero; |
|||
for (var i = 0; i < MatrixVT.ColumnCount; i++) |
|||
{ |
|||
value += MatrixVT.At(i, j).Conjugate() * tmp[i]; |
|||
} |
|||
|
|||
result[j] = value; |
|||
} |
|||
} |
|||
|
|||
#region Simple arithmetic of type T
|
|||
|
|||
/// <summary>
|
|||
/// Multiply two values T*T
|
|||
/// </summary>
|
|||
/// <param name="val1">Left operand value</param>
|
|||
/// <param name="val2">Right operand value</param>
|
|||
/// <returns>Result of multiplication</returns>
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the absolute value of a specified number.
|
|||
/// </summary>
|
|||
/// <param name="val1"> A number whose absolute is to be found</param>
|
|||
/// <returns>Absolute value </returns>
|
|||
protected sealed override double AbsoluteT(Complex32 val1) |
|||
{ |
|||
return val1.Magnitude; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,521 @@ |
|||
// <copyright file="BiCgStab.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Iterative |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Solvers; |
|||
using Generic.Solvers.Preconditioners; |
|||
using Generic.Solvers.Status; |
|||
using Numerics; |
|||
using Preconditioners; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// A Bi-Conjugate Gradient stabilized iterative matrix solver.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The Bi-Conjugate Gradient Stabilized (BiCGStab) solver is an 'improvement'
|
|||
/// of the standard Conjugate Gradient (CG) solver. Unlike the CG solver the
|
|||
/// BiCGStab can be used on non-symmetric matrices. <br/>
|
|||
/// Note that much of the success of the solver depends on the selection of the
|
|||
/// proper preconditioner.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The Bi-CGSTAB algorithm was taken from: <br/>
|
|||
/// Templates for the solution of linear systems: Building blocks
|
|||
/// for iterative methods
|
|||
/// <br/>
|
|||
/// Richard Barrett, Michael Berry, Tony F. Chan, James Demmel,
|
|||
/// June M. Donato, Jack Dongarra, Victor Eijkhout, Roldan Pozo,
|
|||
/// Charles Romine and Henk van der Vorst
|
|||
/// <br/>
|
|||
/// Url: <a href="http://www.netlib.org/templates/Templates.html">http://www.netlib.org/templates/Templates.html</a>
|
|||
/// <br/>
|
|||
/// Algorithm is described in Chapter 2, section 2.3.8, page 27
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The example code below provides an indication of the possible use of the
|
|||
/// solver.
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
public sealed class BiCgStab : IIterativeSolver<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The status used if there is no status, i.e. the solver hasn't run yet and there is no
|
|||
/// iterator.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus DefaultStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// The preconditioner that will be used. Can be set to <see langword="null" />, in which case the default
|
|||
/// pre-conditioner will be used.
|
|||
/// </summary>
|
|||
private IPreConditioner<Complex32> _preconditioner; |
|||
|
|||
/// <summary>
|
|||
/// The iterative process controller.
|
|||
/// </summary>
|
|||
private IIterator<Complex32> _iterator; |
|||
|
|||
/// <summary>
|
|||
/// Indicates if the user has stopped the solver.
|
|||
/// </summary>
|
|||
private bool _hasBeenStopped; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BiCgStab"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// When using this constructor the solver will use the <see cref="IIterator{T}"/> with
|
|||
/// the standard settings and a default preconditioner.
|
|||
/// </remarks>
|
|||
public BiCgStab() : this(null, null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BiCgStab"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// When using this constructor the solver will use a default preconditioner.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The main advantages of using a user defined <see cref="IIterator{T}"/> are:
|
|||
/// <list type="number">
|
|||
/// <item>It is possible to set the desired convergence limits.</item>
|
|||
/// <item>
|
|||
/// It is possible to check the reason for which the solver finished
|
|||
/// the iterative procedure by calling the <see cref="IIterator{T}.Status"/> property.
|
|||
/// </item>
|
|||
/// </list>
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <param name="iterator">The <see cref="IIterator{T}"/> that will be used to monitor the iterative process. </param>
|
|||
public BiCgStab(IIterator<Complex32> iterator) : this(null, iterator) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BiCgStab"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// When using this constructor the solver will use the <see cref="IIterator{T}"/> with
|
|||
/// the standard settings.
|
|||
/// </remarks>
|
|||
/// <param name="preconditioner">The <see cref="IPreConditioner{T}"/> that will be used to precondition the matrix equation.</param>
|
|||
public BiCgStab(IPreConditioner<Complex32> preconditioner) : this(preconditioner, null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BiCgStab"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The main advantages of using a user defined <see cref="IIterator{T}"/> are:
|
|||
/// <list type="number">
|
|||
/// <item>It is possible to set the desired convergence limits.</item>
|
|||
/// <item>
|
|||
/// It is possible to check the reason for which the solver finished
|
|||
/// the iterative procedure by calling the <see cref="IIterator{T}.Status"/> property.
|
|||
/// </item>
|
|||
/// </list>
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <param name="preconditioner">The <see cref="IPreConditioner{T}"/> that will be used to precondition the matrix equation. </param>
|
|||
/// <param name="iterator">The <see cref="IIterator{T}"/> that will be used to monitor the iterative process. </param>
|
|||
public BiCgStab(IPreConditioner<Complex32> preconditioner, IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
_preconditioner = preconditioner; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the <see cref="IPreConditioner{T}"/> that will be used to precondition the iterative process.
|
|||
/// </summary>
|
|||
/// <param name="preconditioner">The preconditioner.</param>
|
|||
public void SetPreconditioner(IPreConditioner<Complex32> preconditioner) |
|||
{ |
|||
_preconditioner = preconditioner; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the <see cref="IIterator{T}"/> that will be used to track the iterative process.
|
|||
/// </summary>
|
|||
/// <param name="iterator">The iterator.</param>
|
|||
public void SetIterator(IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the status of the iteration once the calculation is finished.
|
|||
/// </summary>
|
|||
public ICalculationStatus IterationResult |
|||
{ |
|||
get |
|||
{ |
|||
return (_iterator != null) ? _iterator.Status : DefaultStatus; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Stops the solve process.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
|
|||
/// </remarks>
|
|||
public void StopSolve() |
|||
{ |
|||
_hasBeenStopped = true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient <see cref="Matrix{T}"/>, <c>A</c>.</param>
|
|||
/// <param name="vector">The solution <see cref="Vector{T}"/>, <c>b</c>.</param>
|
|||
/// <returns>The result <see cref="Vector{T}"/>, <c>x</c>.</returns>
|
|||
public Vector<Complex32> Solve(Matrix<Complex32> matrix, Vector<Complex32> vector) |
|||
{ |
|||
if (vector == null) |
|||
{ |
|||
throw new ArgumentNullException(); |
|||
} |
|||
|
|||
Vector<Complex32> result = new DenseVector(matrix.RowCount); |
|||
Solve(matrix, vector, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient <see cref="Matrix{T}"/>, <c>A</c>.</param>
|
|||
/// <param name="input">The solution <see cref="Vector{T}"/>, <c>b</c>.</param>
|
|||
/// <param name="result">The result <see cref="Vector{T}"/>, <c>x</c>.</param>
|
|||
public void Solve(Matrix<Complex32> matrix, Vector<Complex32> input, Vector<Complex32> result) |
|||
{ |
|||
// If we were stopped before, we are no longer
|
|||
// We're doing this at the start of the method to ensure
|
|||
// that we can use these fields immediately.
|
|||
_hasBeenStopped = false; |
|||
|
|||
// Parameters checks
|
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (result.Count != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Initialize the solver fields
|
|||
// Set the convergence monitor
|
|||
if (_iterator == null) |
|||
{ |
|||
_iterator = Iterator.CreateDefault(); |
|||
} |
|||
|
|||
if (_preconditioner == null) |
|||
{ |
|||
_preconditioner = new UnitPreconditioner(); |
|||
} |
|||
|
|||
_preconditioner.Initialize(matrix); |
|||
|
|||
// Compute r_0 = b - Ax_0 for some initial guess x_0
|
|||
// In this case we take x_0 = vector
|
|||
// This is basically a SAXPY so it could be made a lot faster
|
|||
Vector<Complex32> residuals = new DenseVector(matrix.RowCount); |
|||
CalculateTrueResidual(matrix, residuals, result, input); |
|||
|
|||
// Choose r~ (for example, r~ = r_0)
|
|||
var tempResiduals = residuals.Clone(); |
|||
var temp = result.Clone(); |
|||
|
|||
// create five temporary vectors needed to hold temporary
|
|||
// coefficients. All vectors are mangled in each iteration.
|
|||
// These are defined here to prevent stressing the garbage collector
|
|||
Vector<Complex32> vecP = new DenseVector(residuals.Count); |
|||
Vector<Complex32> vecPdash = new DenseVector(residuals.Count); |
|||
Vector<Complex32> nu = new DenseVector(residuals.Count); |
|||
Vector<Complex32> vecS = new DenseVector(residuals.Count); |
|||
Vector<Complex32> vecSdash = new DenseVector(residuals.Count); |
|||
Vector<Complex32> t = new DenseVector(residuals.Count); |
|||
|
|||
// create some temporary float variables that are needed
|
|||
// to hold values in between iterations
|
|||
Complex32 currentRho = 0; |
|||
Complex32 alpha = 0; |
|||
Complex32 omega = 0; |
|||
|
|||
var iterationNumber = 0; |
|||
while (ShouldContinue(iterationNumber, result, input, residuals)) |
|||
{ |
|||
// rho_(i-1) = r~^T r_(i-1) // dotproduct r~ and r_(i-1)
|
|||
var oldRho = currentRho; |
|||
currentRho = tempResiduals.DotProduct(residuals); |
|||
|
|||
// if (rho_(i-1) == 0) // METHOD FAILS
|
|||
// If rho is only 1 ULP from zero then we fail.
|
|||
if (currentRho.Real.AlmostEqual(0, 1) && currentRho.Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
// Rho-type breakdown
|
|||
throw new Exception("Iterative solver experience a numerical break down"); |
|||
} |
|||
|
|||
if (iterationNumber != 0) |
|||
{ |
|||
// beta_(i-1) = (rho_(i-1)/rho_(i-2))(alpha_(i-1)/omega(i-1))
|
|||
var beta = (currentRho / oldRho) * (alpha / omega); |
|||
|
|||
// p_i = r_(i-1) + beta_(i-1)(p_(i-1) - omega_(i-1) * nu_(i-1))
|
|||
vecP.Add(nu.Multiply(-omega), vecP); |
|||
|
|||
vecP.Multiply(beta, vecP); |
|||
vecP.Add(residuals, vecP); |
|||
} |
|||
else |
|||
{ |
|||
// p_i = r_(i-1)
|
|||
residuals.CopyTo(vecP); |
|||
} |
|||
|
|||
// SOLVE Mp~ = p_i // M = preconditioner
|
|||
_preconditioner.Approximate(vecP, vecPdash); |
|||
|
|||
// nu_i = Ap~
|
|||
matrix.Multiply(vecPdash, nu); |
|||
|
|||
// alpha_i = rho_(i-1)/ (r~^T nu_i) = rho / dotproduct(r~ and nu_i)
|
|||
alpha = currentRho * 1 / tempResiduals.DotProduct(nu); |
|||
|
|||
// s = r_(i-1) - alpha_i nu_i
|
|||
residuals.Add(nu.Multiply(-alpha), vecS); |
|||
|
|||
// Check if we're converged. If so then stop. Otherwise continue;
|
|||
// Calculate the temporary result.
|
|||
// Be careful not to change any of the temp vectors, except for
|
|||
// temp. Others will be used in the calculation later on.
|
|||
// x_i = x_(i-1) + alpha_i * p^_i + s^_i
|
|||
vecPdash.Multiply(alpha, temp); |
|||
temp.Add(vecSdash, temp); |
|||
temp.Add(result, temp); |
|||
|
|||
// Check convergence and stop if we are converged.
|
|||
if (!ShouldContinue(iterationNumber, temp, input, vecS)) |
|||
{ |
|||
temp.CopyTo(result); |
|||
|
|||
// Calculate the true residual
|
|||
CalculateTrueResidual(matrix, residuals, result, input); |
|||
|
|||
// Now recheck the convergence
|
|||
if (!ShouldContinue(iterationNumber, result, input, residuals)) |
|||
{ |
|||
// We're all good now.
|
|||
return; |
|||
} |
|||
|
|||
// Continue the calculation
|
|||
iterationNumber++; |
|||
continue; |
|||
} |
|||
|
|||
// SOLVE Ms~ = s
|
|||
_preconditioner.Approximate(vecS, vecSdash); |
|||
|
|||
// temp = As~
|
|||
matrix.Multiply(vecSdash, t); |
|||
|
|||
// omega_i = temp^T s / temp^T temp
|
|||
omega = t.DotProduct(vecS) / t.DotProduct(t); |
|||
|
|||
// x_i = x_(i-1) + alpha_i p^ + omega_i s^
|
|||
result.Add(vecSdash.Multiply(omega), result); |
|||
result.Add(vecPdash.Multiply(alpha), result); |
|||
|
|||
t.Multiply(-omega, residuals); |
|||
residuals.Add(vecS, residuals); |
|||
|
|||
// for continuation it is necessary that omega_i != 0.0f
|
|||
// If omega is only 1 ULP from zero then we fail.
|
|||
if (omega.Real.AlmostEqual(0, 1) && omega.Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
// Omega-type breakdown
|
|||
throw new Exception("Iterative solver experience a numerical break down"); |
|||
} |
|||
|
|||
if (!ShouldContinue(iterationNumber, result, input, residuals)) |
|||
{ |
|||
// Recalculate the residuals and go round again. This is done to ensure that
|
|||
// we have the proper residuals.
|
|||
// The residual calculation based on omega_i * s can be off by a factor 10. So here
|
|||
// we calculate the real residual (which can be expensive) but we only do it if we're
|
|||
// sufficiently close to the finish.
|
|||
CalculateTrueResidual(matrix, residuals, result, input); |
|||
} |
|||
|
|||
iterationNumber++; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the true residual of the matrix equation Ax = b according to: residual = b - Ax
|
|||
/// </summary>
|
|||
/// <param name="matrix">Instance of the <see cref="Matrix{T}"/> A.</param>
|
|||
/// <param name="residual">Residual values in <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="x">Instance of the <see cref="Vector{T}"/> x.</param>
|
|||
/// <param name="b">Instance of the <see cref="Vector{T}"/> b.</param>
|
|||
private static void CalculateTrueResidual(Matrix<Complex32> matrix, Vector<Complex32> residual, Vector<Complex32> x, Vector<Complex32> b) |
|||
{ |
|||
// -Ax = residual
|
|||
matrix.Multiply(x, residual); |
|||
|
|||
// Do not use residual = residual.Negate() because it creates another object
|
|||
residual.Multiply(-1, residual); |
|||
|
|||
// residual + b
|
|||
residual.Add(b, residual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determine if calculation should continue
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">Number of iterations passed</param>
|
|||
/// <param name="result">Result <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="source">Source <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="residuals">Residual <see cref="Vector{T}"/>.</param>
|
|||
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
|
|||
private bool ShouldContinue(int iterationNumber, Vector<Complex32> result, Vector<Complex32> source, Vector<Complex32> residuals) |
|||
{ |
|||
if (_hasBeenStopped) |
|||
{ |
|||
_iterator.IterationCancelled(); |
|||
return true; |
|||
} |
|||
|
|||
_iterator.DetermineStatus(iterationNumber, result, source, residuals); |
|||
var status = _iterator.Status; |
|||
|
|||
// We stop if either:
|
|||
// - the user has stopped the calculation
|
|||
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
|
|||
return (!status.TerminatesCalculation) && (!_hasBeenStopped); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient <see cref="Matrix{T}"/>, <c>A</c>.</param>
|
|||
/// <param name="input">The solution <see cref="Matrix{T}"/>, <c>B</c>.</param>
|
|||
/// <returns>The result <see cref="Matrix{T}"/>, <c>X</c>.</returns>
|
|||
public Matrix<Complex32> Solve(Matrix<Complex32> matrix, Matrix<Complex32> input) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount); |
|||
Solve(matrix, input, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient <see cref="Matrix{T}"/>, <c>A</c>.</param>
|
|||
/// <param name="input">The solution <see cref="Matrix{T}"/>, <c>B</c>.</param>
|
|||
/// <param name="result">The result <see cref="Matrix{T}"/>, <c>X</c></param>
|
|||
public void Solve(Matrix<Complex32> matrix, Matrix<Complex32> input, Matrix<Complex32> result) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (matrix.RowCount != input.RowCount || input.RowCount != result.RowCount || input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
for (var column = 0; column < input.ColumnCount; column++) |
|||
{ |
|||
var solution = Solve(matrix, input.Column(column)); |
|||
foreach (var element in solution.GetIndexedEnumerator()) |
|||
{ |
|||
result.At(element.Key, column, element.Value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,630 @@ |
|||
// <copyright file="CompositeSolver.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Iterative |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Generic; |
|||
using Generic.Solvers; |
|||
using Generic.Solvers.Status; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// A composite matrix solver. The actual solver is made by a sequence of
|
|||
/// matrix solvers.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// Solver based on:<br />
|
|||
/// Faster PDE-based simulations using robust composite linear solvers<br />
|
|||
/// S. Bhowmicka, P. Raghavan a,*, L. McInnes b, B. Norris<br />
|
|||
/// Future Generation Computer Systems, Vol 20, 2004, pp 373–387<br />
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// Note that if an iterator is passed to this solver it will be used for all the sub-solvers.
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
public sealed class CompositeSolver : IIterativeSolver<Complex32> |
|||
{ |
|||
#region Internal class - DoubleComparer
|
|||
/// <summary>
|
|||
/// An <c>IComparer</c> used to compare double precision floating points.
|
|||
/// </summary>
|
|||
/// NOTE: The instance of this class is used only in <see cref="SolverSetups"/>. If C# suppports interface inheritence
|
|||
/// NOTE: and methods in anonymous types, then this class should be deleted and anonymous type implemented with IComaprer support
|
|||
/// NOTE: in <see cref="SolverSetups"/> constructor
|
|||
public sealed class DoubleComparer : IComparer<double> |
|||
{ |
|||
/// <summary>
|
|||
/// Compares two double values based on the selected comparison method.
|
|||
/// </summary>
|
|||
/// <param name="x">The first double to compare.</param>
|
|||
/// <param name="y">The second double to compare.</param>
|
|||
/// <returns>
|
|||
/// A 32-bit signed integer that indicates the relative order of the objects being compared. The return
|
|||
/// value has the following meanings:
|
|||
/// Value Meaning Less than zero This object is less than the other parameter.
|
|||
/// Zero This object is equal to other.
|
|||
/// Greater than zero This object is greater than other.
|
|||
/// </returns>
|
|||
public int Compare(double x, double y) |
|||
{ |
|||
return x.CompareTo(y, 1); |
|||
} |
|||
} |
|||
#endregion
|
|||
|
|||
/// <summary>
|
|||
/// The default status used if the solver is not running.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus NonRunningStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// The default status used if the solver is running.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus RunningStatus = new CalculationRunning(); |
|||
|
|||
#if SILVERLIGHT
|
|||
private static readonly Dictionary<double, List<IIterativeSolverSetup<Complex32>>> SolverSetups = new Dictionary<double, List<IIterativeSolverSetup<Complex32>>>(); |
|||
#else
|
|||
/// <summary>
|
|||
/// The collection of iterative solver setups. Stored based on the
|
|||
/// ratio between the relative speed and relative accuracy.
|
|||
/// </summary>
|
|||
private static readonly SortedList<double, List<IIterativeSolverSetup<Complex32>>> SolverSetups = new SortedList<double, List<IIterativeSolverSetup<Complex32>>>(new DoubleComparer()); |
|||
#endif
|
|||
|
|||
#region Solver information loading methods
|
|||
|
|||
/// <summary>
|
|||
/// Loads all the available <see cref="IIterativeSolverSetup{T}"/> objects from the MathNet.Numerics assembly.
|
|||
/// </summary>
|
|||
public static void LoadSolverInformation() |
|||
{ |
|||
LoadSolverInformation(new Type[0]); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the available <see cref="IIterativeSolverSetup{T}"/> objects from the MathNet.Numerics assembly.
|
|||
/// </summary>
|
|||
/// <param name="typesToExclude">The <see cref="IIterativeSolver{T}"/> types that should not be loaded.</param>
|
|||
public static void LoadSolverInformation(Type[] typesToExclude) |
|||
{ |
|||
LoadSolverInformationFromAssembly(Assembly.GetExecutingAssembly(), typesToExclude); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the available <see cref="IIterativeSolverSetup{T}"/> objects from the assembly specified by the file location.
|
|||
/// </summary>
|
|||
/// <param name="assemblyLocation">The fully qualified path to the assembly.</param>
|
|||
public static void LoadSolverInformationFromAssembly(string assemblyLocation) |
|||
{ |
|||
LoadSolverInformationFromAssembly(assemblyLocation, new Type[0]); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the available <see cref="IIterativeSolverSetup{T}"/> objects from the assembly specified by the file location.
|
|||
/// </summary>
|
|||
/// <param name="assemblyLocation">The fully qualified path to the assembly.</param>
|
|||
/// <param name="typesToExclude">The <see cref="IIterativeSolver{T}"/> types that should not be loaded. </param>
|
|||
public static void LoadSolverInformationFromAssembly(string assemblyLocation, params Type[] typesToExclude) |
|||
{ |
|||
if (assemblyLocation == null) |
|||
{ |
|||
throw new ArgumentNullException("assemblyLocation"); |
|||
} |
|||
|
|||
if (assemblyLocation.Length == 0) |
|||
{ |
|||
throw new ArgumentException(); |
|||
} |
|||
|
|||
if (!File.Exists(assemblyLocation)) |
|||
{ |
|||
throw new FileNotFoundException(); |
|||
} |
|||
|
|||
// Get the assembly name
|
|||
var assemblyFileName = Path.GetFileNameWithoutExtension(assemblyLocation); |
|||
|
|||
// Now load the assembly with an AssemblyName
|
|||
var assemblyName = new AssemblyName(assemblyFileName); |
|||
var assembly = Assembly.Load(assemblyName); |
|||
|
|||
// <ay throws:
|
|||
// ArgumentNullException --> Can't get this because we checked that the file exists.
|
|||
// FileNotFoundException --> Can't get this because we checked that the file exists.
|
|||
// FileLoadException
|
|||
// BadImageFormatException
|
|||
// Now we can load the solver information.
|
|||
LoadSolverInformationFromAssembly(assembly, typesToExclude); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the available <see cref="IIterativeSolverSetup{T}"/> objects from the assembly specified by the assembly name.
|
|||
/// </summary>
|
|||
/// <param name="assemblyName">The <see cref="AssemblyName"/> of the assembly that should be searched for setup objects. </param>
|
|||
public static void LoadSolverInformationFromAssembly(AssemblyName assemblyName) |
|||
{ |
|||
LoadSolverInformationFromAssembly(assemblyName, new Type[0]); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the available <see cref="IIterativeSolverSetup{T}"/> objects from the assembly specified by the assembly name.
|
|||
/// </summary>
|
|||
/// <param name="assemblyName">The <see cref="AssemblyName"/> of the assembly that should be searched for setup objects.</param>
|
|||
/// <param name="typesToExclude">The <see cref="IIterativeSolver{T}"/> types that should not be loaded.</param>
|
|||
public static void LoadSolverInformationFromAssembly(AssemblyName assemblyName, params Type[] typesToExclude) |
|||
{ |
|||
if (assemblyName == null) |
|||
{ |
|||
throw new ArgumentNullException("assemblyName"); |
|||
} |
|||
|
|||
var assembly = Assembly.Load(assemblyName); |
|||
|
|||
// May throw:
|
|||
// ArgumentNullException --> Can't get this because we checked it.
|
|||
// FileNotFoundException
|
|||
// FileLoadException
|
|||
// BadImageFormatException
|
|||
// Now we can load the solver information.
|
|||
LoadSolverInformationFromAssembly(assembly, typesToExclude); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the available <see cref="IIterativeSolverSetup{T}"/> objects from the assembly specified by the type.
|
|||
/// </summary>
|
|||
/// <param name="typeInAssembly">The type in the assembly which should be searched for setup objects.</param>
|
|||
public static void LoadSolverInformationFromAssembly(Type typeInAssembly) |
|||
{ |
|||
LoadSolverInformationFromAssembly(typeInAssembly, new Type[0]); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the available <see cref="IIterativeSolverSetup{T}"/> objects from the assembly specified by the type.
|
|||
/// </summary>
|
|||
/// <param name="typeInAssembly">The type in the assembly which should be searched for setup objects.</param>
|
|||
/// <param name="typesToExclude">The <see cref="IIterativeSolver{T}"/> types that should not be loaded.</param>
|
|||
public static void LoadSolverInformationFromAssembly(Type typeInAssembly, params Type[] typesToExclude) |
|||
{ |
|||
if (typeInAssembly == null) |
|||
{ |
|||
throw new ArgumentNullException("typeInAssembly"); |
|||
} |
|||
|
|||
LoadSolverInformationFromAssembly(typeInAssembly.Assembly, typesToExclude); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the available <see cref="IIterativeSolverSetup{T}"/> objects from the specified assembly.
|
|||
/// </summary>
|
|||
/// <param name="assembly">The assembly which will be searched for setup objects.</param>
|
|||
public static void LoadSolverInformationFromAssembly(Assembly assembly) |
|||
{ |
|||
LoadSolverInformationFromAssembly(assembly, new Type[0]); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the available <see cref="IIterativeSolverSetup{T}"/> objects from the specified assembly.
|
|||
/// </summary>
|
|||
/// <param name="assembly">The assembly which will be searched for setup objects.</param>
|
|||
/// <param name="typesToExclude">The <see cref="IIterativeSolver{T}"/> types that should not be loaded.</param>
|
|||
public static void LoadSolverInformationFromAssembly(Assembly assembly, params Type[] typesToExclude) |
|||
{ |
|||
if (assembly == null) |
|||
{ |
|||
throw new ArgumentNullException("Assembly"); |
|||
} |
|||
|
|||
if (typesToExclude == null) |
|||
{ |
|||
throw new ArgumentNullException("typesToExclude"); |
|||
} |
|||
|
|||
var excludedTypes = new List<Type>(typesToExclude); |
|||
|
|||
// Load all the types in the assembly
|
|||
// Find all the types that implement IIterativeSolverSetup
|
|||
// Create an object of each of these types
|
|||
// Get the type of the iterative solver that will be instantiated by the setup object
|
|||
// Check if it's on the excluding list, if so throw the setup object away otherwise keep it.
|
|||
var interfaceTypes = new List<Type>(); |
|||
foreach (var type in assembly.GetTypes().Where(type => (!type.IsAbstract && !type.IsEnum && !type.IsInterface && type.IsVisible))) |
|||
{ |
|||
interfaceTypes.AddRange(type.GetInterfaces()); |
|||
if (!interfaceTypes.Any(match => typeof(IIterativeSolverSetup<Complex32>).IsAssignableFrom(match))) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
// See if we actually want this type of iterative solver
|
|||
IIterativeSolverSetup<Complex32> setup; |
|||
try |
|||
{ |
|||
// If something goes wrong we just ignore it and move on with the next type.
|
|||
// There should probably be a log somewhere indicating that something went wrong?
|
|||
setup = (IIterativeSolverSetup<Complex32>)Activator.CreateInstance(type); |
|||
} |
|||
catch (ArgumentException) |
|||
{ |
|||
continue; |
|||
} |
|||
catch (NotSupportedException) |
|||
{ |
|||
continue; |
|||
} |
|||
catch (TargetInvocationException) |
|||
{ |
|||
continue; |
|||
} |
|||
catch (MethodAccessException) |
|||
{ |
|||
continue; |
|||
} |
|||
catch (MissingMethodException) |
|||
{ |
|||
continue; |
|||
} |
|||
catch (MemberAccessException) |
|||
{ |
|||
continue; |
|||
} |
|||
catch (TypeLoadException) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
if (excludedTypes.Any(match => match.IsAssignableFrom(setup.SolverType) || |
|||
match.IsAssignableFrom(setup.PreconditionerType))) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
// Ok we want the solver, so store the object
|
|||
var ratio = setup.SolutionSpeed / setup.Reliability; |
|||
if (!SolverSetups.ContainsKey(ratio)) |
|||
{ |
|||
SolverSetups.Add(ratio, new List<IIterativeSolverSetup<Complex32>>()); |
|||
} |
|||
|
|||
var list = SolverSetups[ratio]; |
|||
list.Add(setup); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
/// <summary>
|
|||
/// The collection of solvers that will be used to
|
|||
/// </summary>
|
|||
private readonly List<IIterativeSolver<Complex32>> _solvers = new List<IIterativeSolver<Complex32>>(); |
|||
|
|||
/// <summary>
|
|||
/// The status of the calculation.
|
|||
/// </summary>
|
|||
private ICalculationStatus _status = NonRunningStatus; |
|||
|
|||
/// <summary>
|
|||
/// The iterator that is used to control the iteration process.
|
|||
/// </summary>
|
|||
private IIterator<Complex32> _iterator; |
|||
|
|||
/// <summary>
|
|||
/// A flag indicating if the solver has been stopped or not.
|
|||
/// </summary>
|
|||
private bool _hasBeenStopped; |
|||
|
|||
/// <summary>
|
|||
/// The solver that is currently running. Reference is used to be able to stop the
|
|||
/// solver if the user cancels the solve process.
|
|||
/// </summary>
|
|||
private IIterativeSolver<Complex32> _currentSolver; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CompositeSolver"/> class with the default iterator.
|
|||
/// </summary>
|
|||
public CompositeSolver() : this(null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CompositeSolver"/> class with the specified iterator.
|
|||
/// </summary>
|
|||
/// <param name="iterator">The iterator that will be used to control the iteration process. </param>
|
|||
public CompositeSolver(IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the <c>IIterator</c> that will be used to track the iterative process.
|
|||
/// </summary>
|
|||
/// <param name="iterator">The iterator.</param>
|
|||
public void SetIterator(IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the status of the iteration once the calculation is finished.
|
|||
/// </summary>
|
|||
public ICalculationStatus IterationResult |
|||
{ |
|||
get |
|||
{ |
|||
return _status; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Stops the solve process.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
|
|||
/// </remarks>
|
|||
public void StopSolve() |
|||
{ |
|||
_hasBeenStopped = true; |
|||
if (_currentSolver != null) |
|||
{ |
|||
_currentSolver.StopSolve(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="vector">The solution vector, <c>b</c>.</param>
|
|||
/// <returns>The result vector, <c>x</c>.</returns>
|
|||
public Vector<Complex32> Solve(Matrix<Complex32> matrix, Vector<Complex32> vector) |
|||
{ |
|||
if (vector == null) |
|||
{ |
|||
throw new ArgumentNullException(); |
|||
} |
|||
|
|||
Vector<Complex32> result = new DenseVector(matrix.RowCount); |
|||
Solve(matrix, vector, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution vector, <c>b</c></param>
|
|||
/// <param name="result">The result vector, <c>x</c></param>
|
|||
public void Solve(Matrix<Complex32> matrix, Vector<Complex32> input, Vector<Complex32> result) |
|||
{ |
|||
// If we were stopped before, we are no longer
|
|||
// We're doing this at the start of the method to ensure
|
|||
// that we can use these fields immediately.
|
|||
_hasBeenStopped = false; |
|||
_currentSolver = null; |
|||
|
|||
// Error checks
|
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (result.Count != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Initialize the solver fields
|
|||
// Set the convergence monitor
|
|||
if (_iterator == null) |
|||
{ |
|||
_iterator = Iterator.CreateDefault(); |
|||
} |
|||
|
|||
// Load the solvers into our own internal data structure
|
|||
// Once we have solvers we can always reuse them.
|
|||
if (_solvers.Count == 0) |
|||
{ |
|||
LoadSolvers(); |
|||
} |
|||
|
|||
// Create a copy of the solution and result vectors so we can use them
|
|||
// later on
|
|||
var internalInput = input.Clone(); |
|||
var internalResult = result.Clone(); |
|||
|
|||
foreach (var solver in _solvers.TakeWhile(solver => !_hasBeenStopped)) |
|||
{ |
|||
// Store a reference to the solver so we can stop it.
|
|||
_currentSolver = solver; |
|||
|
|||
try |
|||
{ |
|||
// Reset the iterator and pass it to the solver
|
|||
_iterator.ResetToPrecalculationState(); |
|||
solver.SetIterator(_iterator); |
|||
|
|||
// Start the solver
|
|||
solver.Solve(matrix, internalInput, internalResult); |
|||
} |
|||
catch (Exception) |
|||
{ |
|||
// The solver broke down.
|
|||
// Log a message about this
|
|||
// Switch to the next preconditioner.
|
|||
// Reset the solution vector to the previous solution
|
|||
input.CopyTo(internalInput); |
|||
_status = RunningStatus; |
|||
continue; |
|||
} |
|||
|
|||
// There was no fatal breakdown so check the status
|
|||
if (_iterator.Status is CalculationConverged) |
|||
{ |
|||
// We're done
|
|||
break; |
|||
} |
|||
|
|||
// We're not done
|
|||
// Either:
|
|||
// - calculation finished without convergence
|
|||
if (_iterator.Status is CalculationStoppedWithoutConvergence) |
|||
{ |
|||
// Copy the internal result to the result vector and
|
|||
// continue with the calculation.
|
|||
internalInput.CopyTo(input); |
|||
} |
|||
else |
|||
{ |
|||
// - calculation failed --> restart with the original vector
|
|||
// - calculation diverged --> restart with the original vector
|
|||
// - Some unknown status occurred --> To be safe restart.
|
|||
input.CopyTo(internalInput); |
|||
} |
|||
} |
|||
|
|||
// Inside the loop we already copied the final results (if there are any)
|
|||
// So no need to do that again.
|
|||
|
|||
// Clean up
|
|||
// No longer need the current solver
|
|||
_currentSolver = null; |
|||
|
|||
// Set the final status
|
|||
_status = _iterator.Status; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Load solvers
|
|||
/// </summary>
|
|||
private void LoadSolvers() |
|||
{ |
|||
if (SolverSetups.Count == 0) |
|||
{ |
|||
throw new Exception("IIterativeSolverSetup objects not found"); |
|||
} |
|||
|
|||
#if SILVERLIGHT
|
|||
foreach (var setup in SolverSetups.OrderBy(solver => solver.Key, new DoubleComparer()).Select(pair => pair.Value).SelectMany(setups => setups)) |
|||
#else
|
|||
foreach (var setup in SolverSetups.Select(pair => pair.Value).SelectMany(setups => setups)) |
|||
#endif
|
|||
{ |
|||
_solvers.Add(setup.CreateNew()); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution matrix, <c>B</c>.</param>
|
|||
/// <returns>The result matrix, <c>X</c>.</returns>
|
|||
public Matrix<Complex32> Solve(Matrix<Complex32> matrix, Matrix<Complex32> input) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount); |
|||
Solve(matrix, input, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution matrix, <c>B</c>.</param>
|
|||
/// <param name="result">The result matrix, <c>X</c></param>
|
|||
public void Solve(Matrix<Complex32> matrix, Matrix<Complex32> input, Matrix<Complex32> result) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (matrix.RowCount != input.RowCount || input.RowCount != result.RowCount || input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
for (var column = 0; column < input.ColumnCount; column++) |
|||
{ |
|||
var solution = Solve(matrix, input.Column(column)); |
|||
foreach (var element in solution.GetIndexedEnumerator()) |
|||
{ |
|||
result.At(element.Key, column, element.Value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,624 @@ |
|||
// <copyright file="GpBiCg.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Iterative |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Solvers; |
|||
using Generic.Solvers.Preconditioners; |
|||
using Generic.Solvers.Status; |
|||
using Numerics; |
|||
using Preconditioners; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// A Generalized Product Bi-Conjugate Gradient iterative matrix solver.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The Generalized Product Bi-Conjugate Gradient (GPBiCG) solver is an
|
|||
/// alternative version of the Bi-Conjugate Gradient stabilized (CG) solver.
|
|||
/// Unlike the CG solver the GPBiCG solver can be used on
|
|||
/// non-symmetric matrices. <br/>
|
|||
/// Note that much of the success of the solver depends on the selection of the
|
|||
/// proper preconditioner.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The GPBiCG algorithm was taken from: <br/>
|
|||
/// GPBiCG(m,l): A hybrid of BiCGSTAB and GPBiCG methods with
|
|||
/// efficiency and robustness
|
|||
/// <br/>
|
|||
/// S. Fujino
|
|||
/// <br/>
|
|||
/// Applied Numerical Mathematics, Volume 41, 2002, pp 107 - 117
|
|||
/// <br/>
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The example code below provides an indication of the possible use of the
|
|||
/// solver.
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
public sealed class GpBiCg : IIterativeSolver<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The status used if there is no status, i.e. the solver hasn't run yet and there is no
|
|||
/// iterator.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus DefaultStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// The preconditioner that will be used. Can be set to <c>null</c>, in which case the default
|
|||
/// pre-conditioner will be used.
|
|||
/// </summary>
|
|||
private IPreConditioner<Complex32> _preconditioner; |
|||
|
|||
/// <summary>
|
|||
/// The iterative process controller.
|
|||
/// </summary>
|
|||
private IIterator<Complex32> _iterator; |
|||
|
|||
/// <summary>
|
|||
/// Indicates the number of <c>BiCGStab</c> steps should be taken
|
|||
/// before switching.
|
|||
/// </summary>
|
|||
private int _numberOfBiCgStabSteps = 1; |
|||
|
|||
/// <summary>
|
|||
/// Indicates the number of <c>GPBiCG</c> steps should be taken
|
|||
/// before switching.
|
|||
/// </summary>
|
|||
private int _numberOfGpbiCgSteps = 4; |
|||
|
|||
/// <summary>
|
|||
/// Indicates if the user has stopped the solver.
|
|||
/// </summary>
|
|||
private bool _hasBeenStopped; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GpBiCg"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// When using this constructor the solver will use the <see cref="IIterator{T}"/> with
|
|||
/// the standard settings and a default preconditioner.
|
|||
/// </remarks>
|
|||
public GpBiCg() : this(null, null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GpBiCg"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// When using this constructor the solver will use a default preconditioner.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The main advantages of using a user defined <see cref="IIterator{T}"/> are:
|
|||
/// <list type="number">
|
|||
/// <item>It is possible to set the desired convergence limits.</item>
|
|||
/// <item>
|
|||
/// It is possible to check the reason for which the solver finished
|
|||
/// the iterative procedure by calling the <see cref="IIterator{T}.Status"/> property.
|
|||
/// </item>
|
|||
/// </list>
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <param name="iterator">The <see cref="IIterator{T}"/> that will be used to monitor the iterative process.</param>
|
|||
public GpBiCg(IIterator<Complex32> iterator) : this(null, iterator) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GpBiCg"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// When using this constructor the solver will use the <see cref="IIterator{T}"/> with
|
|||
/// the standard settings.
|
|||
/// </remarks>
|
|||
/// <param name="preconditioner">The <see cref="IPreConditioner{T}"/> that will be used to precondition the matrix equation.</param>
|
|||
public GpBiCg(IPreConditioner<Complex32> preconditioner) : this(preconditioner, null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GpBiCg"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The main advantages of using a user defined <see cref="IIterator{T}"/> are:
|
|||
/// <list type="number">
|
|||
/// <item>It is possible to set the desired convergence limits.</item>
|
|||
/// <item>
|
|||
/// It is possible to check the reason for which the solver finished
|
|||
/// the iterative procedure by calling the <see cref="IIterator{T}.Status"/> property.
|
|||
/// </item>
|
|||
/// </list>
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <param name="preconditioner">The <see cref="IPreConditioner{T}"/> that will be used to precondition the matrix equation.</param>
|
|||
/// <param name="iterator">The <see cref="IIterator{T}"/> that will be used to monitor the iterative process.</param>
|
|||
public GpBiCg(IPreConditioner<Complex32> preconditioner, IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
_preconditioner = preconditioner; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the number of steps taken with the <c>BiCgStab</c> algorithm
|
|||
/// before switching over to the <c>GPBiCG</c> algorithm.
|
|||
/// </summary>
|
|||
public int NumberOfBiCgStabSteps |
|||
{ |
|||
get |
|||
{ |
|||
return _numberOfBiCgStabSteps; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
if (value < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("value"); |
|||
} |
|||
|
|||
_numberOfBiCgStabSteps = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the number of steps taken with the <c>GPBiCG</c> algorithm
|
|||
/// before switching over to the <c>BiCgStab</c> algorithm.
|
|||
/// </summary>
|
|||
public int NumberOfGpBiCgSteps |
|||
{ |
|||
get |
|||
{ |
|||
return _numberOfGpbiCgSteps; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
if (value < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("value"); |
|||
} |
|||
|
|||
_numberOfGpbiCgSteps = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the <see cref="IPreConditioner{T}"/> that will be used to precondition the iterative process.
|
|||
/// </summary>
|
|||
/// <param name="preconditioner">The preconditioner.</param>
|
|||
public void SetPreconditioner(IPreConditioner<Complex32> preconditioner) |
|||
{ |
|||
_preconditioner = preconditioner; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the <see cref="IIterator{T}"/> that will be used to track the iterative process.
|
|||
/// </summary>
|
|||
/// <param name="iterator">The iterator.</param>
|
|||
public void SetIterator(IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the status of the iteration once the calculation is finished.
|
|||
/// </summary>
|
|||
public ICalculationStatus IterationResult |
|||
{ |
|||
get |
|||
{ |
|||
return (_iterator != null) ? _iterator.Status : DefaultStatus; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Stops the solve process.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Note that it may take an indetermined amount of time for the solver to actually
|
|||
/// stop the process.
|
|||
/// </remarks>
|
|||
public void StopSolve() |
|||
{ |
|||
_hasBeenStopped = true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="vector">The solution vector, <c>b</c>.</param>
|
|||
/// <returns>The result vector, <c>x</c>.</returns>
|
|||
public Vector<Complex32> Solve(Matrix<Complex32> matrix, Vector<Complex32> vector) |
|||
{ |
|||
if (vector == null) |
|||
{ |
|||
throw new ArgumentNullException(); |
|||
} |
|||
|
|||
Vector<Complex32> result = new DenseVector(matrix.RowCount); |
|||
Solve(matrix, vector, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution vector, <c>b</c></param>
|
|||
/// <param name="result">The result vector, <c>x</c></param>
|
|||
public void Solve(Matrix<Complex32> matrix, Vector<Complex32> input, Vector<Complex32> result) |
|||
{ |
|||
// If we were stopped before, we are no longer
|
|||
// We're doing this at the start of the method to ensure
|
|||
// that we can use these fields immediately.
|
|||
_hasBeenStopped = false; |
|||
|
|||
// Error checks
|
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (result.Count != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Initialize the solver fields
|
|||
|
|||
// Set the convergence monitor
|
|||
if (_iterator == null) |
|||
{ |
|||
_iterator = Iterator.CreateDefault(); |
|||
} |
|||
|
|||
if (_preconditioner == null) |
|||
{ |
|||
_preconditioner = new UnitPreconditioner(); |
|||
} |
|||
|
|||
_preconditioner.Initialize(matrix); |
|||
|
|||
// x_0 is initial guess
|
|||
// Take x_0 = 0
|
|||
Vector<Complex32> xtemp = new DenseVector(input.Count); |
|||
|
|||
// r_0 = b - Ax_0
|
|||
// This is basically a SAXPY so it could be made a lot faster
|
|||
Vector<Complex32> residuals = new DenseVector(matrix.RowCount); |
|||
CalculateTrueResidual(matrix, residuals, xtemp, input); |
|||
|
|||
// Define the temporary scalars
|
|||
Complex32 beta = 0; |
|||
Complex32 sigma; |
|||
|
|||
// Define the temporary vectors
|
|||
// rDash_0 = r_0
|
|||
Vector<Complex32> rdash = new DenseVector(residuals); |
|||
|
|||
// t_-1 = 0
|
|||
Vector<Complex32> t = new DenseVector(residuals.Count); |
|||
Vector<Complex32> t0 = new DenseVector(residuals.Count); |
|||
|
|||
// w_-1 = 0
|
|||
Vector<Complex32> w = new DenseVector(residuals.Count); |
|||
|
|||
// Define the remaining temporary vectors
|
|||
Vector<Complex32> c = new DenseVector(residuals.Count); |
|||
Vector<Complex32> p = new DenseVector(residuals.Count); |
|||
Vector<Complex32> s = new DenseVector(residuals.Count); |
|||
Vector<Complex32> u = new DenseVector(residuals.Count); |
|||
Vector<Complex32> y = new DenseVector(residuals.Count); |
|||
Vector<Complex32> z = new DenseVector(residuals.Count); |
|||
|
|||
Vector<Complex32> temp = new DenseVector(residuals.Count); |
|||
|
|||
// for (k = 0, 1, .... )
|
|||
var iterationNumber = 0; |
|||
while (ShouldContinue(iterationNumber, xtemp, input, residuals)) |
|||
{ |
|||
// p_k = r_k + beta_(k-1) * (p_(k-1) - u_(k-1))
|
|||
p.Subtract(u, temp); |
|||
|
|||
residuals.Add(temp.Multiply(beta), p); |
|||
|
|||
// Solve M b_k = p_k
|
|||
_preconditioner.Approximate(p, temp); |
|||
|
|||
// s_k = A b_k
|
|||
matrix.Multiply(temp, s); |
|||
|
|||
// alpha_k = (r*_0 * r_k) / (r*_0 * s_k)
|
|||
var alpha = rdash.DotProduct(residuals) / rdash.DotProduct(s); |
|||
|
|||
// y_k = t_(k-1) - r_k - alpha_k * w_(k-1) + alpha_k s_k
|
|||
s.Subtract(w, temp); |
|||
t.Subtract(residuals, y); |
|||
|
|||
y.Add(temp.Multiply(alpha), y); |
|||
|
|||
// Store the old value of t in t0
|
|||
t.CopyTo(t0); |
|||
|
|||
// t_k = r_k - alpha_k s_k
|
|||
residuals.Add(s.Multiply(-alpha), t); |
|||
|
|||
// Solve M d_k = t_k
|
|||
_preconditioner.Approximate(t, temp); |
|||
|
|||
// c_k = A d_k
|
|||
matrix.Multiply(temp, c); |
|||
var cdot = c.DotProduct(c); |
|||
|
|||
// cDot can only be zero if c is a zero vector
|
|||
// We'll set cDot to 1 if it is zero to prevent NaN's
|
|||
// Note that the calculation should continue fine because
|
|||
// c.DotProduct(t) will be zero and so will c.DotProduct(y)
|
|||
if (cdot.Real.AlmostEqual(0, 1) && cdot.Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
cdot = 1.0f; |
|||
} |
|||
|
|||
// Even if we don't want to do any BiCGStab steps we'll still have
|
|||
// to do at least one at the start to initialize the
|
|||
// system, but we'll only have to take special measures
|
|||
// if we don't do any so ...
|
|||
var ctdot = c.DotProduct(t); |
|||
Complex32 eta; |
|||
if (((_numberOfBiCgStabSteps == 0) && (iterationNumber == 0)) || ShouldRunBiCgStabSteps(iterationNumber)) |
|||
{ |
|||
// sigma_k = (c_k * t_k) / (c_k * c_k)
|
|||
sigma = ctdot / cdot; |
|||
|
|||
// eta_k = 0
|
|||
eta = 0; |
|||
} |
|||
else |
|||
{ |
|||
var ydot = y.DotProduct(y); |
|||
|
|||
// yDot can only be zero if y is a zero vector
|
|||
// We'll set yDot to 1 if it is zero to prevent NaN's
|
|||
// Note that the calculation should continue fine because
|
|||
// y.DotProduct(t) will be zero and so will c.DotProduct(y)
|
|||
if (ydot.Real.AlmostEqual(0, 1) && ydot.Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
ydot = 1.0f; |
|||
} |
|||
|
|||
var ytdot = y.DotProduct(t); |
|||
var cydot = c.DotProduct(y); |
|||
|
|||
var denom = (cdot * ydot) - (cydot * cydot); |
|||
|
|||
// sigma_k = ((y_k * y_k)(c_k * t_k) - (y_k * t_k)(c_k * y_k)) / ((c_k * c_k)(y_k * y_k) - (y_k * c_k)(c_k * y_k))
|
|||
sigma = ((ydot * ctdot) - (ytdot * cydot)) / denom; |
|||
|
|||
// eta_k = ((c_k * c_k)(y_k * t_k) - (y_k * c_k)(c_k * t_k)) / ((c_k * c_k)(y_k * y_k) - (y_k * c_k)(c_k * y_k))
|
|||
eta = ((cdot * ytdot) - (cydot * ctdot)) / denom; |
|||
} |
|||
|
|||
// u_k = sigma_k s_k + eta_k (t_(k-1) - r_k + beta_(k-1) u_(k-1))
|
|||
t0.Add(u.Multiply(beta), temp); |
|||
|
|||
temp.Subtract(residuals, temp); |
|||
temp.Multiply(eta, temp); |
|||
|
|||
temp.Add(s.Multiply(sigma), u); |
|||
|
|||
// z_k = sigma_k r_k +_ eta_k z_(k-1) - alpha_k u_k
|
|||
z.Multiply(eta, z); |
|||
z.Add(u.Multiply(-alpha), z); |
|||
z.Add(residuals.Multiply(sigma), z); |
|||
|
|||
// x_(k+1) = x_k + alpha_k p_k + z_k
|
|||
xtemp.Add(p.Multiply(alpha), xtemp); |
|||
|
|||
xtemp.Add(z, xtemp); |
|||
|
|||
// r_(k+1) = t_k - eta_k y_k - sigma_k c_k
|
|||
// Copy the old residuals to a temp vector because we'll
|
|||
// need those in the next step
|
|||
residuals.CopyTo(t0); |
|||
|
|||
t.Add(y.Multiply(-eta), residuals); |
|||
|
|||
residuals.Add(c.Multiply(-sigma), residuals); |
|||
|
|||
// beta_k = alpha_k / sigma_k * (r*_0 * r_(k+1)) / (r*_0 * r_k)
|
|||
// But first we check if there is a possible NaN. If so just reset beta to zero.
|
|||
beta = (!sigma.Real.AlmostEqual(0, 1) || !sigma.Imaginary.AlmostEqual(0, 1)) ? alpha / sigma * rdash.DotProduct(residuals) / rdash.DotProduct(t0) : 0; |
|||
|
|||
// w_k = c_k + beta_k s_k
|
|||
c.Add(s.Multiply(beta), w); |
|||
|
|||
// Get the real value
|
|||
_preconditioner.Approximate(xtemp, result); |
|||
|
|||
// Now check for convergence
|
|||
if (!ShouldContinue(iterationNumber, result, input, residuals)) |
|||
{ |
|||
// Recalculate the residuals and go round again. This is done to ensure that
|
|||
// we have the proper residuals.
|
|||
CalculateTrueResidual(matrix, residuals, result, input); |
|||
} |
|||
|
|||
// Next iteration.
|
|||
iterationNumber++; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the true residual of the matrix equation Ax = b according to: residual = b - Ax
|
|||
/// </summary>
|
|||
/// <param name="matrix">Instance of the <see cref="Matrix{T}"/> A.</param>
|
|||
/// <param name="residual">Residual values in <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="x">Instance of the <see cref="Vector{T}"/> x.</param>
|
|||
/// <param name="b">Instance of the <see cref="Vector{T}"/> b.</param>
|
|||
private static void CalculateTrueResidual(Matrix<Complex32> matrix, Vector<Complex32> residual, Vector<Complex32> x, Vector<Complex32> b) |
|||
{ |
|||
// -Ax = residual
|
|||
matrix.Multiply(x, residual); |
|||
residual.Multiply(-1, residual); |
|||
|
|||
// residual + b
|
|||
residual.Add(b, residual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determine if calculation should continue
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">Number of iterations passed</param>
|
|||
/// <param name="result">Result <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="source">Source <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="residuals">Residual <see cref="Vector{T}"/>.</param>
|
|||
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
|
|||
private bool ShouldContinue(int iterationNumber, Vector<Complex32> result, Vector<Complex32> source, Vector<Complex32> residuals) |
|||
{ |
|||
if (_hasBeenStopped) |
|||
{ |
|||
_iterator.IterationCancelled(); |
|||
return true; |
|||
} |
|||
|
|||
_iterator.DetermineStatus(iterationNumber, result, source, residuals); |
|||
var status = _iterator.Status; |
|||
|
|||
// We stop if either:
|
|||
// - the user has stopped the calculation
|
|||
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
|
|||
return (!status.TerminatesCalculation) && (!_hasBeenStopped); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Decide if to do steps with BiCgStab
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">Number of iteration</param>
|
|||
/// <returns><c>true</c> if yes, otherwise <c>false</c></returns>
|
|||
private bool ShouldRunBiCgStabSteps(int iterationNumber) |
|||
{ |
|||
// Run the first steps as BiCGStab
|
|||
// The number of steps past a whole iteration set
|
|||
var difference = iterationNumber % (_numberOfBiCgStabSteps + _numberOfGpbiCgSteps); |
|||
|
|||
// Do steps with BiCGStab if:
|
|||
// - The difference is zero or more (i.e. we have done zero or more complete cycles)
|
|||
// - The difference is less than the number of BiCGStab steps that should be taken
|
|||
return (difference >= 0) && (difference < _numberOfBiCgStabSteps); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution matrix, <c>B</c>.</param>
|
|||
/// <returns>The result matrix, <c>X</c>.</returns>
|
|||
public Matrix<Complex32> Solve(Matrix<Complex32> matrix, Matrix<Complex32> input) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount); |
|||
Solve(matrix, input, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution matrix, <c>B</c>.</param>
|
|||
/// <param name="result">The result matrix, <c>X</c></param>
|
|||
public void Solve(Matrix<Complex32> matrix, Matrix<Complex32> input, Matrix<Complex32> result) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (matrix.RowCount != input.RowCount || input.RowCount != result.RowCount || input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
for (var column = 0; column < input.ColumnCount; column++) |
|||
{ |
|||
var solution = Solve(matrix, input.Column(column)); |
|||
foreach (var element in solution.GetIndexedEnumerator()) |
|||
{ |
|||
result.At(element.Key, column, element.Value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,783 @@ |
|||
// <copyright file="MlkBiCgStab.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Iterative |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Linq; |
|||
using Distributions; |
|||
using Factorization; |
|||
using Generic; |
|||
using Generic.Solvers; |
|||
using Generic.Solvers.Preconditioners; |
|||
using Generic.Solvers.Status; |
|||
using Numerics; |
|||
using Preconditioners; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// A Multiple-Lanczos Bi-Conjugate Gradient stabilized iterative matrix solver.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The Multiple-Lanczos Bi-Conjugate Gradient stabilized (ML(k)-BiCGStab) solver is an 'improvement'
|
|||
/// of the standard BiCgStab solver.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The algorithm was taken from: <br/>
|
|||
/// ML(k)BiCGSTAB: A BiCGSTAB variant based on multiple Lanczos starting vectors
|
|||
/// <br/>
|
|||
/// Man-chung Yeung and Tony F. Chan
|
|||
/// <br/>
|
|||
/// SIAM Journal of Scientific Computing
|
|||
/// <br/>
|
|||
/// Volume 21, Number 4, pp. 1263 - 1290
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The example code below provides an indication of the possible use of the
|
|||
/// solver.
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
public sealed class MlkBiCgStab : IIterativeSolver<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The default number of starting vectors.
|
|||
/// </summary>
|
|||
private const int DefaultNumberOfStartingVectors = 50; |
|||
|
|||
/// <summary>
|
|||
/// The status used if there is no status, i.e. the solver hasn't run yet and there is no
|
|||
/// iterator.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus DefaultStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// The preconditioner that will be used. Can be set to <see langword="null" />, in which case the default
|
|||
/// pre-conditioner will be used.
|
|||
/// </summary>
|
|||
private IPreConditioner<Complex32> _preconditioner; |
|||
|
|||
/// <summary>
|
|||
/// The iterative process controller.
|
|||
/// </summary>
|
|||
private IIterator<Complex32> _iterator; |
|||
|
|||
/// <summary>
|
|||
/// The collection of starting vectors which are used as the basis for the Krylov sub-space.
|
|||
/// </summary>
|
|||
private IList<Vector<Complex32>> _startingVectors; |
|||
|
|||
/// <summary>
|
|||
/// The number of starting vectors used by the algorithm
|
|||
/// </summary>
|
|||
private int _numberOfStartingVectors = DefaultNumberOfStartingVectors; |
|||
|
|||
/// <summary>
|
|||
/// Indicates if the user has stopped the solver.
|
|||
/// </summary>
|
|||
private bool _hasBeenStopped; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="MlkBiCgStab"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// When using this constructor the solver will use the <see cref="IIterator{T}"/> with
|
|||
/// the standard settings and a default preconditioner.
|
|||
/// </remarks>
|
|||
public MlkBiCgStab() : this(null, null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="MlkBiCgStab"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// When using this constructor the solver will use a default preconditioner.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The main advantages of using a user defined <see cref="IIterator{T}"/> are:
|
|||
/// <list type="number">
|
|||
/// <item>It is possible to set the desired convergence limits.</item>
|
|||
/// <item>
|
|||
/// It is possible to check the reason for which the solver finished
|
|||
/// the iterative procedure by calling the <see cref="IIterator{T}.Status"/> property.
|
|||
/// </item>
|
|||
/// </list>
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <param name="iterator">The <see cref="IIterator{T}"/> that will be used to monitor the iterative process.</param>
|
|||
public MlkBiCgStab(IIterator<Complex32> iterator) : this(null, iterator) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="MlkBiCgStab"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// When using this constructor the solver will use the <see cref="IIterator{T}"/> with
|
|||
/// the standard settings.
|
|||
/// </remarks>
|
|||
/// <param name="preconditioner">The <see cref="IPreConditioner{T}"/> that will be used to precondition the matrix equation.</param>
|
|||
public MlkBiCgStab(IPreConditioner<Complex32> preconditioner) : this(preconditioner, null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="MlkBiCgStab"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The main advantages of using a user defined <see cref="IIterator{T}"/> are:
|
|||
/// <list type="number">
|
|||
/// <item>It is possible to set the desired convergence limits.</item>
|
|||
/// <item>
|
|||
/// It is possible to check the reason for which the solver finished
|
|||
/// the iterative procedure by calling the <see cref="IIterator{T}.Status"/> property.
|
|||
/// </item>
|
|||
/// </list>
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <param name="preconditioner">The <see cref="IPreConditioner{T}"/> that will be used to precondition the matrix equation.</param>
|
|||
/// <param name="iterator">The <see cref="IIterator{T}"/> that will be used to monitor the iterative process.</param>
|
|||
public MlkBiCgStab(IPreConditioner<Complex32> preconditioner, IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
_preconditioner = preconditioner; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the number of starting vectors.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Must be larger than 1 and smaller than the number of variables in the matrix that
|
|||
/// for which this solver will be used.
|
|||
/// </remarks>
|
|||
public int NumberOfStartingVectors |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _numberOfStartingVectors; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
set |
|||
{ |
|||
if (value <= 1) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("value"); |
|||
} |
|||
|
|||
_numberOfStartingVectors = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Resets the number of starting vectors to the default value.
|
|||
/// </summary>
|
|||
public void ResetNumberOfStartingVectors() |
|||
{ |
|||
_numberOfStartingVectors = DefaultNumberOfStartingVectors; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the <see cref="IPreConditioner{T}"/> that will be used to precondition the iterative process.
|
|||
/// </summary>
|
|||
/// <param name="preconditioner">The preconditioner.</param>
|
|||
public void SetPreconditioner(IPreConditioner<Complex32> preconditioner) |
|||
{ |
|||
_preconditioner = preconditioner; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the <see cref="IIterator{T}"/> that will be used to track the iterative process.
|
|||
/// </summary>
|
|||
/// <param name="iterator">The iterator.</param>
|
|||
public void SetIterator(IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a series of orthonormal vectors which will be used as basis for the
|
|||
/// Krylov sub-space.
|
|||
/// </summary>
|
|||
public IList<Vector<Complex32>> StartingVectors |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _startingVectors; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
set |
|||
{ |
|||
if ((value == null) || (value.Count == 0)) |
|||
{ |
|||
_startingVectors = null; |
|||
} |
|||
else |
|||
{ |
|||
_startingVectors = value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the status of the iteration once the calculation is finished.
|
|||
/// </summary>
|
|||
public ICalculationStatus IterationResult |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return (_iterator != null) ? _iterator.Status : DefaultStatus; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Stops the solve process.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
|
|||
/// </remarks>
|
|||
public void StopSolve() |
|||
{ |
|||
_hasBeenStopped = true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="vector">The solution vector, <c>b</c>.</param>
|
|||
/// <returns>The result vector, <c>x</c>.</returns>
|
|||
public Vector<Complex32> Solve(Matrix<Complex32> matrix, Vector<Complex32> vector) |
|||
{ |
|||
if (vector == null) |
|||
{ |
|||
throw new ArgumentNullException(); |
|||
} |
|||
|
|||
Vector<Complex32> result = new DenseVector(matrix.RowCount); |
|||
Solve(matrix, vector, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution vector, <c>b</c></param>
|
|||
/// <param name="result">The result vector, <c>x</c></param>
|
|||
public void Solve(Matrix<Complex32> matrix, Vector<Complex32> input, Vector<Complex32> result) |
|||
{ |
|||
// If we were stopped before, we are no longer
|
|||
// We're doing this at the start of the method to ensure
|
|||
// that we can use these fields immediately.
|
|||
_hasBeenStopped = false; |
|||
|
|||
// Error checks
|
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (result.Count != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Initialize the solver fields
|
|||
// Set the convergence monitor
|
|||
if (_iterator == null) |
|||
{ |
|||
_iterator = Iterator.CreateDefault(); |
|||
} |
|||
|
|||
if (_preconditioner == null) |
|||
{ |
|||
_preconditioner = new UnitPreconditioner(); |
|||
} |
|||
|
|||
_preconditioner.Initialize(matrix); |
|||
|
|||
// Choose an initial guess x_0
|
|||
// Take x_0 = 0
|
|||
Vector<Complex32> xtemp = new DenseVector(input.Count); |
|||
|
|||
// Choose k vectors q_1, q_2, ..., q_k
|
|||
// Build a new set if:
|
|||
// a) the stored set doesn't exist (i.e. == null)
|
|||
// b) Is of an incorrect length (i.e. too long)
|
|||
// c) The vectors are of an incorrect length (i.e. too long or too short)
|
|||
var useOld = false; |
|||
if (_startingVectors != null) |
|||
{ |
|||
// We don't accept collections with zero starting vectors so ...
|
|||
if (_startingVectors.Count <= NumberOfStartingVectorsToCreate(_numberOfStartingVectors, input.Count)) |
|||
{ |
|||
// Only check the first vector for sizing. If that matches we assume the
|
|||
// other vectors match too. If they don't the process will crash
|
|||
if (_startingVectors[0].Count == input.Count) |
|||
{ |
|||
useOld = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
_startingVectors = useOld ? _startingVectors : CreateStartingVectors(_numberOfStartingVectors, input.Count); |
|||
|
|||
// Store the number of starting vectors. Not really necessary but easier to type :)
|
|||
var k = _startingVectors.Count; |
|||
|
|||
// r_0 = b - Ax_0
|
|||
// This is basically a SAXPY so it could be made a lot faster
|
|||
Vector<Complex32> residuals = new DenseVector(matrix.RowCount); |
|||
CalculateTrueResidual(matrix, residuals, xtemp, input); |
|||
|
|||
// Define the temporary values
|
|||
var c = new Complex32[k]; |
|||
|
|||
// Define the temporary vectors
|
|||
Vector<Complex32> gtemp = new DenseVector(residuals.Count); |
|||
|
|||
Vector<Complex32> u = new DenseVector(residuals.Count); |
|||
Vector<Complex32> utemp = new DenseVector(residuals.Count); |
|||
Vector<Complex32> temp = new DenseVector(residuals.Count); |
|||
Vector<Complex32> temp1 = new DenseVector(residuals.Count); |
|||
|
|||
Vector<Complex32> zd = new DenseVector(residuals.Count); |
|||
Vector<Complex32> zg = new DenseVector(residuals.Count); |
|||
Vector<Complex32> zw = new DenseVector(residuals.Count); |
|||
|
|||
var d = CreateVectorArray(_startingVectors.Count, residuals.Count); |
|||
|
|||
// g_0 = r_0
|
|||
var g = CreateVectorArray(_startingVectors.Count, residuals.Count); |
|||
residuals.CopyTo(g[k - 1]); |
|||
|
|||
var w = CreateVectorArray(_startingVectors.Count, residuals.Count); |
|||
|
|||
// FOR (j = 0, 1, 2 ....)
|
|||
var iterationNumber = 0; |
|||
while (ShouldContinue(iterationNumber, xtemp, input, residuals)) |
|||
{ |
|||
// SOLVE M g~_((j-1)k+k) = g_((j-1)k+k)
|
|||
_preconditioner.Approximate(g[k - 1], gtemp); |
|||
|
|||
// w_((j-1)k+k) = A g~_((j-1)k+k)
|
|||
matrix.Multiply(gtemp, w[k - 1]); |
|||
|
|||
// c_((j-1)k+k) = q^T_1 w_((j-1)k+k)
|
|||
c[k - 1] = _startingVectors[0].DotProduct(w[k - 1]); |
|||
if (c[k - 1].Real.AlmostEqual(0, 1) && c[k - 1].Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
throw new Exception("Iterative solver experience a numerical break down"); |
|||
} |
|||
|
|||
// alpha_(jk+1) = q^T_1 r_((j-1)k+k) / c_((j-1)k+k)
|
|||
var alpha = _startingVectors[0].DotProduct(residuals) / c[k - 1]; |
|||
|
|||
// u_(jk+1) = r_((j-1)k+k) - alpha_(jk+1) w_((j-1)k+k)
|
|||
residuals.Add(w[k - 1].Multiply(-alpha), u); |
|||
|
|||
// SOLVE M u~_(jk+1) = u_(jk+1)
|
|||
_preconditioner.Approximate(u, temp1); |
|||
temp1.CopyTo(utemp); |
|||
|
|||
// rho_(j+1) = -u^t_(jk+1) A u~_(jk+1) / ||A u~_(jk+1)||^2
|
|||
matrix.Multiply(temp1, temp); |
|||
var rho = temp.DotProduct(temp); |
|||
|
|||
// If rho is zero then temp is a zero vector and we're probably
|
|||
// about to have zero residuals (i.e. an exact solution).
|
|||
// So set rho to 1.0 because in the next step it will turn to zero.
|
|||
if (rho.Real.AlmostEqual(0, 1) && rho.Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
rho = 1.0f; |
|||
} |
|||
|
|||
rho = -u.DotProduct(temp) / rho; |
|||
|
|||
// x_(jk+1) = x_((j-1)k_k) - rho_(j+1) u~_(jk+1) + alpha_(jk+1) g~_((j-1)k+k)
|
|||
xtemp.Add(utemp.Multiply(-rho), xtemp); |
|||
|
|||
gtemp.Multiply(alpha, gtemp); |
|||
xtemp.Add(gtemp, xtemp); |
|||
|
|||
// r_(jk+1) = rho_(j+1) A u~_(jk+1) + u_(jk+1)
|
|||
u.CopyTo(residuals); |
|||
|
|||
// Reuse temp
|
|||
temp.Multiply(rho, temp); |
|||
residuals.Add(temp, residuals); |
|||
|
|||
// Check convergence and stop if we are converged.
|
|||
if (!ShouldContinue(iterationNumber, xtemp, input, residuals)) |
|||
{ |
|||
// Calculate the true residual
|
|||
CalculateTrueResidual(matrix, residuals, xtemp, input); |
|||
|
|||
// Now recheck the convergence
|
|||
if (!ShouldContinue(iterationNumber, xtemp, input, residuals)) |
|||
{ |
|||
// We're all good now.
|
|||
// Exit from the while loop.
|
|||
break; |
|||
} |
|||
} |
|||
|
|||
// FOR (i = 1,2, ...., k)
|
|||
for (var i = 0; i < k; i++) |
|||
{ |
|||
// z_d = u_(jk+1)
|
|||
u.CopyTo(zd); |
|||
|
|||
// z_g = r_(jk+i)
|
|||
residuals.CopyTo(zg); |
|||
|
|||
// z_w = 0
|
|||
zw.Clear(); |
|||
|
|||
// FOR (s = i, ...., k-1) AND j >= 1
|
|||
Complex32 beta; |
|||
if (iterationNumber >= 1) |
|||
{ |
|||
for (var s = i; s < k - 1; s++) |
|||
{ |
|||
// beta^(jk+i)_((j-1)k+s) = -q^t_(s+1) z_d / c_((j-1)k+s)
|
|||
beta = -_startingVectors[s + 1].DotProduct(zd) / c[s]; |
|||
|
|||
// z_d = z_d + beta^(jk+i)_((j-1)k+s) d_((j-1)k+s)
|
|||
zd.Add(d[s].Multiply(beta), zd); |
|||
|
|||
// z_g = z_g + beta^(jk+i)_((j-1)k+s) g_((j-1)k+s)
|
|||
zg.Add(g[s].Multiply(beta), zg); |
|||
|
|||
// z_w = z_w + beta^(jk+i)_((j-1)k+s) w_((j-1)k+s)
|
|||
zw.Add(w[s].Multiply(beta), zw); |
|||
} |
|||
} |
|||
|
|||
beta = rho * c[k - 1]; |
|||
if (beta.Real.AlmostEqual(0, 1) && beta.Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
throw new Exception("Iterative solver experience a numerical break down"); |
|||
} |
|||
|
|||
// beta^(jk+i)_((j-1)k+k) = -(q^T_1 (r_(jk+1) + rho_(j+1) z_w)) / (rho_(j+1) c_((j-1)k+k))
|
|||
residuals.Add(zw.Multiply(rho), temp); |
|||
beta = -_startingVectors[0].DotProduct(temp) / beta; |
|||
|
|||
// z_g = z_g + beta^(jk+i)_((j-1)k+k) g_((j-1)k+k)
|
|||
zg.Add(g[k - 1].Multiply(beta), zg); |
|||
|
|||
// z_w = rho_(j+1) (z_w + beta^(jk+i)_((j-1)k+k) w_((j-1)k+k))
|
|||
zw.Add(w[k - 1].Multiply(beta), zw); |
|||
zw.Multiply(rho, zw); |
|||
|
|||
// z_d = r_(jk+i) + z_w
|
|||
residuals.Add(zw, zd); |
|||
|
|||
// FOR (s = 1, ... i - 1)
|
|||
for (var s = 0; s < i - 1; s++) |
|||
{ |
|||
// beta^(jk+i)_(jk+s) = -q^T_s+1 z_d / c_(jk+s)
|
|||
beta = -_startingVectors[s + 1].DotProduct(zd) / c[s]; |
|||
|
|||
// z_d = z_d + beta^(jk+i)_(jk+s) * d_(jk+s)
|
|||
zd.Add(d[s].Multiply(beta), zd); |
|||
|
|||
// z_g = z_g + beta^(jk+i)_(jk+s) * g_(jk+s)
|
|||
zg.Add(g[s].Multiply(beta), zg); |
|||
} |
|||
|
|||
// d_(jk+i) = z_d - u_(jk+i)
|
|||
zd.Subtract(u, d[i]); |
|||
|
|||
// g_(jk+i) = z_g + z_w
|
|||
zg.Add(zw, g[i]); |
|||
|
|||
// IF (i < k - 1)
|
|||
if (i < k - 1) |
|||
{ |
|||
// c_(jk+1) = q^T_i+1 d_(jk+i)
|
|||
c[i] = _startingVectors[i + 1].DotProduct(d[i]); |
|||
if (c[i].Real.AlmostEqual(0, 1) && c[i].Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
throw new Exception("Iterative solver experience a numerical break down"); |
|||
} |
|||
|
|||
// alpha_(jk+i+1) = q^T_(i+1) u_(jk+i) / c_(jk+i)
|
|||
alpha = _startingVectors[i + 1].DotProduct(u) / c[i]; |
|||
|
|||
// u_(jk+i+1) = u_(jk+i) - alpha_(jk+i+1) d_(jk+i)
|
|||
u.Add(d[i].Multiply(-alpha), u); |
|||
|
|||
// SOLVE M g~_(jk+i) = g_(jk+i)
|
|||
_preconditioner.Approximate(g[i], gtemp); |
|||
|
|||
// x_(jk+i+1) = x_(jk+i) + rho_(j+1) alpha_(jk+i+1) g~_(jk+i)
|
|||
xtemp.Add(gtemp.Multiply(rho * alpha), xtemp); |
|||
|
|||
// w_(jk+i) = A g~_(jk+i)
|
|||
matrix.Multiply(gtemp, w[i]); |
|||
|
|||
// r_(jk+i+1) = r_(jk+i) - rho_(j+1) alpha_(jk+i+1) w_(jk+i)
|
|||
residuals.Add(w[i].Multiply(-rho * alpha), residuals); |
|||
|
|||
// We can check the residuals here if they're close
|
|||
if (!ShouldContinue(iterationNumber, xtemp, input, residuals)) |
|||
{ |
|||
// Recalculate the residuals and go round again. This is done to ensure that
|
|||
// we have the proper residuals.
|
|||
CalculateTrueResidual(matrix, residuals, xtemp, input); |
|||
} |
|||
} |
|||
} // END ITERATION OVER i
|
|||
|
|||
iterationNumber++; |
|||
} |
|||
|
|||
// copy the temporary result to the real result vector
|
|||
xtemp.CopyTo(result); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the number of starting vectors to create
|
|||
/// </summary>
|
|||
/// <param name="maximumNumberOfStartingVectors">Maximum number</param>
|
|||
/// <param name="numberOfVariables">Number of variables</param>
|
|||
/// <returns>Number of starting vectors to create</returns>
|
|||
private static int NumberOfStartingVectorsToCreate(int maximumNumberOfStartingVectors, int numberOfVariables) |
|||
{ |
|||
// Create no more starting vectors than the size of the problem - 1
|
|||
return Math.Min(maximumNumberOfStartingVectors, (numberOfVariables - 1)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an array of starting vectors.
|
|||
/// </summary>
|
|||
/// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
|
|||
/// <param name="numberOfVariables">The number of variables.</param>
|
|||
/// <returns>
|
|||
/// An array with starting vectors. The array will never be larger than the
|
|||
/// <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
|
|||
/// the <paramref name="numberOfVariables"/> is smaller than
|
|||
/// the <paramref name="maximumNumberOfStartingVectors"/>.
|
|||
/// </returns>
|
|||
private static IList<Vector<Complex32>> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables) |
|||
{ |
|||
// Create no more starting vectors than the size of the problem - 1
|
|||
// Get random values and then orthogonalize them with
|
|||
// modified Gramm - Schmidt
|
|||
var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables); |
|||
|
|||
// Get a random set of samples based on the standard normal distribution with
|
|||
// mean = 0 and sd = 1
|
|||
var distribution = new Normal(); |
|||
|
|||
Matrix<Complex32> matrix = new DenseMatrix(numberOfVariables, count); |
|||
for (var i = 0; i < matrix.ColumnCount; i++) |
|||
{ |
|||
var samples = new Complex32[matrix.RowCount]; |
|||
var samplesRe = distribution.Samples().Take(matrix.RowCount).ToArray(); |
|||
var samplesIm = distribution.Samples().Take(matrix.RowCount).ToArray(); |
|||
for (int j = 0; j < matrix.RowCount; j++) |
|||
{ |
|||
samples[j] = new Complex32((float)samplesRe[j], (float)samplesIm[j]); |
|||
} |
|||
|
|||
// Set the column
|
|||
matrix.SetColumn(i, samples); |
|||
} |
|||
|
|||
// Compute the orthogonalization.
|
|||
var gs = new GramSchmidt(matrix); |
|||
var orthogonalMatrix = gs.Q; |
|||
|
|||
// Now transfer this to vectors
|
|||
var result = new List<Vector<Complex32>>(); |
|||
for (var i = 0; i < orthogonalMatrix.ColumnCount; i++) |
|||
{ |
|||
result.Add(orthogonalMatrix.Column(i)); |
|||
|
|||
// Normalize the result vector
|
|||
result[i].Multiply(1 / (float)result[i].Norm(2), result[i]); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create random vecrors array
|
|||
/// </summary>
|
|||
/// <param name="arraySize">Number of vectors</param>
|
|||
/// <param name="vectorSize">Size of each vector</param>
|
|||
/// <returns>Array of random vectors</returns>
|
|||
private static Vector<Complex32>[] CreateVectorArray(int arraySize, int vectorSize) |
|||
{ |
|||
var result = new Vector<Complex32>[arraySize]; |
|||
for (var i = 0; i < result.Length; i++) |
|||
{ |
|||
result[i] = new DenseVector(vectorSize); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the true residual of the matrix equation Ax = b according to: residual = b - Ax
|
|||
/// </summary>
|
|||
/// <param name="matrix">Source <see cref="Matrix{T}"/>A.</param>
|
|||
/// <param name="residual">Residual <see cref="Vector{T}"/> data.</param>
|
|||
/// <param name="x">x <see cref="Vector{T}"/> data.</param>
|
|||
/// <param name="b">b <see cref="Vector{T}"/> data.</param>
|
|||
private static void CalculateTrueResidual(Matrix<Complex32> matrix, Vector<Complex32> residual, Vector<Complex32> x, Vector<Complex32> b) |
|||
{ |
|||
// -Ax = residual
|
|||
matrix.Multiply(x, residual); |
|||
residual.Multiply(-1, residual); |
|||
|
|||
// residual + b
|
|||
residual.Add(b, residual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determine if calculation should continue
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">Number of iterations passed</param>
|
|||
/// <param name="result">Result <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="source">Source <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="residuals">Residual <see cref="Vector{T}"/>.</param>
|
|||
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
|
|||
private bool ShouldContinue(int iterationNumber, Vector<Complex32> result, Vector<Complex32> source, Vector<Complex32> residuals) |
|||
{ |
|||
if (_hasBeenStopped) |
|||
{ |
|||
_iterator.IterationCancelled(); |
|||
return true; |
|||
} |
|||
|
|||
_iterator.DetermineStatus(iterationNumber, result, source, residuals); |
|||
var status = _iterator.Status; |
|||
|
|||
// We stop if either:
|
|||
// - the user has stopped the calculation
|
|||
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
|
|||
return (!status.TerminatesCalculation) && (!_hasBeenStopped); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution matrix, <c>B</c>.</param>
|
|||
/// <returns>The result matrix, <c>X</c>.</returns>
|
|||
public Matrix<Complex32> Solve(Matrix<Complex32> matrix, Matrix<Complex32> input) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount); |
|||
Solve(matrix, input, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution matrix, <c>B</c>.</param>
|
|||
/// <param name="result">The result matrix, <c>X</c></param>
|
|||
public void Solve(Matrix<Complex32> matrix, Matrix<Complex32> input, Matrix<Complex32> result) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (matrix.RowCount != input.RowCount || input.RowCount != result.RowCount || input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
for (var column = 0; column < input.ColumnCount; column++) |
|||
{ |
|||
var solution = Solve(matrix, input.Column(column)); |
|||
foreach (var element in solution.GetIndexedEnumerator()) |
|||
{ |
|||
result.At(element.Key, column, element.Value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,528 @@ |
|||
// <copyright file="TFQMR.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Iterative |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Solvers; |
|||
using Generic.Solvers.Preconditioners; |
|||
using Generic.Solvers.Status; |
|||
using Numerics; |
|||
using Preconditioners; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// A Transpose Free Quasi-Minimal Residual (TFQMR) iterative matrix solver.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The TFQMR algorithm was taken from: <br/>
|
|||
/// Iterative methods for sparse linear systems.
|
|||
/// <br/>
|
|||
/// Yousef Saad
|
|||
/// <br/>
|
|||
/// Algorithm is described in Chapter 7, section 7.4.3, page 219
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The example code below provides an indication of the possible use of the
|
|||
/// solver.
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
public sealed class TFQMR : IIterativeSolver<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The status used if there is no status, i.e. the solver hasn't run yet and there is no
|
|||
/// iterator.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus DefaultStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// The preconditioner that will be used. Can be set to <see langword="null" />, in which case the default
|
|||
/// pre-conditioner will be used.
|
|||
/// </summary>
|
|||
private IPreConditioner<Complex32> _preconditioner; |
|||
|
|||
/// <summary>
|
|||
/// The iterative process controller.
|
|||
/// </summary>
|
|||
private IIterator<Complex32> _iterator; |
|||
|
|||
/// <summary>
|
|||
/// Indicates if the user has stopped the solver.
|
|||
/// </summary>
|
|||
private bool _hasBeenStopped; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TFQMR"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// When using this constructor the solver will use the <see cref="IIterator{T}"/> with
|
|||
/// the standard settings and a default preconditioner.
|
|||
/// </remarks>
|
|||
public TFQMR() : this(null, null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TFQMR"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// When using this constructor the solver will use a default preconditioner.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// The main advantages of using a user defined <see cref="IIterator{T}"/> are:
|
|||
/// <list type="number">
|
|||
/// <item>It is possible to set the desired convergence limits.</item>
|
|||
/// <item>
|
|||
/// It is possible to check the reason for which the solver finished
|
|||
/// the iterative procedure by calling the <see cref="IIterator{T}.Status"/> property.
|
|||
/// </item>
|
|||
/// </list>
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <param name="iterator">The <see cref="IIterator{T}"/> that will be used to monitor the iterative process.</param>
|
|||
public TFQMR(IIterator<Complex32> iterator) : this(null, iterator) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TFQMR"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// When using this constructor the solver will use the <see cref="IIterator{T}"/> with
|
|||
/// the standard settings.
|
|||
/// </remarks>
|
|||
/// <param name="preconditioner">The <see cref="IPreConditioner{T}"/> that will be used to precondition the matrix equation.</param>
|
|||
public TFQMR(IPreConditioner<Complex32> preconditioner) : this(preconditioner, null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TFQMR"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The main advantages of using a user defined <see cref="IIterator{T}"/> are:
|
|||
/// <list type="number">
|
|||
/// <item>It is possible to set the desired convergence limits.</item>
|
|||
/// <item>
|
|||
/// It is possible to check the reason for which the solver finished
|
|||
/// the iterative procedure by calling the <see cref="IIterator{T}.Status"/> property.
|
|||
/// </item>
|
|||
/// </list>
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <param name="preconditioner">The <see cref="IPreConditioner{T}"/> that will be used to precondition the matrix equation.</param>
|
|||
/// <param name="iterator">The <see cref="IIterator{T}"/> that will be used to monitor the iterative process.</param>
|
|||
public TFQMR(IPreConditioner<Complex32> preconditioner, IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
_preconditioner = preconditioner; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the <see cref="IPreConditioner{T}"/> that will be used to precondition the iterative process.
|
|||
/// </summary>
|
|||
/// <param name="preconditioner">The preconditioner.</param>
|
|||
public void SetPreconditioner(IPreConditioner<Complex32> preconditioner) |
|||
{ |
|||
_preconditioner = preconditioner; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the <see cref="IIterator{T}"/> that will be used to track the iterative process.
|
|||
/// </summary>
|
|||
/// <param name="iterator">The iterator.</param>
|
|||
public void SetIterator(IIterator<Complex32> iterator) |
|||
{ |
|||
_iterator = iterator; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the status of the iteration once the calculation is finished.
|
|||
/// </summary>
|
|||
public ICalculationStatus IterationResult |
|||
{ |
|||
get |
|||
{ |
|||
return (_iterator != null) ? _iterator.Status : DefaultStatus; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Stops the solve process.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
|
|||
/// </remarks>
|
|||
public void StopSolve() |
|||
{ |
|||
_hasBeenStopped = true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="vector">The solution vector, <c>b</c>.</param>
|
|||
/// <returns>The result vector, <c>x</c>.</returns>
|
|||
public Vector<Complex32> Solve(Matrix<Complex32> matrix, Vector<Complex32> vector) |
|||
{ |
|||
if (vector == null) |
|||
{ |
|||
throw new ArgumentNullException(); |
|||
} |
|||
|
|||
Vector<Complex32> result = new DenseVector(matrix.RowCount); |
|||
Solve(matrix, vector, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
|
|||
/// solution vector and x is the unknown vector.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution vector, <c>b</c></param>
|
|||
/// <param name="result">The result vector, <c>x</c></param>
|
|||
public void Solve(Matrix<Complex32> matrix, Vector<Complex32> input, Vector<Complex32> result) |
|||
{ |
|||
// If we were stopped before, we are no longer
|
|||
// We're doing this at the start of the method to ensure
|
|||
// that we can use these fields immediately.
|
|||
_hasBeenStopped = false; |
|||
|
|||
// Error checks
|
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (result.Count != input.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Initialize the solver fields
|
|||
// Set the convergence monitor
|
|||
if (_iterator == null) |
|||
{ |
|||
_iterator = Iterator.CreateDefault(); |
|||
} |
|||
|
|||
if (_preconditioner == null) |
|||
{ |
|||
_preconditioner = new UnitPreconditioner(); |
|||
} |
|||
|
|||
_preconditioner.Initialize(matrix); |
|||
|
|||
var d = new DenseVector(input.Count); |
|||
var r = new DenseVector(input); |
|||
|
|||
var uodd = new DenseVector(input.Count); |
|||
var ueven = new DenseVector(input.Count); |
|||
|
|||
var v = new DenseVector(input.Count); |
|||
var pseudoResiduals = new DenseVector(input); |
|||
|
|||
var x = new DenseVector(input.Count); |
|||
var yodd = new DenseVector(input.Count); |
|||
var yeven = new DenseVector(input); |
|||
|
|||
// Temp vectors
|
|||
var temp = new DenseVector(input.Count); |
|||
|
|||
// Initialize
|
|||
var startNorm = input.Norm(2); |
|||
|
|||
// Define the scalars
|
|||
Complex32 alpha = 0; |
|||
Complex32 eta = 0; |
|||
float theta = 0; |
|||
|
|||
var tau = (float)startNorm; |
|||
Complex32 rho = tau * tau; |
|||
|
|||
// Calculate the initial values for v
|
|||
// M temp = yEven
|
|||
_preconditioner.Approximate(yeven, temp); |
|||
|
|||
// v = A temp
|
|||
matrix.Multiply(temp, v); |
|||
|
|||
// Set uOdd
|
|||
v.CopyTo(ueven); |
|||
|
|||
// Start the iteration
|
|||
var iterationNumber = 0; |
|||
while (ShouldContinue(iterationNumber, result, input, pseudoResiduals)) |
|||
{ |
|||
// First part of the step, the even bit
|
|||
if (IsEven(iterationNumber)) |
|||
{ |
|||
// sigma = (v, r)
|
|||
var sigma = v.DotProduct(r.Conjugate()); |
|||
if (sigma.Real.AlmostEqual(0, 1) && sigma.Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
// FAIL HERE
|
|||
_iterator.IterationCancelled(); |
|||
break; |
|||
} |
|||
|
|||
// alpha = rho / sigma
|
|||
alpha = rho / sigma; |
|||
|
|||
// yOdd = yEven - alpha * v
|
|||
yeven.Add(v.Multiply(-alpha), yodd); |
|||
|
|||
// Solve M temp = yOdd
|
|||
_preconditioner.Approximate(yodd, temp); |
|||
|
|||
// uOdd = A temp
|
|||
matrix.Multiply(temp, uodd); |
|||
} |
|||
|
|||
// The intermediate step which is equal for both even and
|
|||
// odd iteration steps.
|
|||
// Select the correct vector
|
|||
var uinternal = IsEven(iterationNumber) ? ueven : uodd; |
|||
var yinternal = IsEven(iterationNumber) ? yeven : yodd; |
|||
|
|||
// pseudoResiduals = pseudoResiduals - alpha * uOdd
|
|||
pseudoResiduals.Add(uinternal.Multiply(-alpha), pseudoResiduals); |
|||
|
|||
// d = yOdd + theta * theta * eta / alpha * d
|
|||
d.Multiply(theta * theta * eta / alpha, temp); |
|||
yinternal.Add(temp, d); |
|||
|
|||
// theta = ||pseudoResiduals||_2 / tau
|
|||
theta = (float)pseudoResiduals.Norm(2) / tau; |
|||
var c = 1 / (float)Math.Sqrt(1 + (theta * theta)); |
|||
|
|||
// tau = tau * theta * c
|
|||
tau *= theta * c; |
|||
|
|||
// eta = c^2 * alpha
|
|||
eta = c * c * alpha; |
|||
|
|||
// x = x + eta * d
|
|||
x.Add(d.Multiply(eta), x); |
|||
|
|||
// Check convergence and see if we can bail
|
|||
if (!ShouldContinue(iterationNumber, result, input, pseudoResiduals)) |
|||
{ |
|||
// Calculate the real values
|
|||
_preconditioner.Approximate(x, result); |
|||
|
|||
// Calculate the true residual. Use the temp vector for that
|
|||
// so that we don't pollute the pseudoResidual vector for no
|
|||
// good reason.
|
|||
CalculateTrueResidual(matrix, temp, result, input); |
|||
|
|||
// Now recheck the convergence
|
|||
if (!ShouldContinue(iterationNumber, result, input, temp)) |
|||
{ |
|||
// We're all good now.
|
|||
return; |
|||
} |
|||
} |
|||
|
|||
// The odd step
|
|||
if (!IsEven(iterationNumber)) |
|||
{ |
|||
if (rho.Real.AlmostEqual(0, 1) && rho.Imaginary.AlmostEqual(0, 1)) |
|||
{ |
|||
// FAIL HERE
|
|||
_iterator.IterationCancelled(); |
|||
break; |
|||
} |
|||
|
|||
var rhoNew = pseudoResiduals.DotProduct(r.Conjugate()); |
|||
var beta = rhoNew / rho; |
|||
|
|||
// Update rho for the next loop
|
|||
rho = rhoNew; |
|||
|
|||
// yOdd = pseudoResiduals + beta * yOdd
|
|||
pseudoResiduals.Add(yodd.Multiply(beta), yeven); |
|||
|
|||
// Solve M temp = yOdd
|
|||
_preconditioner.Approximate(yeven, temp); |
|||
|
|||
// uOdd = A temp
|
|||
matrix.Multiply(temp, ueven); |
|||
|
|||
// v = uEven + beta * (uOdd + beta * v)
|
|||
uodd.Add(v.Multiply(beta), temp); |
|||
ueven.Add(temp.Multiply(beta), v); |
|||
} |
|||
|
|||
// Calculate the real values
|
|||
_preconditioner.Approximate(x, result); |
|||
|
|||
iterationNumber++; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the true residual of the matrix equation Ax = b according to: residual = b - Ax
|
|||
/// </summary>
|
|||
/// <param name="matrix">Instance of the <see cref="Matrix{T}"/> A.</param>
|
|||
/// <param name="residual">Residual values in <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="x">Instance of the <see cref="Vector{T}"/> x.</param>
|
|||
/// <param name="b">Instance of the <see cref="Vector{T}"/> b.</param>
|
|||
private static void CalculateTrueResidual(Matrix<Complex32> matrix, Vector<Complex32> residual, Vector<Complex32> x, Vector<Complex32> b) |
|||
{ |
|||
// -Ax = residual
|
|||
matrix.Multiply(x, residual); |
|||
residual.Multiply(-1, residual); |
|||
|
|||
// residual + b
|
|||
residual.Add(b, residual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determine if calculation should continue
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">Number of iterations passed</param>
|
|||
/// <param name="result">Result <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="source">Source <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="residuals">Residual <see cref="Vector{T}"/>.</param>
|
|||
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
|
|||
private bool ShouldContinue(int iterationNumber, Vector<Complex32> result, Vector<Complex32> source, Vector<Complex32> residuals) |
|||
{ |
|||
if (_hasBeenStopped) |
|||
{ |
|||
_iterator.IterationCancelled(); |
|||
return true; |
|||
} |
|||
|
|||
_iterator.DetermineStatus(iterationNumber, result, source, residuals); |
|||
var status = _iterator.Status; |
|||
|
|||
// We stop if either:
|
|||
// - the user has stopped the calculation
|
|||
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
|
|||
return (!status.TerminatesCalculation) && (!_hasBeenStopped); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Is <paramref name="number"/> even?
|
|||
/// </summary>
|
|||
/// <param name="number">Number to check</param>
|
|||
/// <returns><c>true</c> if <paramref name="number"/> even, otherwise <c>false</c></returns>
|
|||
private static bool IsEven(int number) |
|||
{ |
|||
return number % 2 == 0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution matrix, <c>B</c>.</param>
|
|||
/// <returns>The result matrix, <c>X</c>.</returns>
|
|||
public Matrix<Complex32> Solve(Matrix<Complex32> matrix, Matrix<Complex32> input) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount); |
|||
Solve(matrix, input, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
|
|||
/// solution matrix and X is the unknown matrix.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
|
|||
/// <param name="input">The solution matrix, <c>B</c>.</param>
|
|||
/// <param name="result">The result matrix, <c>X</c></param>
|
|||
public void Solve(Matrix<Complex32> matrix, Matrix<Complex32> input, Matrix<Complex32> result) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (input == null) |
|||
{ |
|||
throw new ArgumentNullException("input"); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
throw new ArgumentNullException("result"); |
|||
} |
|||
|
|||
if (matrix.RowCount != input.RowCount || input.RowCount != result.RowCount || input.ColumnCount != result.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
for (var column = 0; column < input.ColumnCount; column++) |
|||
{ |
|||
var solution = Solve(matrix, input.Column(column)); |
|||
foreach (var element in solution.GetIndexedEnumerator()) |
|||
{ |
|||
result.At(element.Key, column, element.Value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,329 @@ |
|||
// <copyright file="Iterator.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Generic; |
|||
using Generic.Solvers; |
|||
using Generic.Solvers.Status; |
|||
using Generic.Solvers.StopCriterium; |
|||
using Numerics; |
|||
using Properties; |
|||
using StopCriterium; |
|||
|
|||
/// <summary>
|
|||
/// An iterator that is used to check if an iterative calculation should continue or stop.
|
|||
/// </summary>
|
|||
public sealed class Iterator : IIterator<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The default status for the iterator.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus DefaultStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// Creates a default iterator with all the <see cref="IIterationStopCriterium{T}"/> objects.
|
|||
/// </summary>
|
|||
/// <returns>A new <see cref="IIterator{T}"/> object.</returns>
|
|||
public static IIterator<Complex32> CreateDefault() |
|||
{ |
|||
var iterator = new Iterator(); |
|||
iterator.Add(new FailureStopCriterium()); |
|||
iterator.Add(new DivergenceStopCriterium()); |
|||
iterator.Add(new IterationCountStopCriterium()); |
|||
iterator.Add(new ResidualStopCriterium()); |
|||
|
|||
return iterator; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The collection that holds all the stop criteria and the flag indicating if they should be added
|
|||
/// to the child iterators.
|
|||
/// </summary>
|
|||
private readonly Dictionary<Type, IIterationStopCriterium<Complex32>> _stopCriterias = new Dictionary<Type, IIterationStopCriterium<Complex32>>(); |
|||
|
|||
/// <summary>
|
|||
/// The status of the iterator.
|
|||
/// </summary>
|
|||
private ICalculationStatus _status = DefaultStatus; |
|||
|
|||
/// <summary>
|
|||
/// Indicates if the iteration was cancelled.
|
|||
/// </summary>
|
|||
private bool _wasIterationCancelled; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Iterator"/> class.
|
|||
/// </summary>
|
|||
public Iterator() : this(null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Iterator"/> class with the specified stop criteria.
|
|||
/// </summary>
|
|||
/// <param name="stopCriteria">
|
|||
/// The specified stop criteria. Only one stop criterium of each type can be passed in. None
|
|||
/// of the stop criteria will be passed on to child iterators.
|
|||
/// </param>
|
|||
/// <exception cref="ArgumentException">Thrown if <paramref name="stopCriteria"/> contains multiple stop criteria of the same type.</exception>
|
|||
public Iterator(IEnumerable<IIterationStopCriterium<Complex32>> stopCriteria) |
|||
{ |
|||
// Add the stop criteria
|
|||
if (stopCriteria == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var stopCriterium in stopCriteria.Where(stopCriterium => stopCriterium != null)) |
|||
{ |
|||
Add(stopCriterium); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds an <see cref="IIterationStopCriterium{T}"/> to the internal collection of stop-criteria. Only a
|
|||
/// single stop criterium of each type can be stored.
|
|||
/// </summary>
|
|||
/// <param name="stopCriterium">The stop criterium to add.</param>
|
|||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="stopCriterium"/> is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// Thrown if <paramref name="stopCriterium"/> is of the same type as an already
|
|||
/// stored criterium.
|
|||
/// </exception>
|
|||
public void Add(IIterationStopCriterium<Complex32> stopCriterium) |
|||
{ |
|||
if (stopCriterium == null) |
|||
{ |
|||
throw new ArgumentNullException("stopCriterium"); |
|||
} |
|||
|
|||
if (_stopCriterias.ContainsKey(stopCriterium.GetType())) |
|||
{ |
|||
throw new ArgumentException(Resources.StopCriteriumDuplicate); |
|||
} |
|||
|
|||
// Store the stop criterium.
|
|||
_stopCriterias.Add(stopCriterium.GetType(), stopCriterium); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the <see cref="IIterationStopCriterium{T}"/> from the internal collection.
|
|||
/// </summary>
|
|||
/// <param name="stopCriterium">The stop criterium that must be removed.</param>
|
|||
public void Remove(IIterationStopCriterium<Complex32> stopCriterium) |
|||
{ |
|||
if (stopCriterium == null) |
|||
{ |
|||
throw new ArgumentNullException("stopCriterium"); |
|||
} |
|||
|
|||
if (!_stopCriterias.ContainsKey(stopCriterium.GetType())) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
// Remove from the collection
|
|||
_stopCriterias.Remove(stopCriterium.GetType()); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Indicates if the specific stop criterium is stored by the <see cref="IIterator{T}"/>.
|
|||
/// </summary>
|
|||
/// <param name="stopCriterium">The stop criterium.</param>
|
|||
/// <returns><c>true</c> if the <see cref="IIterator{T}"/> contains the stop criterium; otherwise <c>false</c>.</returns>
|
|||
public bool Contains(IIterationStopCriterium<Complex32> stopCriterium) |
|||
{ |
|||
return stopCriterium != null && _stopCriterias.ContainsKey(stopCriterium.GetType()); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the number of stored stop criteria.
|
|||
/// </summary>
|
|||
/// <remarks>Used for testing only.</remarks>
|
|||
internal int NumberOfCriteria |
|||
{ |
|||
get |
|||
{ |
|||
return _stopCriterias.Count; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an <c>IEnumerator</c> that enumerates over all the stored stop criteria.
|
|||
/// </summary>
|
|||
/// <remarks>Used for testing only.</remarks>
|
|||
internal IEnumerator<IIterationStopCriterium<Complex32>> StoredStopCriteria |
|||
{ |
|||
get |
|||
{ |
|||
return _stopCriterias.Select(criterium => criterium.Value).GetEnumerator(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Indicates to the iterator that the iterative process has been cancelled.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Does not reset the stop-criteria.
|
|||
/// </remarks>
|
|||
public void IterationCancelled() |
|||
{ |
|||
_wasIterationCancelled = true; |
|||
_status = new CalculationCancelled(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determines the status of the iterative calculation based on the stop criteria stored
|
|||
/// by the current <c>IIterator</c>. Result is set into <c>Status</c> field.
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">The number of iterations that have passed so far.</param>
|
|||
/// <param name="solutionVector">The vector containing the current solution values.</param>
|
|||
/// <param name="sourceVector">The right hand side vector.</param>
|
|||
/// <param name="residualVector">The vector containing the current residual vectors.</param>
|
|||
/// <remarks>
|
|||
/// The individual iterators may internally track the progress of the calculation based
|
|||
/// on the invocation of this method. Therefore this method should only be called if the
|
|||
/// calculation has moved forwards at least one step.
|
|||
/// </remarks>
|
|||
public void DetermineStatus(int iterationNumber, Vector<Complex32> solutionVector, Vector<Complex32> sourceVector, Vector<Complex32> residualVector) |
|||
{ |
|||
if (_stopCriterias.Count == 0) |
|||
{ |
|||
throw new ArgumentException(Resources.StopCriteriumMissing); |
|||
} |
|||
|
|||
if (iterationNumber < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("iterationNumber"); |
|||
} |
|||
|
|||
if (solutionVector == null) |
|||
{ |
|||
throw new ArgumentNullException("solutionVector"); |
|||
} |
|||
|
|||
if (sourceVector == null) |
|||
{ |
|||
throw new ArgumentNullException("sourceVector"); |
|||
} |
|||
|
|||
if (residualVector == null) |
|||
{ |
|||
throw new ArgumentNullException("residualVector"); |
|||
} |
|||
|
|||
// While we're cancelled we don't call on the stop-criteria.
|
|||
if (_wasIterationCancelled) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var stopCriterium in _stopCriterias.Select(pair => pair.Value)) |
|||
{ |
|||
stopCriterium.DetermineStatus(iterationNumber, solutionVector, sourceVector, residualVector); |
|||
var status = stopCriterium.Status; |
|||
|
|||
// Check if the status is:
|
|||
// - Running --> keep going
|
|||
// - Indetermined --> keep going
|
|||
// Anything else:
|
|||
// Stop looping and set that status
|
|||
if ((status is CalculationRunning) || (status is CalculationIndetermined)) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
_status = status; |
|||
return; |
|||
} |
|||
|
|||
// Got all the way through
|
|||
// So we're running because we had vectors passed to us.
|
|||
if (!(_status is CalculationRunning)) |
|||
{ |
|||
_status = new CalculationRunning(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the current calculation status.
|
|||
/// </summary>
|
|||
public ICalculationStatus Status |
|||
{ |
|||
get |
|||
{ |
|||
return _status; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Resets the <see cref="IIterator{T}"/> to the pre-calculation state.
|
|||
/// </summary>
|
|||
public void ResetToPrecalculationState() |
|||
{ |
|||
// Indicate that we're no longer cancelled.
|
|||
_wasIterationCancelled = false; |
|||
|
|||
// Reset the status.
|
|||
_status = DefaultStatus; |
|||
|
|||
// Reset the stop-criteria
|
|||
foreach (var stopCriterium in _stopCriterias.Select(pair => pair.Value)) |
|||
{ |
|||
stopCriterium.ResetToPrecalculationState(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a deep clone of the current iterator.
|
|||
/// </summary>
|
|||
/// <returns>The deep clone of the current iterator.</returns>
|
|||
public IIterator<Complex32> Clone() |
|||
{ |
|||
var stopCriteria = _stopCriterias.Select(pair => pair.Value).Select(stopCriterium => (IIterationStopCriterium<Complex32>)stopCriterium.Clone()).ToList(); |
|||
return new Iterator(stopCriteria); |
|||
} |
|||
|
|||
#if !SILVERLIGHT
|
|||
/// <summary>
|
|||
/// Creates a deep clone of the current iterator.
|
|||
/// </summary>
|
|||
/// <returns>The deep clone of the current iterator.</returns>
|
|||
object ICloneable.Clone() |
|||
{ |
|||
return Clone(); |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|||
@ -0,0 +1,151 @@ |
|||
// <copyright file="Diagonal.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Solvers.Preconditioners; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// A diagonal preconditioner. The preconditioner uses the inverse
|
|||
/// of the matrix diagonal as preconditioning values.
|
|||
/// </summary>
|
|||
public sealed class Diagonal : IPreConditioner<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The inverse of the matrix diagonal.
|
|||
/// </summary>
|
|||
private Complex32[] _inverseDiagonals; |
|||
|
|||
/// <summary>
|
|||
/// Returns the decomposed matrix diagonal.
|
|||
/// </summary>
|
|||
/// <returns>The matrix diagonal.</returns>
|
|||
internal DiagonalMatrix DiagonalEntries() |
|||
{ |
|||
var result = new DiagonalMatrix(_inverseDiagonals.Length); |
|||
for (var i = 0; i < _inverseDiagonals.Length; i++) |
|||
{ |
|||
result[i, i] = 1 / _inverseDiagonals[i]; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes the preconditioner and loads the internal data structures.
|
|||
/// </summary>
|
|||
/// <param name="matrix">
|
|||
/// The <see cref="Matrix{T}"/> upon which this preconditioner is based.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <see langword="null" />. </exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
|
|||
public void Initialize(Matrix<Complex32> matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); |
|||
} |
|||
|
|||
_inverseDiagonals = new Complex32[matrix.RowCount]; |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
_inverseDiagonals[i] = 1 / matrix[i, i]; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Approximates the solution to the matrix equation <b>Ax = b</b>.
|
|||
/// </summary>
|
|||
/// <param name="rhs">The right hand side vector.</param>
|
|||
/// <returns>The left hand side vector.</returns>
|
|||
public Vector<Complex32> Approximate(Vector<Complex32> rhs) |
|||
{ |
|||
if (rhs == null) |
|||
{ |
|||
throw new ArgumentNullException("rhs"); |
|||
} |
|||
|
|||
if (_inverseDiagonals == null) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDoesNotExist); |
|||
} |
|||
|
|||
if (rhs.Count != _inverseDiagonals.Length) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rhs"); |
|||
} |
|||
|
|||
Vector<Complex32> result = new DenseVector(rhs.Count); |
|||
Approximate(rhs, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Approximates the solution to the matrix equation <b>Ax = b</b>.
|
|||
/// </summary>
|
|||
/// <param name="rhs">The right hand side vector.</param>
|
|||
/// <param name="lhs">The left hand side vector. Also known as the result vector.</param>
|
|||
public void Approximate(Vector<Complex32> rhs, Vector<Complex32> lhs) |
|||
{ |
|||
if (rhs == null) |
|||
{ |
|||
throw new ArgumentNullException("rhs"); |
|||
} |
|||
|
|||
if (lhs == null) |
|||
{ |
|||
throw new ArgumentNullException("lhs"); |
|||
} |
|||
|
|||
if (_inverseDiagonals == null) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDoesNotExist); |
|||
} |
|||
|
|||
if ((lhs.Count != rhs.Count) || (lhs.Count != _inverseDiagonals.Length)) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rhs"); |
|||
} |
|||
|
|||
for (var i = 0; i < _inverseDiagonals.Length; i++) |
|||
{ |
|||
lhs[i] = rhs[i] * _inverseDiagonals[i]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,730 @@ |
|||
// <copyright file="Ilutp.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Generic; |
|||
using Generic.Solvers.Preconditioners; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// This class performs an Incomplete LU factorization with drop tolerance
|
|||
/// and partial pivoting. The drop tolerance indicates which additional entries
|
|||
/// will be dropped from the factorized LU matrices.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The ILUTP-Mem algorithm was taken from: <br/>
|
|||
/// ILUTP_Mem: a Space-Efficient Incomplete LU Preconditioner
|
|||
/// <br/>
|
|||
/// Tzu-Yi Chen, Department of Mathematics and Computer Science, <br/>
|
|||
/// Pomona College, Claremont CA 91711, USA <br/>
|
|||
/// Published in: <br/>
|
|||
/// Lecture Notes in Computer Science <br/>
|
|||
/// Volume 3046 / 2004 <br/>
|
|||
/// pp. 20 - 28 <br/>
|
|||
/// Algorithm is described in Section 2, page 22
|
|||
/// </remarks>
|
|||
public sealed class Ilutp : IPreConditioner<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The default fill level.
|
|||
/// </summary>
|
|||
public const double DefaultFillLevel = 200.0; |
|||
|
|||
/// <summary>
|
|||
/// The default drop tolerance.
|
|||
/// </summary>
|
|||
public const double DefaultDropTolerance = 0.0001; |
|||
|
|||
/// <summary>
|
|||
/// The decomposed upper triangular matrix.
|
|||
/// </summary>
|
|||
private SparseMatrix _upper; |
|||
|
|||
/// <summary>
|
|||
/// The decomposed lower triangular matrix.
|
|||
/// </summary>
|
|||
private SparseMatrix _lower; |
|||
|
|||
/// <summary>
|
|||
/// The array containing the pivot values.
|
|||
/// </summary>
|
|||
private int[] _pivots; |
|||
|
|||
/// <summary>
|
|||
/// The fill level.
|
|||
/// </summary>
|
|||
private double _fillLevel = DefaultFillLevel; |
|||
|
|||
/// <summary>
|
|||
/// The drop tolerance.
|
|||
/// </summary>
|
|||
private double _dropTolerance = DefaultDropTolerance; |
|||
|
|||
/// <summary>
|
|||
/// The pivot tolerance.
|
|||
/// </summary>
|
|||
private double _pivotTolerance; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Ilutp"/> class with the default settings.
|
|||
/// </summary>
|
|||
public Ilutp() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Ilutp"/> class with the specified settings.
|
|||
/// </summary>
|
|||
/// <param name="fillLevel">
|
|||
/// The amount of fill that is allowed in the matrix. The value is a fraction of
|
|||
/// the number of non-zero entries in the original matrix. Values should be positive.
|
|||
/// </param>
|
|||
/// <param name="dropTolerance">
|
|||
/// The absolute drop tolerance which indicates below what absolute value an entry
|
|||
/// will be dropped from the matrix. A drop tolerance of 0.0 means that no values
|
|||
/// will be dropped. Values should always be positive.
|
|||
/// </param>
|
|||
/// <param name="pivotTolerance">
|
|||
/// The pivot tolerance which indicates at what level pivoting will take place. A
|
|||
/// value of 0.0 means that no pivoting will take place.
|
|||
/// </param>
|
|||
public Ilutp(double fillLevel, double dropTolerance, double pivotTolerance) |
|||
{ |
|||
if (fillLevel < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("fillLevel"); |
|||
} |
|||
|
|||
if (dropTolerance < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("dropTolerance"); |
|||
} |
|||
|
|||
if (pivotTolerance < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("pivotTolerance"); |
|||
} |
|||
|
|||
_fillLevel = fillLevel; |
|||
_dropTolerance = dropTolerance; |
|||
_pivotTolerance = pivotTolerance; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the amount of fill that is allowed in the matrix. The
|
|||
/// value is a fraction of the number of non-zero entries in the original
|
|||
/// matrix. The standard value is 200.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// Values should always be positive and can be higher than 1.0. A value lower
|
|||
/// than 1.0 means that the eventual preconditioner matrix will have fewer
|
|||
/// non-zero entries as the original matrix. A value higher than 1.0 means that
|
|||
/// the eventual preconditioner can have more non-zero values than the original
|
|||
/// matrix.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// Note that any changes to the <b>FillLevel</b> after creating the preconditioner
|
|||
/// will invalidate the created preconditioner and will require a re-initialization of
|
|||
/// the preconditioner.
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <exception cref="ArgumentOutOfRangeException">Thrown if a negative value is provided.</exception>
|
|||
public double FillLevel |
|||
{ |
|||
get |
|||
{ |
|||
return _fillLevel; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
if (value < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("Value"); |
|||
} |
|||
|
|||
_fillLevel = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the absolute drop tolerance which indicates below what absolute value
|
|||
/// an entry will be dropped from the matrix. The standard value is 0.0001.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The values should always be positive and can be larger than 1.0. A low value will
|
|||
/// keep more small numbers in the preconditioner matrix. A high value will remove
|
|||
/// more small numbers from the preconditioner matrix.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// Note that any changes to the <b>DropTolerance</b> after creating the preconditioner
|
|||
/// will invalidate the created preconditioner and will require a re-initialization of
|
|||
/// the preconditioner.
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <exception cref="ArgumentOutOfRangeException">Thrown if a negative value is provided.</exception>
|
|||
public double DropTolerance |
|||
{ |
|||
get |
|||
{ |
|||
return _dropTolerance; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
if (value < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("Value"); |
|||
} |
|||
|
|||
_dropTolerance = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the pivot tolerance which indicates at what level pivoting will
|
|||
/// take place. The standard value is 0.0 which means pivoting will never take place.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// The pivot tolerance is used to calculate if pivoting is necessary. Pivoting
|
|||
/// will take place if any of the values in a row is bigger than the
|
|||
/// diagonal value of that row divided by the pivot tolerance, i.e. pivoting
|
|||
/// will take place if <b>row(i,j) > row(i,i) / PivotTolerance</b> for
|
|||
/// any <b>j</b> that is not equal to <b>i</b>.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// Note that any changes to the <b>PivotTolerance</b> after creating the preconditioner
|
|||
/// will invalidate the created preconditioner and will require a re-initialization of
|
|||
/// the preconditioner.
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
/// <exception cref="ArgumentOutOfRangeException">Thrown if a negative value is provided.</exception>
|
|||
public double PivotTolerance |
|||
{ |
|||
get |
|||
{ |
|||
return _pivotTolerance; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
if (value < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("Value"); |
|||
} |
|||
|
|||
_pivotTolerance = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the upper triagonal matrix that was created during the LU decomposition.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This method is used for debugging purposes only and should normally not be used.
|
|||
/// </remarks>
|
|||
/// <returns>A new matrix containing the upper triagonal elements.</returns>
|
|||
internal Matrix<Complex32> UpperTriangle() |
|||
{ |
|||
return _upper.Clone(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the lower triagonal matrix that was created during the LU decomposition.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This method is used for debugging purposes only and should normally not be used.
|
|||
/// </remarks>
|
|||
/// <returns>A new matrix containing the lower triagonal elements.</returns>
|
|||
internal Matrix<Complex32> LowerTriangle() |
|||
{ |
|||
return _lower.Clone(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the pivot array. This array is not needed for normal use because
|
|||
/// the preconditioner will return the solution vector values in the proper order.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This method is used for debugging purposes only and should normally not be used.
|
|||
/// </remarks>
|
|||
/// <returns>The pivot array.</returns>
|
|||
internal int[] Pivots() |
|||
{ |
|||
var result = new int[_pivots.Length]; |
|||
for (var i = 0; i < _pivots.Length; i++) |
|||
{ |
|||
result[i] = _pivots[i]; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes the preconditioner and loads the internal data structures.
|
|||
/// </summary>
|
|||
/// <param name="matrix">
|
|||
/// The <see cref="Matrix{T}"/> upon which this preconditioner is based. Note that the
|
|||
/// method takes a general matrix type. However internally the data is stored
|
|||
/// as a sparse matrix. Therefore it is not recommended to pass a dense matrix.
|
|||
/// </param>
|
|||
/// <exception cref="ArgumentNullException"> If <paramref name="matrix"/> is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
|
|||
public void Initialize(Matrix<Complex32> matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); |
|||
} |
|||
|
|||
var sparseMatrix = (matrix is SparseMatrix) ? matrix as SparseMatrix : new SparseMatrix(matrix.ToArray()); |
|||
|
|||
// The creation of the preconditioner follows the following algorithm.
|
|||
// spaceLeft = lfilNnz * nnz(A)
|
|||
// for i = 1, .. , n
|
|||
// {
|
|||
// w = a(i,*)
|
|||
// for j = 1, .. , i - 1
|
|||
// {
|
|||
// if (w(j) != 0)
|
|||
// {
|
|||
// w(j) = w(j) / a(j,j)
|
|||
// if (w(j) < dropTol)
|
|||
// {
|
|||
// w(j) = 0;
|
|||
// }
|
|||
// if (w(j) != 0)
|
|||
// {
|
|||
// w = w - w(j) * U(j,*)
|
|||
// }
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// for j = i, .. ,n
|
|||
// {
|
|||
// if w(j) <= dropTol * ||A(i,*)||
|
|||
// {
|
|||
// w(j) = 0
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// spaceRow = spaceLeft / (n - i + 1) // Determine the space for this row
|
|||
// lfil = spaceRow / 2 // space for this row of L
|
|||
// l(i,j) = w(j) for j = 1, .. , i -1 // only the largest lfil elements
|
|||
//
|
|||
// lfil = spaceRow - nnz(L(i,:)) // space for this row of U
|
|||
// u(i,j) = w(j) for j = i, .. , n // only the largest lfil - 1 elements
|
|||
// w = 0
|
|||
//
|
|||
// if max(U(i,i + 1: n)) > U(i,i) / pivTol then // pivot if necessary
|
|||
// {
|
|||
// pivot by swapping the max and the diagonal entries
|
|||
// Update L, U
|
|||
// Update P
|
|||
// }
|
|||
// spaceLeft = spaceLeft - nnz(L(i,:)) - nnz(U(i,:))
|
|||
// }
|
|||
// Create the lower triangular matrix
|
|||
_lower = new SparseMatrix(sparseMatrix.RowCount); |
|||
|
|||
// Create the upper triangular matrix and copy the values
|
|||
_upper = new SparseMatrix(sparseMatrix.RowCount); |
|||
|
|||
// Create the pivot array
|
|||
_pivots = new int[sparseMatrix.RowCount]; |
|||
for (var i = 0; i < _pivots.Length; i++) |
|||
{ |
|||
_pivots[i] = i; |
|||
} |
|||
|
|||
Vector<Complex32> workVector = new DenseVector(sparseMatrix.RowCount); |
|||
Vector<Complex32> rowVector = new DenseVector(sparseMatrix.ColumnCount); |
|||
var indexSorting = new int[sparseMatrix.RowCount]; |
|||
|
|||
// spaceLeft = lfilNnz * nnz(A)
|
|||
var spaceLeft = (int)_fillLevel * sparseMatrix.NonZerosCount; |
|||
|
|||
// for i = 1, .. , n
|
|||
for (var i = 0; i < sparseMatrix.RowCount; i++) |
|||
{ |
|||
// w = a(i,*)
|
|||
sparseMatrix.Row(i, workVector); |
|||
|
|||
// pivot the row
|
|||
PivotRow(workVector); |
|||
var vectorNorm = workVector.Norm(Double.PositiveInfinity); |
|||
|
|||
// for j = 1, .. , i - 1)
|
|||
for (var j = 0; j < i; j++) |
|||
{ |
|||
// if (w(j) != 0)
|
|||
// {
|
|||
// w(j) = w(j) / a(j,j)
|
|||
// if (w(j) < dropTol)
|
|||
// {
|
|||
// w(j) = 0;
|
|||
// }
|
|||
// if (w(j) != 0)
|
|||
// {
|
|||
// w = w - w(j) * U(j,*)
|
|||
// }
|
|||
if (workVector[j] != 0.0f) |
|||
{ |
|||
// Calculate the multiplication factors that go into the L matrix
|
|||
workVector[j] = workVector[j] / _upper[j, j]; |
|||
if (workVector[j].Magnitude < _dropTolerance) |
|||
{ |
|||
workVector[j] = 0.0f; |
|||
} |
|||
|
|||
// Calculate the addition factor
|
|||
if (workVector[j] != 0.0f) |
|||
{ |
|||
// vector update all in one go
|
|||
_upper.Row(j, rowVector); |
|||
|
|||
// zero out columnVector[k] because we don't need that
|
|||
// one anymore for k = 0 to k = j
|
|||
for (var k = 0; k <= j; k++) |
|||
{ |
|||
rowVector[k] = 0.0f; |
|||
} |
|||
|
|||
rowVector.Multiply(workVector[j], rowVector); |
|||
workVector.Subtract(rowVector, workVector); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// for j = i, .. ,n
|
|||
for (var j = i; j < sparseMatrix.RowCount; j++) |
|||
{ |
|||
// if w(j) <= dropTol * ||A(i,*)||
|
|||
// {
|
|||
// w(j) = 0
|
|||
// }
|
|||
if (workVector[j].Magnitude <= _dropTolerance * vectorNorm) |
|||
{ |
|||
workVector[j] = 0.0f; |
|||
} |
|||
} |
|||
|
|||
// spaceRow = spaceLeft / (n - i + 1) // Determine the space for this row
|
|||
var spaceRow = spaceLeft / (sparseMatrix.RowCount - i + 1); |
|||
|
|||
// lfil = spaceRow / 2 // space for this row of L
|
|||
var fillLevel = spaceRow / 2; |
|||
FindLargestItems(0, i - 1, indexSorting, workVector); |
|||
|
|||
// l(i,j) = w(j) for j = 1, .. , i -1 // only the largest lfil elements
|
|||
var lowerNonZeroCount = 0; |
|||
var count = 0; |
|||
for (var j = 0; j < i; j++) |
|||
{ |
|||
if ((count > fillLevel) || (indexSorting[j] == -1)) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
_lower[i, indexSorting[j]] = workVector[indexSorting[j]]; |
|||
count += 1; |
|||
lowerNonZeroCount += 1; |
|||
} |
|||
|
|||
FindLargestItems(i + 1, sparseMatrix.RowCount - 1, indexSorting, workVector); |
|||
|
|||
// lfil = spaceRow - nnz(L(i,:)) // space for this row of U
|
|||
fillLevel = spaceRow - lowerNonZeroCount; |
|||
|
|||
// u(i,j) = w(j) for j = i + 1, .. , n // only the largest lfil - 1 elements
|
|||
var upperNonZeroCount = 0; |
|||
count = 0; |
|||
for (var j = 0; j < sparseMatrix.RowCount - i; j++) |
|||
{ |
|||
if ((count > fillLevel - 1) || (indexSorting[j] == -1)) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
_upper[i, indexSorting[j]] = workVector[indexSorting[j]]; |
|||
count += 1; |
|||
upperNonZeroCount += 1; |
|||
} |
|||
|
|||
// Simply copy the diagonal element. Next step is to see if we pivot
|
|||
_upper[i, i] = workVector[i]; |
|||
|
|||
// if max(U(i,i + 1: n)) > U(i,i) / pivTol then // pivot if necessary
|
|||
// {
|
|||
// pivot by swapping the max and the diagonal entries
|
|||
// Update L, U
|
|||
// Update P
|
|||
// }
|
|||
|
|||
// Check if we really need to pivot. If (i+1) >=(mCoefficientMatrix.Rows -1) then
|
|||
// we are working on the last row. That means that there is only one number
|
|||
// And pivoting is useless. Also the indexSorting array will only contain
|
|||
// -1 values.
|
|||
if ((i + 1) < (sparseMatrix.RowCount - 1)) |
|||
{ |
|||
if (workVector[i].Magnitude < _pivotTolerance * workVector[indexSorting[0]].Magnitude) |
|||
{ |
|||
// swap columns of u (which holds the values of A in the
|
|||
// sections that haven't been partitioned yet.
|
|||
SwapColumns(_upper, i, indexSorting[0]); |
|||
|
|||
// Update P
|
|||
var temp = _pivots[i]; |
|||
_pivots[i] = _pivots[indexSorting[0]]; |
|||
_pivots[indexSorting[0]] = temp; |
|||
} |
|||
} |
|||
|
|||
// spaceLeft = spaceLeft - nnz(L(i,:)) - nnz(U(i,:))
|
|||
spaceLeft -= lowerNonZeroCount + upperNonZeroCount; |
|||
} |
|||
|
|||
for (var i = 0; i < _lower.RowCount; i++) |
|||
{ |
|||
_lower[i, i] = 1.0f; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pivot elements in the <paramref name="row"/> according to internal pivot array
|
|||
/// </summary>
|
|||
/// <param name="row">Row <see cref="Vector{T}"/> to pivot in</param>
|
|||
private void PivotRow(Vector<Complex32> row) |
|||
{ |
|||
var knownPivots = new Dictionary<int, int>(); |
|||
|
|||
// pivot the row
|
|||
for (var i = 0; i < row.Count; i++) |
|||
{ |
|||
if ((_pivots[i] != i) && (!PivotMapFound(knownPivots, i))) |
|||
{ |
|||
// store the pivots in the hashtable
|
|||
knownPivots.Add(_pivots[i], i); |
|||
|
|||
var t = row[i]; |
|||
row[i] = row[_pivots[i]]; |
|||
row[_pivots[i]] = t; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Was pivoting already performed
|
|||
/// </summary>
|
|||
/// <param name="knownPivots">Pivots already done</param>
|
|||
/// <param name="currentItem">Current item to pivot</param>
|
|||
/// <returns><c>true</c> if performed, otherwise <c>false</c></returns>
|
|||
private bool PivotMapFound(Dictionary<int, int> knownPivots, int currentItem) |
|||
{ |
|||
if (knownPivots.ContainsKey(_pivots[currentItem])) |
|||
{ |
|||
if (knownPivots[_pivots[currentItem]].Equals(currentItem)) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
if (knownPivots.ContainsKey(currentItem)) |
|||
{ |
|||
if (knownPivots[currentItem].Equals(_pivots[currentItem])) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Swap columns in the <see cref="Matrix{T}"/>
|
|||
/// </summary>
|
|||
/// <param name="matrix">Source <see cref="Matrix{T}"/>.</param>
|
|||
/// <param name="firstColumn">First column index to swap</param>
|
|||
/// <param name="secondColumn">Second column index to swap</param>
|
|||
private static void SwapColumns(Matrix<Complex32> matrix, int firstColumn, int secondColumn) |
|||
{ |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
var temp = matrix[i, firstColumn]; |
|||
matrix[i, firstColumn] = matrix[i, secondColumn]; |
|||
matrix[i, secondColumn] = temp; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sort vector descending, not changing vector but placing sorted indicies to <paramref name="sortedIndices"/>
|
|||
/// </summary>
|
|||
/// <param name="lowerBound">Start sort form</param>
|
|||
/// <param name="upperBound">Sort till upper bound</param>
|
|||
/// <param name="sortedIndices">Array with sorted vector indicies</param>
|
|||
/// <param name="values">Source <see cref="Vector{T}"/></param>
|
|||
private static void FindLargestItems(int lowerBound, int upperBound, int[] sortedIndices, Vector<Complex32> values) |
|||
{ |
|||
// Copy the indices for the values into the array
|
|||
for (var i = 0; i < upperBound + 1 - lowerBound; i++) |
|||
{ |
|||
sortedIndices[i] = lowerBound + i; |
|||
} |
|||
|
|||
for (var i = upperBound + 1 - lowerBound; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = -1; |
|||
} |
|||
|
|||
// Sort the first set of items.
|
|||
// Sorting starts at index 0 because the index array
|
|||
// starts at zero
|
|||
// and ends at index upperBound - lowerBound
|
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, upperBound - lowerBound, sortedIndices, values); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Approximates the solution to the matrix equation <b>Ax = b</b>.
|
|||
/// </summary>
|
|||
/// <param name="rhs">The right hand side vector.</param>
|
|||
/// <returns>The left hand side vector.</returns>
|
|||
public Vector<Complex32> Approximate(Vector<Complex32> rhs) |
|||
{ |
|||
if (rhs == null) |
|||
{ |
|||
throw new ArgumentNullException("rhs"); |
|||
} |
|||
|
|||
if (_upper == null) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDoesNotExist); |
|||
} |
|||
|
|||
if (rhs.Count != _upper.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rhs"); |
|||
} |
|||
|
|||
Vector<Complex32> result = new DenseVector(rhs.Count); |
|||
Approximate(rhs, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Approximates the solution to the matrix equation <b>Ax = b</b>.
|
|||
/// </summary>
|
|||
/// <param name="rhs">The right hand side vector.</param>
|
|||
/// <param name="lhs">The left hand side vector. Also known as the result vector.</param>
|
|||
public void Approximate(Vector<Complex32> rhs, Vector<Complex32> lhs) |
|||
{ |
|||
if (rhs == null) |
|||
{ |
|||
throw new ArgumentNullException("rhs"); |
|||
} |
|||
|
|||
if (lhs == null) |
|||
{ |
|||
throw new ArgumentNullException("lhs"); |
|||
} |
|||
|
|||
if (_upper == null) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDoesNotExist); |
|||
} |
|||
|
|||
if ((lhs.Count != rhs.Count) || (lhs.Count != _upper.RowCount)) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rhs"); |
|||
} |
|||
|
|||
// Solve equation here
|
|||
// Pivot(vector, result);
|
|||
// Solve L*Y = B(piv,:)
|
|||
Vector<Complex32> rowValues = new DenseVector(_lower.RowCount); |
|||
for (var i = 0; i < _lower.RowCount; i++) |
|||
{ |
|||
_lower.Row(i, rowValues); |
|||
|
|||
var sum = Complex32.Zero; |
|||
for (var j = 0; j < i; j++) |
|||
{ |
|||
sum += rowValues[j] * lhs[j]; |
|||
} |
|||
|
|||
lhs[i] = rhs[i] - sum; |
|||
} |
|||
|
|||
// Solve U*X = Y;
|
|||
for (var i = _upper.RowCount - 1; i > -1; i--) |
|||
{ |
|||
_upper.Row(i, rowValues); |
|||
|
|||
var sum = Complex32.Zero; |
|||
for (var j = _upper.RowCount - 1; j > i; j--) |
|||
{ |
|||
sum += rowValues[j] * lhs[j]; |
|||
} |
|||
|
|||
lhs[i] = 1 / rowValues[i] * (lhs[i] - sum); |
|||
} |
|||
|
|||
// We have a column pivot so we only need to pivot the
|
|||
// end result not the incoming right hand side vector
|
|||
var temp = lhs.Clone(); |
|||
|
|||
Pivot(temp, lhs); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pivot elements in <see cref="Vector{T}"/> accoring to internal pivot array
|
|||
/// </summary>
|
|||
/// <param name="vector">Source <see cref="Vector{T}"/>.</param>
|
|||
/// <param name="result">Result <see cref="Vector{T}"/> after pivoting.</param>
|
|||
private void Pivot(Vector<Complex32> vector, Vector<Complex32> result) |
|||
{ |
|||
for (var i = 0; i < _pivots.Length; i++) |
|||
{ |
|||
result[i] = vector[_pivots[i]]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,228 @@ |
|||
// <copyright file="IlutpElementSorter.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using Generic; |
|||
using Numerics; |
|||
|
|||
/// <summary>
|
|||
/// An element sort algorithm for the <see cref="Ilutp"/> class.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This sort algorithm is used to sort the columns in a sparse matrix based on
|
|||
/// the value of the element on the diagonal of the matrix.
|
|||
/// </remarks>
|
|||
internal class IlutpElementSorter |
|||
{ |
|||
/// <summary>
|
|||
/// Sorts the elements of the <paramref name="values"/> vector in decreasing
|
|||
/// fashion. The vector itself is not affected.
|
|||
/// </summary>
|
|||
/// <param name="lowerBound">The starting index.</param>
|
|||
/// <param name="upperBound">The stopping index.</param>
|
|||
/// <param name="sortedIndices">An array that will contain the sorted indices once the algorithm finishes.</param>
|
|||
/// <param name="values">The <see cref="Vector{T}"/> that contains the values that need to be sorted.</param>
|
|||
public static void SortDoubleIndicesDecreasing(int lowerBound, int upperBound, int[] sortedIndices, Vector<Complex32> values) |
|||
{ |
|||
// Move all the indices that we're interested in to the beginning of the
|
|||
// array. Ignore the rest of the indices.
|
|||
if (lowerBound > 0) |
|||
{ |
|||
for (var i = 0; i < (upperBound - lowerBound + 1); i++) |
|||
{ |
|||
Exchange(sortedIndices, i, i + lowerBound); |
|||
} |
|||
|
|||
upperBound -= lowerBound; |
|||
lowerBound = 0; |
|||
} |
|||
|
|||
HeapSortDoublesIndices(lowerBound, upperBound, sortedIndices, values); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sorts the elements of the <paramref name="values"/> vector in decreasing
|
|||
/// fashion using heap sort algorithm. The vector itself is not affected.
|
|||
/// </summary>
|
|||
/// <param name="lowerBound">The starting index.</param>
|
|||
/// <param name="upperBound">The stopping index.</param>
|
|||
/// <param name="sortedIndices">An array that will contain the sorted indices once the algorithm finishes.</param>
|
|||
/// <param name="values">The <see cref="Vector{T}"/> that contains the values that need to be sorted.</param>
|
|||
private static void HeapSortDoublesIndices(int lowerBound, int upperBound, int[] sortedIndices, Vector<Complex32> values) |
|||
{ |
|||
var start = ((upperBound - lowerBound + 1) / 2) - 1 + lowerBound; |
|||
var end = (upperBound - lowerBound + 1) - 1 + lowerBound; |
|||
|
|||
BuildDoubleIndexHeap(start, upperBound - lowerBound + 1, sortedIndices, values); |
|||
|
|||
while (end >= lowerBound) |
|||
{ |
|||
Exchange(sortedIndices, end, lowerBound); |
|||
SiftDoubleIndices(sortedIndices, values, lowerBound, end); |
|||
end -= 1; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Build heap for double indicies
|
|||
/// </summary>
|
|||
/// <param name="start">Root position</param>
|
|||
/// <param name="count">Lenght of <paramref name="values"/></param>
|
|||
/// <param name="sortedIndices">Indicies of <paramref name="values"/></param>
|
|||
/// <param name="values">Target <see cref="Vector{T}"/></param>
|
|||
private static void BuildDoubleIndexHeap(int start, int count, int[] sortedIndices, Vector<Complex32> values) |
|||
{ |
|||
while (start >= 0) |
|||
{ |
|||
SiftDoubleIndices(sortedIndices, values, start, count); |
|||
start -= 1; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sift double indicies
|
|||
/// </summary>
|
|||
/// <param name="sortedIndices">Indicies of <paramref name="values"/></param>
|
|||
/// <param name="values">Target <see cref="Vector{T}"/></param>
|
|||
/// <param name="begin">Root position</param>
|
|||
/// <param name="count">Lenght of <paramref name="values"/></param>
|
|||
private static void SiftDoubleIndices(int[] sortedIndices, Vector<Complex32> values, int begin, int count) |
|||
{ |
|||
var root = begin; |
|||
int child; |
|||
|
|||
while (root * 2 < count) |
|||
{ |
|||
child = root * 2; |
|||
if ((child < count - 1) && (values[sortedIndices[child]].Magnitude > values[sortedIndices[child + 1]].Magnitude)) |
|||
{ |
|||
child += 1; |
|||
} |
|||
|
|||
if (values[sortedIndices[root]].Magnitude <= values[sortedIndices[child]].Magnitude) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
Exchange(sortedIndices, root, child); |
|||
root = child; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sorts the given integers in a decreasing fashion.
|
|||
/// </summary>
|
|||
/// <param name="values">The values.</param>
|
|||
public static void SortIntegersDecreasing(int[] values) |
|||
{ |
|||
HeapSortIntegers(values, values.Length); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sort the given integers in a decreasing fashion using heapsort algorithm
|
|||
/// </summary>
|
|||
/// <param name="values">Array of values to sort</param>
|
|||
/// <param name="count">Length of <paramref name="values"/></param>
|
|||
private static void HeapSortIntegers(int[] values, int count) |
|||
{ |
|||
var start = (count / 2) - 1; |
|||
var end = count - 1; |
|||
|
|||
BuildHeap(values, start, count); |
|||
|
|||
while (end >= 0) |
|||
{ |
|||
Exchange(values, end, 0); |
|||
Sift(values, 0, end); |
|||
end -= 1; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Build heap
|
|||
/// </summary>
|
|||
/// <param name="values">Target values array</param>
|
|||
/// <param name="start">Root position</param>
|
|||
/// <param name="count">Lenght of <paramref name="values"/></param>
|
|||
private static void BuildHeap(int[] values, int start, int count) |
|||
{ |
|||
while (start >= 0) |
|||
{ |
|||
Sift(values, start, count); |
|||
start -= 1; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sift values
|
|||
/// </summary>
|
|||
/// <param name="values">Target value array</param>
|
|||
/// <param name="start">Root position</param>
|
|||
/// <param name="count">Lenght of <paramref name="values"/></param>
|
|||
private static void Sift(int[] values, int start, int count) |
|||
{ |
|||
var root = start; |
|||
int child; |
|||
|
|||
while (root * 2 < count) |
|||
{ |
|||
child = root * 2; |
|||
if ((child < count - 1) && (values[child] > values[child + 1])) |
|||
{ |
|||
child += 1; |
|||
} |
|||
|
|||
if (values[root] > values[child]) |
|||
{ |
|||
Exchange(values, root, child); |
|||
root = child; |
|||
} |
|||
else |
|||
{ |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Exchange values in array
|
|||
/// </summary>
|
|||
/// <param name="values">Target values array</param>
|
|||
/// <param name="first">First value to exchanghe</param>
|
|||
/// <param name="second">Second value to exchanghe</param>
|
|||
private static void Exchange(int[] values, int first, int second) |
|||
{ |
|||
var t = values[first]; |
|||
values[first] = values[second]; |
|||
values[second] = t; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,261 @@ |
|||
// <copyright file="IncompleteLU.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Solvers.Preconditioners; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// An incomplete, level 0, LU factorization preconditioner.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The ILU(0) algorithm was taken from: <br/>
|
|||
/// Iterative methods for sparse linear systems <br/>
|
|||
/// Yousef Saad <br/>
|
|||
/// Algorithm is described in Chapter 10, section 10.3.2, page 275 <br/>
|
|||
/// </remarks>
|
|||
public sealed class IncompleteLU : IPreConditioner<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The matrix holding the lower (L) and upper (U) matrices. The
|
|||
/// decomposition matrices are combined to reduce storage.
|
|||
/// </summary>
|
|||
private SparseMatrix _decompositionLU; |
|||
|
|||
/// <summary>
|
|||
/// Returns the upper triagonal matrix that was created during the LU decomposition.
|
|||
/// </summary>
|
|||
/// <returns>A new matrix containing the upper triagonal elements.</returns>
|
|||
internal Matrix<Complex32> UpperTriangle() |
|||
{ |
|||
var result = new SparseMatrix(_decompositionLU.RowCount); |
|||
for (var i = 0; i < _decompositionLU.RowCount; i++) |
|||
{ |
|||
for (var j = i; j < _decompositionLU.ColumnCount; j++) |
|||
{ |
|||
result[i, j] = _decompositionLU[i, j]; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the lower triagonal matrix that was created during the LU decomposition.
|
|||
/// </summary>
|
|||
/// <returns>A new matrix containing the lower triagonal elements.</returns>
|
|||
internal Matrix<Complex32> LowerTriangle() |
|||
{ |
|||
var result = new SparseMatrix(_decompositionLU.RowCount); |
|||
for (var i = 0; i < _decompositionLU.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j <= i; j++) |
|||
{ |
|||
if (i == j) |
|||
{ |
|||
result[i, j] = 1.0f; |
|||
} |
|||
else |
|||
{ |
|||
result[i, j] = _decompositionLU[i, j]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes the preconditioner and loads the internal data structures.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The matrix upon which the preconditioner is based. </param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <see langword="null" />.</exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
|
|||
public void Initialize(Matrix<Complex32> matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); |
|||
} |
|||
|
|||
_decompositionLU = new SparseMatrix(matrix.ToArray()); |
|||
|
|||
// M == A
|
|||
// for i = 2, ... , n do
|
|||
// for k = 1, .... , i - 1 do
|
|||
// if (i,k) == NZ(Z) then
|
|||
// compute z(i,k) = z(i,k) / z(k,k);
|
|||
// for j = k + 1, ...., n do
|
|||
// if (i,j) == NZ(Z) then
|
|||
// compute z(i,j) = z(i,j) - z(i,k) * z(k,j)
|
|||
// end
|
|||
// end
|
|||
// end
|
|||
// end
|
|||
// end
|
|||
for (var i = 0; i < _decompositionLU.RowCount; i++) |
|||
{ |
|||
for (var k = 0; k < i; k++) |
|||
{ |
|||
if (_decompositionLU[i, k] != 0.0f) |
|||
{ |
|||
var t = _decompositionLU[i, k] / _decompositionLU[k, k]; |
|||
_decompositionLU[i, k] = t; |
|||
if (_decompositionLU[k, i] != 0.0f) |
|||
{ |
|||
_decompositionLU[i, i] = _decompositionLU[i, i] - (t * _decompositionLU[k, i]); |
|||
} |
|||
|
|||
for (var j = k + 1; j < _decompositionLU.RowCount; j++) |
|||
{ |
|||
if (j == i) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
if (_decompositionLU[i, j] != 0.0f) |
|||
{ |
|||
_decompositionLU[i, j] = _decompositionLU[i, j] - (t * _decompositionLU[k, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Approximates the solution to the matrix equation <b>Ax = b</b>.
|
|||
/// </summary>
|
|||
/// <param name="rhs">The right hand side vector.</param>
|
|||
/// <returns>The left hand side vector.</returns>
|
|||
public Vector<Complex32> Approximate(Vector<Complex32> rhs) |
|||
{ |
|||
if (rhs == null) |
|||
{ |
|||
throw new ArgumentNullException("rhs"); |
|||
} |
|||
|
|||
if (_decompositionLU == null) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDoesNotExist); |
|||
} |
|||
|
|||
if (rhs.Count != _decompositionLU.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "rhs"); |
|||
} |
|||
|
|||
Vector<Complex32> result = new DenseVector(rhs.Count); |
|||
Approximate(rhs, result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Approximates the solution to the matrix equation <b>Ax = b</b>.
|
|||
/// </summary>
|
|||
/// <param name="rhs">The right hand side vector.</param>
|
|||
/// <param name="lhs">The left hand side vector. Also known as the result vector.</param>
|
|||
public void Approximate(Vector<Complex32> rhs, Vector<Complex32> lhs) |
|||
{ |
|||
if (rhs == null) |
|||
{ |
|||
throw new ArgumentNullException("rhs"); |
|||
} |
|||
|
|||
if (lhs == null) |
|||
{ |
|||
throw new ArgumentNullException("lhs"); |
|||
} |
|||
|
|||
if (_decompositionLU == null) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDoesNotExist); |
|||
} |
|||
|
|||
if ((lhs.Count != rhs.Count) || (lhs.Count != _decompositionLU.RowCount)) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
// Solve:
|
|||
// Lz = y
|
|||
// Which gives
|
|||
// for (int i = 1; i < matrix.RowLength; i++)
|
|||
// {
|
|||
// z_i = l_ii^-1 * (y_i - SUM_(j<i) l_ij * z_j)
|
|||
// }
|
|||
// NOTE: l_ii should be 1 because u_ii has to be the value
|
|||
Vector<Complex32> rowValues = new DenseVector(_decompositionLU.RowCount); |
|||
for (var i = 0; i < _decompositionLU.RowCount; i++) |
|||
{ |
|||
// Clear the rowValues
|
|||
rowValues.Clear(); |
|||
_decompositionLU.Row(i, rowValues); |
|||
|
|||
var sum = Complex32.Zero; |
|||
for (var j = 0; j < i; j++) |
|||
{ |
|||
sum += rowValues[j] * lhs[j]; |
|||
} |
|||
|
|||
lhs[i] = rhs[i] - sum; |
|||
} |
|||
|
|||
// Solve:
|
|||
// Ux = z
|
|||
// Which gives
|
|||
// for (int i = matrix.RowLength - 1; i > -1; i--)
|
|||
// {
|
|||
// x_i = u_ii^-1 * (z_i - SUM_(j > i) u_ij * x_j)
|
|||
// }
|
|||
for (var i = _decompositionLU.RowCount - 1; i > -1; i--) |
|||
{ |
|||
_decompositionLU.Row(i, rowValues); |
|||
|
|||
var sum = Complex32.Zero; |
|||
for (var j = _decompositionLU.RowCount - 1; j > i; j--) |
|||
{ |
|||
sum += rowValues[j] * lhs[j]; |
|||
} |
|||
|
|||
lhs[i] = 1 / rowValues[i] * (lhs[i] - sum); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,140 @@ |
|||
// <copyright file="UnitPreconditioner.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using System; |
|||
using Generic; |
|||
using Generic.Solvers; |
|||
using Generic.Solvers.Preconditioners; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// A unit preconditioner. This preconditioner does not actually do anything
|
|||
/// it is only used when running an <see cref="IIterativeSolver{T}"/> without
|
|||
/// a preconditioner.
|
|||
/// </summary>
|
|||
internal sealed class UnitPreconditioner : IPreConditioner<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The coefficient matrix on which this preconditioner operates.
|
|||
/// Is used to check dimensions on the different vectors that are processed.
|
|||
/// </summary>
|
|||
private int _size; |
|||
|
|||
/// <summary>
|
|||
/// Initializes the preconditioner and loads the internal data structures.
|
|||
/// </summary>
|
|||
/// <param name="matrix">
|
|||
/// The matrix upon which the preconditioner is based.
|
|||
/// </param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <see langword="null"/>. </exception>
|
|||
/// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
|
|||
public void Initialize(Matrix<Complex32> matrix) |
|||
{ |
|||
if (matrix == null) |
|||
{ |
|||
throw new ArgumentNullException("matrix"); |
|||
} |
|||
|
|||
if (matrix.RowCount != matrix.ColumnCount) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); |
|||
} |
|||
|
|||
_size = matrix.RowCount; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Approximates the solution to the matrix equation <b>Ax = b</b>.
|
|||
/// </summary>
|
|||
/// <param name="rhs">The right hand side vector.</param>
|
|||
/// <param name="lhs">The left hand side vector. Also known as the result vector.</param>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="rhs"/> is <see langword="null"/>.</exception>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="lhs"/> is <see langword="null"/>. </exception>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// <para>
|
|||
/// If <paramref name="rhs"/> and <paramref name="lhs"/> do not have the same size.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// - or -
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// If the size of <paramref name="rhs"/> is different the number of rows of the coefficient matrix.
|
|||
/// </para>
|
|||
/// </exception>
|
|||
public void Approximate(Vector<Complex32> rhs, Vector<Complex32> lhs) |
|||
{ |
|||
if (rhs == null) |
|||
{ |
|||
throw new ArgumentNullException("rhs"); |
|||
} |
|||
|
|||
if (lhs == null) |
|||
{ |
|||
throw new ArgumentNullException("lhs"); |
|||
} |
|||
|
|||
if ((lhs.Count != rhs.Count) || (lhs.Count != _size)) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength); |
|||
} |
|||
|
|||
rhs.CopyTo(lhs); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Approximates the solution to the matrix equation <b>Ax = b</b>.
|
|||
/// </summary>
|
|||
/// <param name="rhs">The right hand side vector.</param>
|
|||
/// <returns>The left hand side vector.</returns>
|
|||
/// <exception cref="ArgumentNullException">If <paramref name="rhs"/> is <see langword="null"/>. </exception>
|
|||
/// <exception cref="ArgumentException">
|
|||
/// If the size of <paramref name="rhs"/> is different the number of rows of the coefficient matrix.
|
|||
/// </exception>
|
|||
public Vector<Complex32> Approximate(Vector<Complex32> rhs) |
|||
{ |
|||
if (rhs == null) |
|||
{ |
|||
throw new ArgumentNullException("rhs"); |
|||
} |
|||
|
|||
if (rhs.Count != _size) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentMatrixDimensions); |
|||
} |
|||
|
|||
Vector<Complex32> result = new DenseVector(rhs.Count); |
|||
Approximate(rhs, result); |
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,394 @@ |
|||
// <copyright file="DivergenceStopCriterium.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.StopCriterium |
|||
{ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using Generic; |
|||
using Generic.Solvers.Status; |
|||
using Generic.Solvers.StopCriterium; |
|||
using Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Monitors an iterative calculation for signs of divergence.
|
|||
/// </summary>
|
|||
public sealed class DivergenceStopCriterium : IIterationStopCriterium<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Default value for the maximum relative increase that the
|
|||
/// residual may experience before a divergence warning is issued.
|
|||
/// </summary>
|
|||
public const double DefaultMaximumRelativeIncrease = 0.08; |
|||
|
|||
/// <summary>
|
|||
/// Default value for the minimum number of iterations over which
|
|||
/// the residual must grow before a divergence warning is issued.
|
|||
/// </summary>
|
|||
public const int DefaultMinimumNumberOfIterations = 10; |
|||
|
|||
/// <summary>
|
|||
/// Defines the default last iteration number. Set to -1 because iterations normally
|
|||
/// start at 0.
|
|||
/// </summary>
|
|||
private const int DefaultLastIterationNumber = -1; |
|||
|
|||
/// <summary>
|
|||
/// The default status.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus DefaultStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// The maximum relative increase the residual may experience without triggering a divergence warning.
|
|||
/// </summary>
|
|||
private double _maximumRelativeIncrease; |
|||
|
|||
/// <summary>
|
|||
/// The number of iterations over which a residual increase should be tracked before issuing a divergence warning.
|
|||
/// </summary>
|
|||
private int _minimumNumberOfIterations; |
|||
|
|||
/// <summary>
|
|||
/// The status of the calculation
|
|||
/// </summary>
|
|||
private ICalculationStatus _status = DefaultStatus; |
|||
|
|||
/// <summary>
|
|||
/// The array that holds the tracking information.
|
|||
/// </summary>
|
|||
private double[] _residualHistory; |
|||
|
|||
/// <summary>
|
|||
/// The iteration number of the last iteration.
|
|||
/// </summary>
|
|||
private int _lastIteration = DefaultLastIterationNumber; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DivergenceStopCriterium"/> class with the default maximum
|
|||
/// relative increase and the default minimum number of tracking iterations.
|
|||
/// </summary>
|
|||
public DivergenceStopCriterium() : this(DefaultMaximumRelativeIncrease, DefaultMinimumNumberOfIterations) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DivergenceStopCriterium"/> class with the specified maximum
|
|||
/// relative increase and the default minimum number of tracking iterations.
|
|||
/// </summary>
|
|||
/// <param name="maximumRelativeIncrease">The maximum relative increase that the residual may experience before a divergence warning is issued.</param>
|
|||
public DivergenceStopCriterium(double maximumRelativeIncrease) : this(maximumRelativeIncrease, DefaultMinimumNumberOfIterations) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DivergenceStopCriterium"/> class with the default maximum
|
|||
/// relative increase and the specified minimum number of tracking iterations.
|
|||
/// </summary>
|
|||
/// <param name="minimumIterations">The minimum number of iterations over which the residual must grow before a divergence warning is issued. </param>
|
|||
public DivergenceStopCriterium(int minimumIterations) : this(DefaultMinimumNumberOfIterations, minimumIterations) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DivergenceStopCriterium"/> class with the specified maximum
|
|||
/// relative increase and the specified minimum number of tracking iterations.
|
|||
/// </summary>
|
|||
/// <param name="maximumRelativeIncrease">The maximum relative increase that the residual may experience before a divergence warning is issued. </param>
|
|||
/// <param name="minimumIterations">The minimum number of iterations over which the residual must grow before a divergence warning is issued.</param>
|
|||
public DivergenceStopCriterium(double maximumRelativeIncrease, int minimumIterations) |
|||
{ |
|||
if (maximumRelativeIncrease <= 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("maximumRelativeIncrease"); |
|||
} |
|||
|
|||
// There must be at least three iterations otherwise we can't calculate the relative increase
|
|||
if (minimumIterations < 3) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("minimumIterations"); |
|||
} |
|||
|
|||
_maximumRelativeIncrease = maximumRelativeIncrease; |
|||
_minimumNumberOfIterations = minimumIterations; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the maximum relative increase that the residual may experience before a divergence warning is issued.
|
|||
/// </summary>
|
|||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the <c>Maximum</c> is set to zero or below.</exception>
|
|||
public double MaximumRelativeIncrease |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _maximumRelativeIncrease; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
set |
|||
{ |
|||
if (value <= 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("value"); |
|||
} |
|||
|
|||
_maximumRelativeIncrease = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the maximum relative increase to the default.
|
|||
/// </summary>
|
|||
public void ResetMaximumRelativeIncreaseToDefault() |
|||
{ |
|||
_maximumRelativeIncrease = DefaultMaximumRelativeIncrease; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the minimum number of iterations over which the residual must grow before
|
|||
/// issuing a divergence warning.
|
|||
/// </summary>
|
|||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the <c>value</c> is set to less than one.</exception>
|
|||
public int MinimumNumberOfIterations |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _minimumNumberOfIterations; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
set |
|||
{ |
|||
// There must be at least three iterations otherwise we can't calculate
|
|||
// the relative increase
|
|||
if (value < 3) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("value"); |
|||
} |
|||
|
|||
_minimumNumberOfIterations = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the minimum number of iterations to the default.
|
|||
/// </summary>
|
|||
public void ResetNumberOfIterationsToDefault() |
|||
{ |
|||
_minimumNumberOfIterations = DefaultMinimumNumberOfIterations; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determines the status of the iterative calculation based on the stop criteria stored
|
|||
/// by the current <see cref="IIterationStopCriterium{T}"/>. Result is set into <c>Status</c> field.
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">The number of iterations that have passed so far.</param>
|
|||
/// <param name="solutionVector">The vector containing the current solution values.</param>
|
|||
/// <param name="sourceVector">The right hand side vector.</param>
|
|||
/// <param name="residualVector">The vector containing the current residual vectors.</param>
|
|||
/// <remarks>
|
|||
/// The individual stop criteria may internally track the progress of the calculation based
|
|||
/// on the invocation of this method. Therefore this method should only be called if the
|
|||
/// calculation has moved forwards at least one step.
|
|||
/// </remarks>
|
|||
public void DetermineStatus(int iterationNumber, Vector<Complex32> solutionVector, Vector<Complex32> sourceVector, Vector<Complex32> residualVector) |
|||
{ |
|||
if (iterationNumber < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("iterationNumber"); |
|||
} |
|||
|
|||
if (residualVector == null) |
|||
{ |
|||
throw new ArgumentNullException("residualVector"); |
|||
} |
|||
|
|||
if (_lastIteration >= iterationNumber) |
|||
{ |
|||
// We have already stored the actual last iteration number
|
|||
// For now do nothing. We only care about the next step.
|
|||
return; |
|||
} |
|||
|
|||
if ((_residualHistory == null) || (_residualHistory.Length != RequiredHistoryLength)) |
|||
{ |
|||
_residualHistory = new double[RequiredHistoryLength]; |
|||
} |
|||
|
|||
// We always track the residual.
|
|||
// Move the old versions one element up in the array.
|
|||
for (var i = 1; i < _residualHistory.Length; i++) |
|||
{ |
|||
_residualHistory[i - 1] = _residualHistory[i]; |
|||
} |
|||
|
|||
// Store the infinity norms of both the solution and residual vectors
|
|||
// These values will be used to calculate the relative drop in residuals later on.
|
|||
_residualHistory[_residualHistory.Length - 1] = residualVector.Norm(Double.PositiveInfinity); |
|||
|
|||
// Check if we have NaN's. If so we've gone way beyond normal divergence.
|
|||
// Stop the iteration.
|
|||
if (double.IsNaN(_residualHistory[_residualHistory.Length - 1])) |
|||
{ |
|||
SetStatusToDiverged(); |
|||
return; |
|||
} |
|||
|
|||
// Check if we are diverging and if so set the status
|
|||
if (IsDiverging()) |
|||
{ |
|||
SetStatusToDiverged(); |
|||
} |
|||
else |
|||
{ |
|||
SetStatusToRunning(); |
|||
} |
|||
|
|||
_lastIteration = iterationNumber; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Detect if solution is diverging
|
|||
/// </summary>
|
|||
/// <returns><c>true</c> if diverging, otherwise <c>false</c></returns>
|
|||
private bool IsDiverging() |
|||
{ |
|||
// Run for each variable
|
|||
for (var i = 1; i < _residualHistory.Length; i++) |
|||
{ |
|||
var difference = _residualHistory[i] - _residualHistory[i - 1]; |
|||
|
|||
// Divergence is occurring if:
|
|||
// - the last residual is larger than the previous one
|
|||
// - the relative increase of the residual is larger than the setting allows
|
|||
if ((difference < 0) || (_residualHistory[i - 1] * (1 + _maximumRelativeIncrease) >= _residualHistory[i])) |
|||
{ |
|||
// No divergence taking place within the required number of iterations
|
|||
// So reset and stop the iteration. There is no way we can get to the
|
|||
// required number of iterations anymore.
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets required history lenght
|
|||
/// </summary>
|
|||
private int RequiredHistoryLength |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _minimumNumberOfIterations + 1; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set status to <see cref="CalculationDiverged"/>
|
|||
/// </summary>
|
|||
private void SetStatusToDiverged() |
|||
{ |
|||
if (!(_status is CalculationDiverged)) |
|||
{ |
|||
_status = new CalculationDiverged(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set status to <see cref="CalculationRunning"/>
|
|||
/// </summary>
|
|||
private void SetStatusToRunning() |
|||
{ |
|||
if (!(_status is CalculationRunning)) |
|||
{ |
|||
_status = new CalculationRunning(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the current calculation status.
|
|||
/// </summary>
|
|||
public ICalculationStatus Status |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _status; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Resets the <see cref="IIterationStopCriterium{T}"/> to the pre-calculation state.
|
|||
/// </summary>
|
|||
public void ResetToPrecalculationState() |
|||
{ |
|||
_status = DefaultStatus; |
|||
_lastIteration = DefaultLastIterationNumber; |
|||
_residualHistory = null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="StopLevel"/> which indicates what sort of stop criterium this
|
|||
/// <see cref="IIterationStopCriterium{T}"/> monitors.
|
|||
/// </summary>
|
|||
/// <value>Returns <see cref="Generic.Solvers.StopCriterium.StopLevel.Divergence"/>.</value>
|
|||
public StopLevel StopLevel |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return StopLevel.Divergence; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Clones the current <see cref="DivergenceStopCriterium"/> and its settings.
|
|||
/// </summary>
|
|||
/// <returns>A new instance of the <see cref="DivergenceStopCriterium"/> class.</returns>
|
|||
public IIterationStopCriterium<Complex32> Clone() |
|||
{ |
|||
return new DivergenceStopCriterium(_maximumRelativeIncrease, _minimumNumberOfIterations); |
|||
} |
|||
|
|||
#if !SILVERLIGHT
|
|||
/// <summary>
|
|||
/// Clone this object
|
|||
/// </summary>
|
|||
/// <returns>Object clone</returns>
|
|||
object ICloneable.Clone() |
|||
{ |
|||
return Clone(); |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|||
@ -0,0 +1,202 @@ |
|||
// <copyright file="FailureStopCriterium.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.StopCriterium |
|||
{ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using Generic; |
|||
using Generic.Solvers.Status; |
|||
using Generic.Solvers.StopCriterium; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// Defines an <see cref="Generic.Solvers.StopCriterium.IIterationStopCriterium{T}"/> that monitors residuals for NaN's.
|
|||
/// </summary>
|
|||
public sealed class FailureStopCriterium : IIterationStopCriterium<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// Defines the default last iteration number. Set to -1 because iterations normally
|
|||
/// start at 0.
|
|||
/// </summary>
|
|||
private const int DefaultLastIterationNumber = -1; |
|||
|
|||
/// <summary>
|
|||
/// The default status.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus DefaultStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// The status of the calculation
|
|||
/// </summary>
|
|||
private ICalculationStatus _status = DefaultStatus; |
|||
|
|||
/// <summary>
|
|||
/// The iteration number of the last iteration.
|
|||
/// </summary>
|
|||
private int _lastIteration = DefaultLastIterationNumber; |
|||
|
|||
/// <summary>
|
|||
/// Determines the status of the iterative calculation based on the stop criteria stored
|
|||
/// by the current <see cref="IIterationStopCriterium{T}"/>. Result is set into <c>Status</c> field.
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">The number of iterations that have passed so far.</param>
|
|||
/// <param name="solutionVector">The vector containing the current solution values.</param>
|
|||
/// <param name="sourceVector">The right hand side vector.</param>
|
|||
/// <param name="residualVector">The vector containing the current residual vectors.</param>
|
|||
/// <remarks>
|
|||
/// The individual stop criteria may internally track the progress of the calculation based
|
|||
/// on the invocation of this method. Therefore this method should only be called if the
|
|||
/// calculation has moved forwards at least one step.
|
|||
/// </remarks>
|
|||
public void DetermineStatus(int iterationNumber, Vector<Complex32> solutionVector, Vector<Complex32> sourceVector, Vector<Complex32> residualVector) |
|||
{ |
|||
if (iterationNumber < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("iterationNumber"); |
|||
} |
|||
|
|||
if (solutionVector == null) |
|||
{ |
|||
throw new ArgumentNullException("solutionVector"); |
|||
} |
|||
|
|||
if (residualVector == null) |
|||
{ |
|||
throw new ArgumentNullException("residualVector"); |
|||
} |
|||
|
|||
if (solutionVector.Count != residualVector.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentArraysSameLength); |
|||
} |
|||
|
|||
if (_lastIteration >= iterationNumber) |
|||
{ |
|||
// We have already stored the actual last iteration number
|
|||
// For now do nothing. We only care about the next step.
|
|||
return; |
|||
} |
|||
|
|||
// Store the infinity norms of both the solution and residual vectors
|
|||
var residualNorm = residualVector.Norm(Double.PositiveInfinity); |
|||
var solutionNorm = solutionVector.Norm(Double.PositiveInfinity); |
|||
|
|||
if (Double.IsNaN(solutionNorm) || Double.IsNaN(residualNorm)) |
|||
{ |
|||
SetStatusToFailed(); |
|||
} |
|||
else |
|||
{ |
|||
SetStatusToRunning(); |
|||
} |
|||
|
|||
_lastIteration = iterationNumber; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set status to <see cref="CalculationFailure"/>
|
|||
/// </summary>
|
|||
private void SetStatusToFailed() |
|||
{ |
|||
if (!(_status is CalculationFailure)) |
|||
{ |
|||
_status = new CalculationFailure(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set status to <see cref="CalculationRunning"/>
|
|||
/// </summary>
|
|||
private void SetStatusToRunning() |
|||
{ |
|||
if (!(_status is CalculationRunning)) |
|||
{ |
|||
_status = new CalculationRunning(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the current calculation status.
|
|||
/// </summary>
|
|||
public ICalculationStatus Status |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _status; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Resets the <see cref="IIterationStopCriterium{T}"/> to the pre-calculation state.
|
|||
/// </summary>
|
|||
public void ResetToPrecalculationState() |
|||
{ |
|||
_status = DefaultStatus; |
|||
_lastIteration = DefaultLastIterationNumber; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="StopLevel"/>which indicates what sort of stop criterium this
|
|||
/// <see cref="IIterationStopCriterium{T}"/> monitors.
|
|||
/// </summary>
|
|||
/// <value>Returns <see cref="CalculationFailure"/>.</value>
|
|||
public StopLevel StopLevel |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return StopLevel.CalculationFailure; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Clones the current <see cref="FailureStopCriterium"/> and its settings.
|
|||
/// </summary>
|
|||
/// <returns>A new instance of the <see cref="FailureStopCriterium"/> class.</returns>
|
|||
public IIterationStopCriterium<Complex32> Clone() |
|||
{ |
|||
return new FailureStopCriterium(); |
|||
} |
|||
|
|||
#if !SILVERLIGHT
|
|||
/// <summary>
|
|||
/// Clones the current <see cref="FailureStopCriterium"/> and its settings.
|
|||
/// </summary>
|
|||
/// <returns>A new instance of the <see cref="FailureStopCriterium"/> class.</returns>
|
|||
object ICloneable.Clone() |
|||
{ |
|||
return Clone(); |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|||
@ -0,0 +1,228 @@ |
|||
// <copyright file="IterationCountStopCriterium.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.StopCriterium |
|||
{ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using Generic; |
|||
using Generic.Solvers.Status; |
|||
using Generic.Solvers.StopCriterium; |
|||
using Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Defines an <see cref="IIterationStopCriterium{T}"/> that monitors the numbers of iteration
|
|||
/// steps as stop criterium.
|
|||
/// </summary>
|
|||
public sealed class IterationCountStopCriterium : IIterationStopCriterium<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The default value for the maximum number of iterations the process is allowed
|
|||
/// to perform.
|
|||
/// </summary>
|
|||
public const int DefaultMaximumNumberOfIterations = 1000; |
|||
|
|||
/// <summary>
|
|||
/// The default status.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus DefaultStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// The maximum number of iterations the calculation is allowed to perform.
|
|||
/// </summary>
|
|||
private int _maximumNumberOfIterations; |
|||
|
|||
/// <summary>
|
|||
/// The status of the calculation
|
|||
/// </summary>
|
|||
private ICalculationStatus _status = DefaultStatus; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="IterationCountStopCriterium"/> class with the default maximum
|
|||
/// number of iterations.
|
|||
/// </summary>
|
|||
public IterationCountStopCriterium() : this(DefaultMaximumNumberOfIterations) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="IterationCountStopCriterium"/> class with the specified maximum
|
|||
/// number of iterations.
|
|||
/// </summary>
|
|||
/// <param name="maximumNumberOfIterations">The maximum number of iterations the calculation is allowed to perform.</param>
|
|||
public IterationCountStopCriterium(int maximumNumberOfIterations) |
|||
{ |
|||
if (maximumNumberOfIterations < 1) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("maximumNumberOfIterations"); |
|||
} |
|||
|
|||
_maximumNumberOfIterations = maximumNumberOfIterations; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the maximum number of iterations the calculation is allowed to perform.
|
|||
/// </summary>
|
|||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the <c>Maximum</c> is set to a negative value.</exception>
|
|||
public int MaximumNumberOfIterations |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _maximumNumberOfIterations; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
set |
|||
{ |
|||
if (value < 1) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("value"); |
|||
} |
|||
|
|||
_maximumNumberOfIterations = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the maximum number of iterations to the default.
|
|||
/// </summary>
|
|||
public void ResetMaximumNumberOfIterationsToDefault() |
|||
{ |
|||
_maximumNumberOfIterations = DefaultMaximumNumberOfIterations; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determines the status of the iterative calculation based on the stop criteria stored
|
|||
/// by the current <see cref="IterationCountStopCriterium"/>. Result is set into <c>Status</c> field.
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">The number of iterations that have passed so far.</param>
|
|||
/// <param name="solutionVector">The vector containing the current solution values.</param>
|
|||
/// <param name="sourceVector">The right hand side vector.</param>
|
|||
/// <param name="residualVector">The vector containing the current residual vectors.</param>
|
|||
/// <remarks>
|
|||
/// The individual stop criteria may internally track the progress of the calculation based
|
|||
/// on the invocation of this method. Therefore this method should only be called if the
|
|||
/// calculation has moved forwards at least one step.
|
|||
/// </remarks>
|
|||
public void DetermineStatus(int iterationNumber, Vector<Complex32> solutionVector, Vector<Complex32> sourceVector, Vector<Complex32> residualVector) |
|||
{ |
|||
if (iterationNumber < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("iterationNumber"); |
|||
} |
|||
|
|||
if (iterationNumber >= _maximumNumberOfIterations) |
|||
{ |
|||
SetStatusToFinished(); |
|||
} |
|||
else |
|||
{ |
|||
SetStatusToRunning(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set status to <see cref="CalculationFailure"/>
|
|||
/// </summary>
|
|||
private void SetStatusToFinished() |
|||
{ |
|||
if (!(_status is CalculationStoppedWithoutConvergence)) |
|||
{ |
|||
_status = new CalculationStoppedWithoutConvergence(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set status to <see cref="CalculationRunning"/>
|
|||
/// </summary>
|
|||
private void SetStatusToRunning() |
|||
{ |
|||
if (!(_status is CalculationRunning)) |
|||
{ |
|||
_status = new CalculationRunning(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the current calculation status.
|
|||
/// </summary>
|
|||
public ICalculationStatus Status |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _status; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Resets the <see cref="IterationCountStopCriterium"/> to the pre-calculation state.
|
|||
/// </summary>
|
|||
public void ResetToPrecalculationState() |
|||
{ |
|||
_status = DefaultStatus; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="StopLevel"/> which indicates what sort of stop criterium this
|
|||
/// <see cref="IterationCountStopCriterium"/> monitors.
|
|||
/// </summary>
|
|||
/// <value>Returns <see cref="StopLevel"/>.</value>
|
|||
public StopLevel StopLevel |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return StopLevel.StoppedWithoutConvergence; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Clones the current <see cref="IterationCountStopCriterium"/> and its settings.
|
|||
/// </summary>
|
|||
/// <returns>A new instance of the <see cref="IterationCountStopCriterium"/> class.</returns>
|
|||
public IIterationStopCriterium<Complex32> Clone() |
|||
{ |
|||
return new IterationCountStopCriterium(_maximumNumberOfIterations); |
|||
} |
|||
|
|||
#if !SILVERLIGHT
|
|||
/// <summary>
|
|||
/// Clones the current <see cref="IterationCountStopCriterium"/> and its settings.
|
|||
/// </summary>
|
|||
/// <returns>A new instance of the <see cref="IterationCountStopCriterium"/> object.</returns>
|
|||
object ICloneable.Clone() |
|||
{ |
|||
return Clone(); |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|||
@ -0,0 +1,410 @@ |
|||
// <copyright file="ResidualStopCriterium.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers.StopCriterium |
|||
{ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using Generic; |
|||
using Generic.Solvers.Status; |
|||
using Generic.Solvers.StopCriterium; |
|||
using Numerics; |
|||
using Properties; |
|||
|
|||
/// <summary>
|
|||
/// Defines an <see cref="IIterationStopCriterium{T}"/> that monitors residuals as stop criterium.
|
|||
/// </summary>
|
|||
public sealed class ResidualStopCriterium : IIterationStopCriterium<Complex32> |
|||
{ |
|||
/// <summary>
|
|||
/// The default value for the maximum value of the residual.
|
|||
/// </summary>
|
|||
public const double DefaultMaximumResidual = 1e-6; |
|||
|
|||
/// <summary>
|
|||
/// The default value for the minimum number of iterations.
|
|||
/// </summary>
|
|||
public const int DefaultMinimumIterationsBelowMaximum = 0; |
|||
|
|||
/// <summary>
|
|||
/// Defines the default last iteration number. Set to -1 because iterations normally start at 0.
|
|||
/// </summary>
|
|||
private const int DefaultLastIterationNumber = -1; |
|||
|
|||
/// <summary>
|
|||
/// The default status.
|
|||
/// </summary>
|
|||
private static readonly ICalculationStatus DefaultStatus = new CalculationIndetermined(); |
|||
|
|||
/// <summary>
|
|||
/// The maximum value for the residual below which the calculation is considered converged.
|
|||
/// </summary>
|
|||
private double _maximum; |
|||
|
|||
/// <summary>
|
|||
/// The minimum number of iterations for which the residual has to be below the maximum before
|
|||
/// the calculation is considered converged.
|
|||
/// </summary>
|
|||
private int _minimumIterationsBelowMaximum; |
|||
|
|||
/// <summary>
|
|||
/// The status of the calculation
|
|||
/// </summary>
|
|||
private ICalculationStatus _status = DefaultStatus; |
|||
|
|||
/// <summary>
|
|||
/// The number of iterations since the residuals got below the maximum.
|
|||
/// </summary>
|
|||
private int _iterationCount; |
|||
|
|||
/// <summary>
|
|||
/// The iteration number of the last iteration.
|
|||
/// </summary>
|
|||
private int _lastIteration = DefaultLastIterationNumber; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ResidualStopCriterium"/> class with the default maximum
|
|||
/// residual and the default minimum number of iterations.
|
|||
/// </summary>
|
|||
public ResidualStopCriterium() : this(DefaultMaximumResidual, DefaultMinimumIterationsBelowMaximum) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ResidualStopCriterium"/> class with the specified
|
|||
/// maximum residual and the default minimum number of iterations.
|
|||
/// </summary>
|
|||
/// <param name="maximum">The maximum value for the residual below which the calculation is considered converged.</param>
|
|||
public ResidualStopCriterium(double maximum) : this(maximum, DefaultMinimumIterationsBelowMaximum) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ResidualStopCriterium"/> class with the default maximum residual
|
|||
/// and specified minimum number of iterations.
|
|||
/// </summary>
|
|||
/// <param name="minimumIterationsBelowMaximum">
|
|||
/// The minimum number of iterations for which the residual has to be below the maximum before
|
|||
/// the calculation is considered converged.
|
|||
/// </param>
|
|||
public ResidualStopCriterium(int minimumIterationsBelowMaximum) : this(DefaultMaximumResidual, minimumIterationsBelowMaximum) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ResidualStopCriterium"/> class with the specified
|
|||
/// maximum residual and minimum number of iterations.
|
|||
/// </summary>
|
|||
/// <param name="maximum">
|
|||
/// The maximum value for the residual below which the calculation is considered converged.
|
|||
/// </param>
|
|||
/// <param name="minimumIterationsBelowMaximum">
|
|||
/// The minimum number of iterations for which the residual has to be below the maximum before
|
|||
/// the calculation is considered converged.
|
|||
/// </param>
|
|||
public ResidualStopCriterium(double maximum, int minimumIterationsBelowMaximum) |
|||
{ |
|||
if (maximum < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("maximum"); |
|||
} |
|||
|
|||
if (minimumIterationsBelowMaximum < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("minimumIterationsBelowMaximum"); |
|||
} |
|||
|
|||
_maximum = maximum; |
|||
_minimumIterationsBelowMaximum = minimumIterationsBelowMaximum; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the maximum value for the residual below which the calculation is considered
|
|||
/// converged.
|
|||
/// </summary>
|
|||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the <c>Maximum</c> is set to a negative value.</exception>
|
|||
public double Maximum |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _maximum; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
set |
|||
{ |
|||
if (value < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("value"); |
|||
} |
|||
|
|||
_maximum = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the maximum residual to the default.
|
|||
/// </summary>
|
|||
public void ResetMaximumResidualToDefault() |
|||
{ |
|||
_maximum = DefaultMaximumResidual; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the minimum number of iterations for which the residual has to be
|
|||
/// below the maximum before the calculation is considered converged.
|
|||
/// </summary>
|
|||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the <c>BelowMaximumFor</c> is set to a value less than 1.</exception>
|
|||
public int MinimumIterationsBelowMaximum |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _minimumIterationsBelowMaximum; |
|||
} |
|||
|
|||
[DebuggerStepThrough] |
|||
set |
|||
{ |
|||
if (value < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("value"); |
|||
} |
|||
|
|||
_minimumIterationsBelowMaximum = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the minimum number of iterations to the default.
|
|||
/// </summary>
|
|||
public void ResetMinimumIterationsBelowMaximumToDefault() |
|||
{ |
|||
_minimumIterationsBelowMaximum = DefaultMinimumIterationsBelowMaximum; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determines the status of the iterative calculation based on the stop criteria stored
|
|||
/// by the current <see cref="IIterationStopCriterium{T}"/>. Result is set into <c>Status</c> field.
|
|||
/// </summary>
|
|||
/// <param name="iterationNumber">The number of iterations that have passed so far.</param>
|
|||
/// <param name="solutionVector">The vector containing the current solution values.</param>
|
|||
/// <param name="sourceVector">The right hand side vector.</param>
|
|||
/// <param name="residualVector">The vector containing the current residual vectors.</param>
|
|||
/// <remarks>
|
|||
/// The individual stop criteria may internally track the progress of the calculation based
|
|||
/// on the invocation of this method. Therefore this method should only be called if the
|
|||
/// calculation has moved forwards at least one step.
|
|||
/// </remarks>
|
|||
public void DetermineStatus(int iterationNumber, Vector<Complex32> solutionVector, Vector<Complex32> sourceVector, Vector<Complex32> residualVector) |
|||
{ |
|||
if (iterationNumber < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("iterationNumber"); |
|||
} |
|||
|
|||
if (solutionVector == null) |
|||
{ |
|||
throw new ArgumentNullException("solutionVector"); |
|||
} |
|||
|
|||
if (sourceVector == null) |
|||
{ |
|||
throw new ArgumentNullException("sourceVector"); |
|||
} |
|||
|
|||
if (residualVector == null) |
|||
{ |
|||
throw new ArgumentNullException("residualVector"); |
|||
} |
|||
|
|||
if (solutionVector.Count != sourceVector.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "sourceVector"); |
|||
} |
|||
|
|||
if (solutionVector.Count != residualVector.Count) |
|||
{ |
|||
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "residualVector"); |
|||
} |
|||
|
|||
// Store the infinity norms of both the solution and residual vectors
|
|||
// These values will be used to calculate the relative drop in residuals
|
|||
// later on.
|
|||
var residualNorm = residualVector.Norm(Double.PositiveInfinity); |
|||
|
|||
// Check the residuals by calculating:
|
|||
// ||r_i|| <= stop_tol * ||b||
|
|||
var stopCriterium = ComputeStopCriterium(sourceVector.Norm(Double.PositiveInfinity)); |
|||
|
|||
// First check that we have real numbers not NaN's.
|
|||
// NaN's can occur when the iterative process diverges so we
|
|||
// stop if that is the case.
|
|||
if (double.IsNaN(stopCriterium) || double.IsNaN(residualNorm)) |
|||
{ |
|||
_iterationCount = 0; |
|||
SetStatusToDiverged(); |
|||
return; |
|||
} |
|||
|
|||
// ||r_i|| <= stop_tol * ||b||
|
|||
// Stop the calculation if it's clearly smaller than the tolerance
|
|||
var decimalMagnitude = Math.Abs(stopCriterium.Magnitude()) + 1; |
|||
if (residualNorm.IsSmallerWithDecimalPlaces(stopCriterium, decimalMagnitude)) |
|||
{ |
|||
if (_lastIteration <= iterationNumber) |
|||
{ |
|||
_iterationCount = iterationNumber - _lastIteration; |
|||
if (_iterationCount >= _minimumIterationsBelowMaximum) |
|||
{ |
|||
SetStatusToConverged(); |
|||
} |
|||
else |
|||
{ |
|||
SetStatusToRunning(); |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
_iterationCount = 0; |
|||
SetStatusToRunning(); |
|||
} |
|||
|
|||
_lastIteration = iterationNumber; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculate stop criterium
|
|||
/// </summary>
|
|||
/// <param name="solutionNorm">Solution vector norm</param>
|
|||
/// <returns>Criterium value</returns>
|
|||
private double ComputeStopCriterium(double solutionNorm) |
|||
{ |
|||
// This is criterium 1 from Templates for the solution of linear systems.
|
|||
// The problem with this criterium is that it's not limiting enough. For now
|
|||
// we won't use it. Later on we might get back to it.
|
|||
// return mMaximumResidual * (System.Math.Abs(mMatrixNorm) * System.Math.Abs(solutionNorm) + System.Math.Abs(mVectorNorm));
|
|||
|
|||
// For now use criterium 2 from Templates for the solution of linear systems. See page 60.
|
|||
return _maximum * Math.Abs(solutionNorm); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set status to <see cref="CalculationDiverged"/>
|
|||
/// </summary>
|
|||
private void SetStatusToDiverged() |
|||
{ |
|||
if (!(_status is CalculationDiverged)) |
|||
{ |
|||
_status = new CalculationDiverged(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set status to <see cref="CalculationConverged"/>
|
|||
/// </summary>
|
|||
private void SetStatusToConverged() |
|||
{ |
|||
if (!(_status is CalculationConverged)) |
|||
{ |
|||
_status = new CalculationConverged(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set status to <see cref="CalculationRunning"/>
|
|||
/// </summary>
|
|||
private void SetStatusToRunning() |
|||
{ |
|||
if (!(_status is CalculationRunning)) |
|||
{ |
|||
_status = new CalculationRunning(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the current calculation status.
|
|||
/// </summary>
|
|||
public ICalculationStatus Status |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return _status; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Resets the <see cref="IIterationStopCriterium{T}"/> to the pre-calculation state.
|
|||
/// </summary>
|
|||
public void ResetToPrecalculationState() |
|||
{ |
|||
_status = DefaultStatus; |
|||
_iterationCount = 0; |
|||
_lastIteration = DefaultLastIterationNumber; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="StopLevel"/> which indicates what sort of stop criterium this
|
|||
/// <see cref="IIterationStopCriterium{T}"/> monitors.
|
|||
/// </summary>
|
|||
/// <value>Returns <see cref="StopLevel"/>.</value>
|
|||
public StopLevel StopLevel |
|||
{ |
|||
[DebuggerStepThrough] |
|||
get |
|||
{ |
|||
return StopLevel.Convergence; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Clones the current <see cref="ResidualStopCriterium"/> and its settings.
|
|||
/// </summary>
|
|||
/// <returns>A new instance of the <see cref="ResidualStopCriterium"/> class.</returns>
|
|||
public IIterationStopCriterium<Complex32> Clone() |
|||
{ |
|||
return new ResidualStopCriterium(_maximum, _minimumIterationsBelowMaximum); |
|||
} |
|||
|
|||
#if !SILVERLIGHT
|
|||
/// <summary>
|
|||
/// Clones the current <see cref="ResidualStopCriterium"/> and its settings.
|
|||
/// </summary>
|
|||
/// <returns>A new instance of the <see cref="ResidualStopCriterium"/> object.</returns>
|
|||
object ICloneable.Clone() |
|||
{ |
|||
return Clone(); |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,157 @@ |
|||
// <copyright file="DenseMatrixTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System.Collections.Generic; |
|||
using Numerics; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32; |
|||
|
|||
public class DenseMatrixTests : MatrixTests |
|||
{ |
|||
protected override Matrix<Complex32> CreateMatrix(int rows, int columns) |
|||
{ |
|||
return new DenseMatrix(rows, columns); |
|||
} |
|||
|
|||
protected override Matrix<Complex32> CreateMatrix(Complex32[,] data) |
|||
{ |
|||
return new DenseMatrix(data); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new DenseVector(size); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(Complex32[] data) |
|||
{ |
|||
return new DenseVector(data); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateMatrixFrom1DArray() |
|||
{ |
|||
Dictionary<string, Matrix<Complex32>> testData = new Dictionary<string, Matrix<Complex32>> |
|||
{ |
|||
{ "Singular3x3", new DenseMatrix(3, 3, new[] { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(2.0f, 1), new Complex32(2.0f, 1) }) }, |
|||
{ "Square3x3", new DenseMatrix(3, 3, new[] { new Complex32(-1.1f, 1), Complex32.Zero, new Complex32(-4.4f, 1), new Complex32(-2.2f, 1), new Complex32(1.1f, 1), new Complex32(5.5f, 1), new Complex32(-3.3f, 1), new Complex32(2.2f, 1), new Complex32(6.6f, 1) }) }, |
|||
{ "Square4x4", new DenseMatrix(4, 4, new[] { new Complex32(-1.1f, 1), Complex32.Zero, new Complex32(1.0f, 1), new Complex32(-4.4f, 1), new Complex32(-2.2f, 1), new Complex32(1.1f, 1), new Complex32(2.1f, 1), new Complex32(5.5f, 1), new Complex32(-3.3f, 1), new Complex32(2.2f, 1), new Complex32(6.2f, 1), new Complex32(6.6f, 1), new Complex32(-4.4f, 1), new Complex32(3.3f, 1), new Complex32(4.3f, 1), new Complex32(-7.7f, 1) }) }, |
|||
{ "Tall3x2", new DenseMatrix(3, 2, new[] { new Complex32(-1.1f, 1), Complex32.Zero, new Complex32(-4.4f, 1), new Complex32(-2.2f, 1), new Complex32(1.1f, 1), new Complex32(5.5f, 1) }) }, |
|||
{ "Wide2x3", new DenseMatrix(2, 3, new[] { new Complex32(-1.1f, 1), Complex32.Zero, new Complex32(-2.2f, 1), new Complex32(1.1f, 1), new Complex32(-3.3f, 1), new Complex32(2.2f, 1) }) } |
|||
}; |
|||
|
|||
foreach (var name in testData.Keys) |
|||
{ |
|||
Assert.AreEqual(TestMatrices[name], testData[name]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void MatrixFrom1DArrayIsReference() |
|||
{ |
|||
var data = new[] { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(2.0f, 1), new Complex32(2.0f, 1) }; |
|||
var matrix = new DenseMatrix(3, 3, data); |
|||
matrix[0, 0] = 10.0f; |
|||
AssertHelpers.AreEqual(10.0f, data[0]); |
|||
} |
|||
|
|||
[Test] |
|||
public void MatrixFrom2DArrayIsCopy() |
|||
{ |
|||
var matrix = new DenseMatrix(TestData2D["Singular3x3"]); |
|||
matrix[0, 0] = 10.0f; |
|||
AssertHelpers.AreEqual(new Complex32(1.0f, 1), TestData2D["Singular3x3"][0, 0]); |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3")] |
|||
[Row("Singular3x3")] |
|||
[Row("Square3x3")] |
|||
[Row("Square4x4")] |
|||
[Row("Tall3x2")] |
|||
[Row("Wide2x3")] |
|||
public void CanCreateMatrixFrom2DArray(string name) |
|||
{ |
|||
var matrix = new DenseMatrix(TestData2D[name]); |
|||
for (var i = 0; i < TestData2D[name].GetLength(0); i++) |
|||
{ |
|||
for (var j = 0; j < TestData2D[name].GetLength(1); j++) |
|||
{ |
|||
AssertHelpers.AreEqual(TestData2D[name][i, j], matrix[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateMatrixWithUniformValues() |
|||
{ |
|||
var matrix = new DenseMatrix(10, 10, new Complex32(10.0f, 1)); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(matrix[i, j], new Complex32(10.0f, 1)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateIdentity() |
|||
{ |
|||
var matrix = DenseMatrix.Identity(5); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
if (i == j) |
|||
{ |
|||
AssertHelpers.AreEqual(Complex32.One, matrix[i, j]); |
|||
} |
|||
else |
|||
{ |
|||
AssertHelpers.AreEqual(Complex32.Zero, matrix[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(0)] |
|||
[Row(-1)] |
|||
[ExpectedArgumentException] |
|||
public void IdentityFailsWithZeroOrNegativeOrder(int order) |
|||
{ |
|||
DenseMatrix.Identity(order); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
// <copyright file="DenseVectorTest.TextHandling.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using System.Globalization; |
|||
using LinearAlgebra.Complex32; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public class DenseVectorTextHandlingTest |
|||
{ |
|||
[Test] |
|||
[Row("2", "2")] |
|||
[Row("(3)", "3")] |
|||
[Row("[1,2,3]", "1,2,3")]
|
|||
[Row(" [ 1.1 , 2.1 , 3.1 ] ", "1.1,2.1,3.1")]
|
|||
[Row(" [ -1.1 , 2.1 , +3.1 ] ", "-1.1,2.1,3.1")]
|
|||
[Row(" [1.2,3.4 , 5.6] ", "1.2,3.4,5.6")]
|
|||
[Row("[1+1i,2+1i,3+1i]", "1 + 1i,2 + 1i,3 + 1i")]
|
|||
[Row(" [ 1.1 + 1i , 2.1+1i , 3.1+1i ] ", "1.1 + 1i,2.1 + 1i,3.1 + 1i")]
|
|||
[Row(" [ -1.1 + 1i , 2.1-1i , +3.1+1i ] ", "-1.1 + 1i,2.1 - 1i,3.1 + 1i")]
|
|||
[Row(" [1.2+2.3i ,3.4+4.5i , 5.6+ 6.7i] ", "1.2 + 2.3i,3.4 + 4.5i,5.6 + 6.7i")]
|
|||
public void CanParseComplexDenseVectorsWithInvariant(string stringToParse, string expectedToString) |
|||
{ |
|||
var formatProvider = CultureInfo.InvariantCulture; |
|||
DenseVector vector = DenseVector.Parse(stringToParse, formatProvider); |
|||
|
|||
Assert.AreEqual(expectedToString, vector.ToString(formatProvider)); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(" 1.2 + 1i , 3.4 + 1i , 5.6 + 1i ", "1.2 + 1i,3.4 + 1i,5.6 + 1i", "en-US")] |
|||
[Row(" 1.2 + 1i ; 3.4 + 1i ; 5.6 + 1i ", "1.2 + 1i;3.4 + 1i;5.6 + 1i", "de-CH")] |
|||
[Row(" 1,2 + 1i ; 3,4 + 1i ; 5,6 + 1i ", "1,2 + 1i;3,4 + 1i;5,6 + 1i", "de-DE")] |
|||
public void CanParseComplexDenseVectorsWithCulture(string stringToParse, string expectedToString, string culture) |
|||
{ |
|||
var formatProvider = CultureInfo.GetCultureInfo(culture); |
|||
DenseVector vector = DenseVector.Parse(stringToParse, formatProvider); |
|||
|
|||
Assert.AreEqual(expectedToString, vector.ToString(formatProvider)); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ParseThrowsFormatExceptionIfMissingClosingParen() |
|||
{ |
|||
Assert.Throws<FormatException>(() => DenseVector.Parse("(1")); |
|||
Assert.Throws<FormatException>(() => DenseVector.Parse("[1")); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(null)] |
|||
[Row("")] |
|||
[Row(",")] |
|||
[Row("1,")] |
|||
[Row(",1")] |
|||
[Row(",1,2,")] |
|||
[Row("1,,2,,3")] |
|||
[Row("1e+")] |
|||
[Row("1e")] |
|||
[Row("()")] |
|||
[Row("[ ]")]
|
|||
public void TryParseReturnsFalseWhenGivenBadValueWithInvariant(string str) |
|||
{ |
|||
DenseVector vector; |
|||
var ret = DenseVector.TryParse(str, CultureInfo.InvariantCulture, out vector); |
|||
Assert.IsFalse(ret); |
|||
Assert.IsNull(vector); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,291 @@ |
|||
// <copyright file="DenseVectorTests.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-2010 Math.NET
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
|
|||
public class DenseVectorTests : VectorTests |
|||
{ |
|||
protected override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new DenseVector(size); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(IList<Complex32> data) |
|||
{ |
|||
var vector = new DenseVector(data.Count); |
|||
for (var index = 0; index < data.Count; index++) |
|||
{ |
|||
vector[index] = data[index]; |
|||
} |
|||
|
|||
return vector; |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateDenseVectorFromArray() |
|||
{ |
|||
var data = new Complex32[Data.Length]; |
|||
Array.Copy(Data, data, Data.Length); |
|||
var vector = new DenseVector(data); |
|||
|
|||
Assert.AreSame(data, vector.Data); |
|||
for (var i = 0; i < data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(data[i], vector[i]); |
|||
} |
|||
|
|||
vector[0] = 100.0f; |
|||
AssertHelpers.AreEqual(100.0f, data[0]); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateDenseVectorFromAnotherDenseVector() |
|||
{ |
|||
var vector = new DenseVector(Data); |
|||
var other = new DenseVector(vector); |
|||
|
|||
Assert.AreNotSame(vector, other); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateDenseVectorFromAnotherVector() |
|||
{ |
|||
var vector = (Vector<Complex32>)new DenseVector(Data); |
|||
var other = new DenseVector(vector); |
|||
|
|||
Assert.AreNotSame(vector, other); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateDenseVectorFromUserDefinedVector() |
|||
{ |
|||
var vector = new UserDefinedVector(Data); |
|||
var other = new DenseVector(vector); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
Assert.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateDenseVectorWithConstantValues() |
|||
{ |
|||
var vector = new DenseVector(5, 5); |
|||
Assert.ForAll(vector, value => value == 5); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateDenseMatrix() |
|||
{ |
|||
var vector = new DenseVector(3); |
|||
var matrix = vector.CreateMatrix(2, 3); |
|||
Assert.AreEqual(2, matrix.RowCount); |
|||
Assert.AreEqual(3, matrix.ColumnCount); |
|||
} |
|||
|
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanConvertDenseVectorToArray() |
|||
{ |
|||
var vector = new DenseVector(Data); |
|||
var array = (Complex32[])vector; |
|||
Assert.IsInstanceOfType(typeof(Complex32[]), array); |
|||
Assert.AreSame(vector.Data, array); |
|||
Assert.AreElementsEqual(vector, array); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanConvertArrayToDenseVector() |
|||
{ |
|||
var array = new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1), new Complex32(4, 1) }; |
|||
var vector = (DenseVector)array; |
|||
Assert.IsInstanceOfType(typeof(DenseVector), vector); |
|||
Assert.AreElementsEqual(array, array); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCallUnaryPlusOperatorOnDenseVector() |
|||
{ |
|||
var vector = new DenseVector(Data); |
|||
var other = +vector; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanAddTwoDenseVectorsUsingOperator() |
|||
{ |
|||
var vector = new DenseVector(Data); |
|||
var other = new DenseVector(Data); |
|||
var result = vector + other; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCallUnaryNegationOperatorOnDenseVector() |
|||
{ |
|||
var vector = new DenseVector(Data); |
|||
var other = -vector; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(-Data[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanSubtractTwoDenseVectorsUsingOperator() |
|||
{ |
|||
var vector = new DenseVector(Data); |
|||
var other = new DenseVector(Data); |
|||
var result = vector - other; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(0.0f, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanMultiplyDenseVectorByComplexUsingOperators() |
|||
{ |
|||
var vector = new DenseVector(Data); |
|||
vector = vector * new Complex32(2.0f, 1); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
|
|||
vector = vector * 1.0f; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
|
|||
vector = new DenseVector(Data); |
|||
vector = new Complex32(2.0f, 1) * vector; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
|
|||
vector = 1.0f * vector; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanDivideDenseVectorByComplexUsingOperators() |
|||
{ |
|||
var vector = new DenseVector(Data); |
|||
vector = vector / new Complex32(2.0f, 1); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
|
|||
vector = vector / 1.0f; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCalculateOuterProductForDenseVector() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = CreateVector(Data); |
|||
Matrix<Complex32> m = Vector<Complex32>.OuterProduct(vector1, vector2); |
|||
for (var i = 0; i < vector1.Count; i++) |
|||
{ |
|||
for (var j = 0; j < vector2.Count; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(m[i, j], vector1[i] * vector2[j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void OuterProducForDenseVectortWithFirstParameterNullShouldThrowException() |
|||
{ |
|||
DenseVector vector1 = null; |
|||
var vector2 = CreateVector(Data); |
|||
Vector<Complex32>.OuterProduct(vector1, vector2); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void OuterProductForDenseVectorWithSecondParameterNullShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
DenseVector vector2 = null; |
|||
Vector<Complex32>.OuterProduct(vector1, vector2); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,452 @@ |
|||
// <copyright file="DiagonalMatrixTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Numerics; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32; |
|||
|
|||
public class DiagonalMatrixTests : MatrixTests |
|||
{ |
|||
[SetUp] |
|||
public override void SetupMatrices() |
|||
{ |
|||
TestData2D = new Dictionary<string, Complex32[,]> |
|||
{ |
|||
{ "Singular3x3", new [,] { { new Complex32(1.0f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, Complex32.Zero, Complex32.Zero }, { Complex32.Zero, Complex32.Zero, new Complex32(3.0f, 1) } } }, |
|||
{ "Square3x3", new [,] { { new Complex32(-1.1f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, new Complex32(1.1f, 1), Complex32.Zero }, { Complex32.Zero, Complex32.Zero, new Complex32(6.6f, 1) } } }, |
|||
{ "Square4x4", new [,] { { new Complex32(-1.1f, 1), Complex32.Zero, Complex32.Zero, Complex32.Zero }, { Complex32.Zero, new Complex32(1.1f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, Complex32.Zero, new Complex32(6.2f, 1), Complex32.Zero}, { Complex32.Zero, Complex32.Zero, Complex32.Zero, new Complex32(-7.7f, 1) } } }, |
|||
{ "Singular4x4", new [,] { { new Complex32(-1.1f, 1), Complex32.Zero, Complex32.Zero, Complex32.Zero }, { Complex32.Zero, new Complex32(-2.2f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, Complex32.Zero, Complex32.Zero, Complex32.Zero}, { Complex32.Zero, Complex32.Zero, Complex32.Zero, new Complex32(-4.4f, 1) } } }, |
|||
{ "Tall3x2", new [,] { { new Complex32(-1.1f, 1), Complex32.Zero }, { Complex32.Zero, new Complex32(1.1f, 1) }, { Complex32.Zero, Complex32.Zero } } }, |
|||
{ "Wide2x3", new [,] { { new Complex32(-1.1f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, new Complex32(1.1f, 1), Complex32.Zero } } } |
|||
}; |
|||
|
|||
TestMatrices = new Dictionary<string, Matrix<Complex32>>(); |
|||
foreach (var name in TestData2D.Keys) |
|||
{ |
|||
TestMatrices.Add(name, CreateMatrix(TestData2D[name])); |
|||
} |
|||
} |
|||
|
|||
protected override Matrix<Complex32> CreateMatrix(int rows, int columns) |
|||
{ |
|||
return new DiagonalMatrix(rows, columns); |
|||
} |
|||
|
|||
protected override Matrix<Complex32> CreateMatrix(Complex32[,] data) |
|||
{ |
|||
return new DiagonalMatrix(data); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new SparseVector(size); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(Complex32[] data) |
|||
{ |
|||
return new SparseVector(data); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateMatrixFromDiagonalArray() |
|||
{ |
|||
var testData = new Dictionary<string, Matrix<Complex32>> |
|||
{ |
|||
{ "Singular3x3", new DiagonalMatrix(3, 3, new[] { new Complex32(1.0f, 1), Complex32.Zero, new Complex32(3.0f, 1) }) }, |
|||
{ "Square3x3", new DiagonalMatrix(4, 4, new[] { new Complex32(-1.1f, 1), new Complex32(1.1f, 1), new Complex32(6.6f, 1) }) }, |
|||
{ "Square4x4", new DiagonalMatrix(4, 4, new[] { new Complex32(-1.1f, 1), new Complex32(1.1f, 1), new Complex32(6.2f, 1), new Complex32(-7.7f, 1) }) }, |
|||
{ "Tall3x2", new DiagonalMatrix(3, 2, new[] { new Complex32(-1.1f, 1), new Complex32(1.1f, 1) }) }, |
|||
{ "Wide2x3", new DiagonalMatrix(2, 3, new[] { new Complex32(-1.1f, 1), new Complex32(1.1f, 1) }) }, |
|||
}; |
|||
foreach (var name in testData.Keys) |
|||
{ |
|||
Assert.AreEqual(TestMatrices[name], testData[name]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void MatrixFrom1DArrayIsReference() |
|||
{ |
|||
var data = new[] { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1), new Complex32(4.0f, 1), new Complex32(5.0f, 1) }; |
|||
var matrix = new DiagonalMatrix(5, 5, data); |
|||
matrix[0, 0] = 10.0f; |
|||
Assert.AreEqual(10.0f, data[0]); |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3")] |
|||
[Row("Singular3x3")] |
|||
[Row("Square3x3")] |
|||
[Row("Square4x4")] |
|||
[Row("Tall3x2")] |
|||
[Row("Wide2x3")] |
|||
public void CanCreateMatrixFrom2DArray(string name) |
|||
{ |
|||
var matrix = new DiagonalMatrix(TestData2D[name]); |
|||
for (var i = 0; i < TestData2D[name].GetLength(0); i++) |
|||
{ |
|||
for (var j = 0; j < TestData2D[name].GetLength(1); j++) |
|||
{ |
|||
Assert.AreEqual(TestData2D[name][i, j], matrix[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateMatrixWithUniformValues() |
|||
{ |
|||
var matrix = new DiagonalMatrix(10, 10, 10.0f); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
Assert.AreEqual(matrix[i, i], 10.0f); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateIdentity() |
|||
{ |
|||
var matrix = DiagonalMatrix.Identity(5); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(i == j ? 1.0f : 0.0f, matrix[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(0)] |
|||
[Row(-1)] |
|||
[ExpectedArgumentException] |
|||
public void IdentityFailsWithZeroOrNegativeOrder(int order) |
|||
{ |
|||
DiagonalMatrix.Identity(order); |
|||
} |
|||
|
|||
[Test] |
|||
public override void CanDiagonallyStackMatricesWithPassingResult() |
|||
{ |
|||
var top = TestMatrices["Tall3x2"]; |
|||
var bottom = TestMatrices["Wide2x3"]; |
|||
var result = new SparseMatrix(top.RowCount + bottom.RowCount, top.ColumnCount + bottom.ColumnCount); |
|||
top.DiagonalStack(bottom, result); |
|||
Assert.AreEqual(top.RowCount + bottom.RowCount, result.RowCount); |
|||
Assert.AreEqual(top.ColumnCount + bottom.ColumnCount, result.ColumnCount); |
|||
|
|||
for (var i = 0; i < result.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < result.ColumnCount; j++) |
|||
{ |
|||
if (i < top.RowCount && j < top.ColumnCount) |
|||
{ |
|||
Assert.AreEqual(top[i, j], result[i, j]); |
|||
} |
|||
else if (i >= top.RowCount && j >= top.ColumnCount) |
|||
{ |
|||
Assert.AreEqual(bottom[i - top.RowCount, j - top.ColumnCount], result[i, j]); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreEqual(0, result[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void CanMultiplyMatrixWithMatrixIntoResult(string nameA, string nameB) |
|||
{ |
|||
var matrixA = TestMatrices[nameA]; |
|||
var matrixB = TestMatrices[nameB]; |
|||
var matrixC = new SparseMatrix(matrixA.RowCount, matrixB.ColumnCount); |
|||
matrixA.Multiply(matrixB, matrixC); |
|||
|
|||
Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); |
|||
Assert.AreEqual(matrixC.ColumnCount, matrixB.ColumnCount); |
|||
|
|||
for (var i = 0; i < matrixC.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixC.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Column(j), matrixC[i, j], 15); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3")] |
|||
[ExpectedException(typeof(InvalidOperationException))] |
|||
public void CanPermuteMatrixRowsThrowException(string name) |
|||
{ |
|||
var matrix = CreateMatrix(TestData2D[name]); |
|||
var matrixp = CreateMatrix(TestData2D[name]); |
|||
|
|||
var permutation = new Permutation(new[] { 2, 0, 1 }); |
|||
matrixp.PermuteRows(permutation); |
|||
|
|||
Assert.AreNotSame(matrix, matrixp); |
|||
Assert.AreEqual(matrix.RowCount, matrixp.RowCount); |
|||
Assert.AreEqual(matrix.ColumnCount, matrixp.ColumnCount); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrix[i, j], matrixp[permutation[i], j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3")] |
|||
[ExpectedException(typeof(InvalidOperationException))] |
|||
public void CanPermuteMatrixColumnsThrowException(string name) |
|||
{ |
|||
var matrix = CreateMatrix(TestData2D[name]); |
|||
var matrixp = CreateMatrix(TestData2D[name]); |
|||
|
|||
var permutation = new Permutation(new[] { 2, 0, 1 }); |
|||
matrixp.PermuteColumns(permutation); |
|||
|
|||
Assert.AreNotSame(matrix, matrixp); |
|||
Assert.AreEqual(matrix.RowCount, matrixp.RowCount); |
|||
Assert.AreEqual(matrix.ColumnCount, matrixp.ColumnCount); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrix[i, j], matrixp[i, permutation[j]]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void CanPermuteMatrixRows(string name) |
|||
{ |
|||
} |
|||
|
|||
public override void CanPermuteMatrixColumns(string name) |
|||
{ |
|||
} |
|||
|
|||
public override void PointwiseDivideResult() |
|||
{ |
|||
foreach (var data in TestMatrices.Values) |
|||
{ |
|||
var other = data.Clone(); |
|||
var result = data.Clone(); |
|||
data.PointwiseDivide(other, result); |
|||
var min = Math.Min(data.RowCount, data.ColumnCount); |
|||
for (var i = 0; i < min; i++) |
|||
{ |
|||
Assert.AreEqual((data[i, i] / other[i, i]).Real, result[i, i].Real); |
|||
Assert.AreEqual((data[i, i] / other[i, i]).Imaginary, result[i, i].Imaginary); |
|||
} |
|||
|
|||
result = data.PointwiseDivide(other); |
|||
for (var i = 0; i < min; i++) |
|||
{ |
|||
Assert.AreEqual((data[i, i] / other[i, i]).Real, result[i, i].Real); |
|||
Assert.AreEqual((data[i, i] / other[i, i]).Imaginary, result[i, i].Imaginary); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void SetColumnWithArray(string name, float[] column) |
|||
{ |
|||
try |
|||
{ |
|||
// Pass all invoke to base
|
|||
base.SetColumnWithArray(name, column); |
|||
} |
|||
catch(AggregateException ex) |
|||
{ |
|||
// Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature
|
|||
if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) |
|||
{ |
|||
throw; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void SetColumnWithVector(string name, float[] column) |
|||
{ |
|||
try |
|||
{ |
|||
// Pass all invoke to base
|
|||
base.SetColumnWithVector(name, column); |
|||
} |
|||
catch (AggregateException ex) |
|||
{ |
|||
// Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature
|
|||
if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) |
|||
{ |
|||
throw; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void SetRowWithArray(string name, float[] row) |
|||
{ |
|||
try |
|||
{ |
|||
// Pass all invoke to base
|
|||
base.SetRowWithArray(name, row); |
|||
} |
|||
catch (AggregateException ex) |
|||
{ |
|||
// Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature
|
|||
if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) |
|||
{ |
|||
throw; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void SetRowWithVector(string name, float[] row) |
|||
{ |
|||
try |
|||
{ |
|||
// Pass all invoke to base
|
|||
base.SetRowWithVector(name, row); |
|||
} |
|||
catch (AggregateException ex) |
|||
{ |
|||
// Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature
|
|||
if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) |
|||
{ |
|||
throw; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void SetSubMatrix(int rowStart, int rowLength, int colStart, int colLength) |
|||
{ |
|||
try |
|||
{ |
|||
// Pass all invoke to base
|
|||
base.SetSubMatrix(rowStart, rowLength, colStart, colLength); |
|||
} |
|||
catch (AggregateException ex) |
|||
{ |
|||
// Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature
|
|||
if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) |
|||
{ |
|||
throw; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void FrobeniusNorm() |
|||
{ |
|||
var matrix = TestMatrices["Square3x3"]; |
|||
var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 7); |
|||
|
|||
matrix = TestMatrices["Wide2x3"]; |
|||
denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 7); |
|||
|
|||
matrix = TestMatrices["Tall3x2"]; |
|||
denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 7); |
|||
} |
|||
|
|||
public override void InfinityNorm() |
|||
{ |
|||
var matrix = TestMatrices["Square3x3"]; |
|||
var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 7); |
|||
|
|||
matrix = TestMatrices["Wide2x3"]; |
|||
denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 7); |
|||
|
|||
matrix = TestMatrices["Tall3x2"]; |
|||
denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 7); |
|||
} |
|||
|
|||
public override void L1Norm() |
|||
{ |
|||
var matrix = TestMatrices["Square3x3"]; |
|||
var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 7); |
|||
|
|||
matrix = TestMatrices["Wide2x3"]; |
|||
denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 7); |
|||
|
|||
matrix = TestMatrices["Tall3x2"]; |
|||
denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 7); |
|||
} |
|||
|
|||
public override void L2Norm() |
|||
{ |
|||
var matrix = TestMatrices["Square3x3"]; |
|||
var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 7); |
|||
|
|||
matrix = TestMatrices["Wide2x3"]; |
|||
denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 7); |
|||
|
|||
matrix = TestMatrices["Tall3x2"]; |
|||
denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 7); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Determinant() |
|||
{ |
|||
var matrix = TestMatrices["Square3x3"]; |
|||
var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.Determinant(), matrix.Determinant(), 7); |
|||
|
|||
matrix = TestMatrices["Square4x4"]; |
|||
denseMatrix = new DenseMatrix(TestData2D["Square4x4"]); |
|||
AssertHelpers.AlmostEqual(denseMatrix.Determinant(), matrix.Determinant(), 7); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void DeterminantNotSquareMatrixThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Tall3x2"]; |
|||
matrix.Determinant(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,305 @@ |
|||
// <copyright file="CholeskyTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization |
|||
{ |
|||
using LinearAlgebra.Generic.Factorization; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32; |
|||
|
|||
public class CholeskyTests |
|||
{ |
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void CanFactorizeIdentity(int order) |
|||
{ |
|||
var I = DenseMatrix.Identity(order); |
|||
var factorC = I.Cholesky(); |
|||
|
|||
Assert.AreEqual(I.RowCount, factorC.Factor.RowCount); |
|||
Assert.AreEqual(I.ColumnCount, factorC.Factor.ColumnCount); |
|||
|
|||
for (var i = 0; i < factorC.Factor.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorC.Factor.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(i == j ? 1.0f : 0.0f, factorC.Factor[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void CholeskyFailsWithDiagonalNonPositiveDefiniteMatrix() |
|||
{ |
|||
var I = DenseMatrix.Identity(10); |
|||
I[3, 3] = -4.0f; |
|||
I.Cholesky(); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(3,5)] |
|||
[Row(5,3)] |
|||
[ExpectedArgumentException] |
|||
public void CholeskyFailsWithNonSquareMatrix(int row, int col) |
|||
{ |
|||
var I = new DenseMatrix(row, col); |
|||
I.Cholesky(); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void IdentityDeterminantIsOne(int order) |
|||
{ |
|||
var I = DenseMatrix.Identity(order); |
|||
var factorC = I.Cholesky(); |
|||
Assert.AreEqual(1.0f, factorC.Determinant); |
|||
Assert.AreEqual(0.0f, factorC.DeterminantLn); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanFactorizeRandomMatrix(int order) |
|||
{ |
|||
var matrixX = MatrixLoader.GenerateRandomPositiveDefiniteHermitianDenseMatrix(order); |
|||
var chol = matrixX.Cholesky(); |
|||
var factorC = chol.Factor; |
|||
|
|||
// Make sure the Cholesky factor has the right dimensions.
|
|||
Assert.AreEqual(order, factorC.RowCount); |
|||
Assert.AreEqual(order, factorC.ColumnCount); |
|||
|
|||
// Make sure the Cholesky factor is lower triangular.
|
|||
for (var i = 0; i < factorC.RowCount; i++) |
|||
{ |
|||
for (var j = i+1; j < factorC.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(0.0f, factorC[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure the cholesky factor times it's transpose is the original matrix.
|
|||
var matrixXfromC = factorC * factorC.ConjugateTranspose(); |
|||
for (var i = 0; i < matrixXfromC.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixXfromC.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixX[i,j].Real, matrixXfromC[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixX[i, j].Imaginary, matrixXfromC[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianDenseMatrix(order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var chol = matrixA.Cholesky(); |
|||
var b = MatrixLoader.GenerateRandomDenseVector(order); |
|||
var x = chol.Solve(b); |
|||
|
|||
Assert.AreEqual(b.Count, x.Count); |
|||
|
|||
var bReconstruct = matrixA * x; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(b[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(b[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1,1)] |
|||
[Row(2,4)] |
|||
[Row(5,8)] |
|||
[Row(10,3)] |
|||
[Row(50,10)] |
|||
[Row(100,100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int row, int col) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianDenseMatrix(row); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var chol = matrixA.Cholesky(); |
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(row, col); |
|||
var matrixX = chol.Solve(matrixB); |
|||
|
|||
Assert.AreEqual(matrixB.RowCount, matrixX.RowCount); |
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVectorWhenResultVectorGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianDenseMatrix(order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var chol = matrixA.Cholesky(); |
|||
var b = MatrixLoader.GenerateRandomDenseVector(order); |
|||
var bCopy = b.Clone(); |
|||
var x = new DenseVector(order); |
|||
chol.Solve(b, x); |
|||
|
|||
Assert.AreEqual(b.Count, x.Count); |
|||
|
|||
var bReconstruct = matrixA * x; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(b[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(b[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure b didn't change.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreEqual(bCopy[i], b[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(2, 4)] |
|||
[Row(5, 8)] |
|||
[Row(10, 3)] |
|||
[Row(50, 10)] |
|||
[Row(100, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrixWhenResultMatrixGiven(int row, int col) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianDenseMatrix(row); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var chol = matrixA.Cholesky(); |
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(row, col); |
|||
var matrixBCopy = matrixB.Clone(); |
|||
var matrixX = new DenseMatrix(row, col); |
|||
chol.Solve(matrixB, matrixX); |
|||
|
|||
Assert.AreEqual(matrixB.RowCount, matrixX.RowCount); |
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure B didn't change.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,356 @@ |
|||
// <copyright file="GramSchmidtTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization |
|||
{ |
|||
using LinearAlgebra.Generic.Factorization; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32.Factorization; |
|||
|
|||
public class GramSchmidtTests |
|||
{ |
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void ConstructorNull() |
|||
{ |
|||
new GramSchmidt(null); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void WideMatrixThrowsInvalidMatrixOperationException() |
|||
{ |
|||
new GramSchmidt(new UserDefinedMatrix(3, 4)); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void CanFactorizeIdentity(int order) |
|||
{ |
|||
var I = UserDefinedMatrix.Identity(order); |
|||
var factorGramSchmidt = I.GramSchmidt(); |
|||
|
|||
Assert.AreEqual(I.RowCount, factorGramSchmidt.Q.RowCount); |
|||
Assert.AreEqual(I.ColumnCount, factorGramSchmidt.Q.ColumnCount); |
|||
|
|||
for (var i = 0; i < factorGramSchmidt.R.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorGramSchmidt.R.ColumnCount; j++) |
|||
{ |
|||
if (i == j) |
|||
{ |
|||
Assert.AreEqual(1.0f, factorGramSchmidt.R[i, j]); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreEqual(0.0f, factorGramSchmidt.R[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (var i = 0; i < factorGramSchmidt.Q.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorGramSchmidt.Q.ColumnCount; j++) |
|||
{ |
|||
if (i == j) |
|||
{ |
|||
Assert.AreEqual(1.0f, factorGramSchmidt.Q[i, j]); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreEqual(0.0f, factorGramSchmidt.Q[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void IdentityDeterminantIsOne(int order) |
|||
{ |
|||
var I = UserDefinedMatrix.Identity(order); |
|||
var factorGramSchmidt = I.GramSchmidt(); |
|||
Assert.AreEqual(1.0f, factorGramSchmidt.Determinant); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1,1)] |
|||
[Row(2,2)] |
|||
[Row(5,5)] |
|||
[Row(10,6)] |
|||
[Row(50,48)] |
|||
[Row(100,98)] |
|||
[MultipleAsserts] |
|||
public void CanFactorizeRandomMatrix(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column); |
|||
var factorGramSchmidt = matrixA.GramSchmidt(); |
|||
|
|||
// Make sure the Q has the right dimensions.
|
|||
Assert.AreEqual(row, factorGramSchmidt.Q.RowCount); |
|||
Assert.AreEqual(column, factorGramSchmidt.Q.ColumnCount); |
|||
|
|||
// Make sure the R has the right dimensions.
|
|||
Assert.AreEqual(column, factorGramSchmidt.R.RowCount); |
|||
Assert.AreEqual(column, factorGramSchmidt.R.ColumnCount); |
|||
|
|||
// Make sure the R factor is upper triangular.
|
|||
for (var i = 0; i < factorGramSchmidt.R.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorGramSchmidt.R.ColumnCount; j++) |
|||
{ |
|||
if (i > j) |
|||
{ |
|||
Assert.AreEqual(0.0f, factorGramSchmidt.R[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Make sure the Q*R is the original matrix.
|
|||
var matrixQfromR = factorGramSchmidt.Q * factorGramSchmidt.R; |
|||
for (var i = 0; i < matrixQfromR.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixQfromR.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Real, matrixQfromR[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Imaginary, matrixQfromR[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure the Q is unitary --> (Q*)x(Q) = I
|
|||
var matrixQсtQ = factorGramSchmidt.Q.ConjugateTranspose() * factorGramSchmidt.Q; |
|||
for (var i = 0; i < matrixQсtQ.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixQсtQ.ColumnCount; j++) |
|||
{ |
|||
if (i == j) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Real, 1.0f, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Real, 0.0f, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorGramSchmidt = matrixA.GramSchmidt(); |
|||
|
|||
var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order); |
|||
var resultx = factorGramSchmidt.Solve(vectorb); |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorGramSchmidt = matrixA.GramSchmidt(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixX = factorGramSchmidt.Solve(matrixB); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVectorWhenResultVectorGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorGramSchmidt = matrixA.GramSchmidt(); |
|||
var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order); |
|||
var vectorbCopy = vectorb.Clone(); |
|||
var resultx = new UserDefinedVector(order); |
|||
factorGramSchmidt.Solve(vectorb,resultx); |
|||
|
|||
Assert.AreEqual(vectorb.Count, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure b didn't change.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreEqual(vectorbCopy[i], vectorb[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrixWhenResultMatrixGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorGramSchmidt = matrixA.GramSchmidt(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixBCopy = matrixB.Clone(); |
|||
|
|||
var matrixX = new UserDefinedMatrix(order, order); |
|||
factorGramSchmidt.Solve(matrixB,matrixX); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure B didn't change.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,371 @@ |
|||
// <copyright file="LUTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Generic.Factorization; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32; |
|||
|
|||
public class LUTests |
|||
{ |
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void CanFactorizeIdentity(int order) |
|||
{ |
|||
var matrixI = DenseMatrix.Identity(order); |
|||
var factorLU = matrixI.LU(); |
|||
|
|||
// Check lower triangular part.
|
|||
var matrixL = factorLU.L; |
|||
Assert.AreEqual(matrixI.RowCount, matrixL.RowCount); |
|||
Assert.AreEqual(matrixI.ColumnCount, matrixL.ColumnCount); |
|||
for (var i = 0; i < matrixL.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixL.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(i == j ? Complex32.One : Complex32.Zero, matrixL[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Check upper triangular part.
|
|||
var matrixU = factorLU.U; |
|||
Assert.AreEqual(matrixI.RowCount, matrixU.RowCount); |
|||
Assert.AreEqual(matrixI.ColumnCount, matrixU.ColumnCount); |
|||
for (var i = 0; i < matrixU.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixU.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(i == j ? Complex32.One : Complex32.Zero, matrixU[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(3,5)] |
|||
[Row(5,3)] |
|||
[ExpectedArgumentException] |
|||
public void LUFailsWithNonSquareMatrix(int row, int col) |
|||
{ |
|||
var I = new DenseMatrix(row, col); |
|||
I.LU(); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void IdentityDeterminantIsOne(int order) |
|||
{ |
|||
var I = DenseMatrix.Identity(order); |
|||
var lu = I.LU(); |
|||
Assert.AreEqual(Complex32.One, lu.Determinant); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanFactorizeRandomMatrix(int order) |
|||
{ |
|||
var matrixX = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var factorLU = matrixX.LU(); |
|||
var matrixL = factorLU.L; |
|||
var matrixU = factorLU.U; |
|||
|
|||
// Make sure the factors have the right dimensions.
|
|||
Assert.AreEqual(order, matrixL.RowCount); |
|||
Assert.AreEqual(order, matrixL.ColumnCount); |
|||
Assert.AreEqual(order, matrixU.RowCount); |
|||
Assert.AreEqual(order, matrixU.ColumnCount); |
|||
|
|||
// Make sure the L factor is lower triangular.
|
|||
for (var i = 0; i < matrixL.RowCount; i++) |
|||
{ |
|||
Assert.AreEqual(1.0f, matrixL[i, i]); |
|||
for (var j = i+1; j < matrixL.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(0.0f, matrixL[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure the U factor is upper triangular.
|
|||
for (var i = 0; i < matrixL.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < i; j++) |
|||
{ |
|||
Assert.AreEqual(0.0f, matrixU[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure the LU factor times it's transpose is the original matrix.
|
|||
var matrixXfromLU = matrixL * matrixU; |
|||
var permutationInverse = factorLU.P.Inverse(); |
|||
matrixXfromLU.PermuteRows(permutationInverse); |
|||
for (var i = 0; i < matrixXfromLU.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixXfromLU.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixX[i, j].Real, matrixXfromLU[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixX[i, j].Imaginary, matrixXfromLU[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
|
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(order); |
|||
var resultx = factorLU.Solve(vectorb); |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixX = factorLU.Solve(matrixB); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVectorWhenResultVectorGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(order); |
|||
var vectorbCopy = vectorb.Clone(); |
|||
var resultx = new DenseVector(order); |
|||
factorLU.Solve(vectorb, resultx); |
|||
|
|||
Assert.AreEqual(vectorb.Count, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure b didn't change.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreEqual(vectorbCopy[i], vectorb[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrixWhenResultMatrixGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixBCopy = matrixB.Clone(); |
|||
|
|||
var matrixX = new DenseMatrix(order, order); |
|||
factorLU.Solve(matrixB, matrixX); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure B didn't change.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanInverse(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
|
|||
var matrixAInverse = factorLU.Inverse(); |
|||
|
|||
// The inverse dimension is equal A
|
|||
Assert.AreEqual(matrixAInverse.RowCount, matrixAInverse.RowCount); |
|||
Assert.AreEqual(matrixAInverse.ColumnCount, matrixAInverse.ColumnCount); |
|||
|
|||
var matrixIdentity = matrixA * matrixAInverse; |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Check if multiplication of A and AI produced identity matrix.
|
|||
for (var i = 0; i < matrixIdentity.RowCount; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixIdentity[i, i].Real, Complex32.One.Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixIdentity[i, i].Imaginary, Complex32.One.Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,343 @@ |
|||
// <copyright file="QRTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Generic.Factorization; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Factorization; |
|||
|
|||
public class QRTests |
|||
{ |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void ConstructorNull() |
|||
{ |
|||
new DenseQR(null); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void WideMatrixThrowsInvalidMatrixOperationException() |
|||
{ |
|||
new DenseQR(new DenseMatrix(3, 4)); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void CanFactorizeIdentity(int order) |
|||
{ |
|||
var I = DenseMatrix.Identity(order); |
|||
var factorQR = I.QR(); |
|||
|
|||
Assert.AreEqual(I.RowCount, factorQR.R.RowCount); |
|||
Assert.AreEqual(I.ColumnCount, factorQR.R.ColumnCount); |
|||
|
|||
for (var i = 0; i < factorQR.R.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorQR.R.ColumnCount; j++) |
|||
{ |
|||
if (i == j) |
|||
{ |
|||
Assert.AreEqual(-Complex32.One, factorQR.R[i, j]); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreEqual(Complex32.Zero, factorQR.R[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void IdentityDeterminantIsOne(int order) |
|||
{ |
|||
var I = DenseMatrix.Identity(order); |
|||
var factorQR = I.QR(); |
|||
Assert.AreEqual(1.0f, factorQR.Determinant); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1,1)] |
|||
[Row(2,2)] |
|||
[Row(5,5)] |
|||
[Row(10,6)] |
|||
[Row(50,48)] |
|||
[Row(100,98)] |
|||
[MultipleAsserts] |
|||
public void CanFactorizeRandomMatrix(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column); |
|||
var factorQR = matrixA.QR(); |
|||
|
|||
// Make sure the R has the right dimensions.
|
|||
Assert.AreEqual(row, factorQR.R.RowCount); |
|||
Assert.AreEqual(column, factorQR.R.ColumnCount); |
|||
|
|||
// Make sure the Q has the right dimensions.
|
|||
Assert.AreEqual(row, factorQR.Q.RowCount); |
|||
Assert.AreEqual(row, factorQR.Q.ColumnCount); |
|||
|
|||
// Make sure the R factor is upper triangular.
|
|||
for (var i = 0; i < factorQR.R.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorQR.R.ColumnCount; j++) |
|||
{ |
|||
if (i > j) |
|||
{ |
|||
Assert.AreEqual(Complex32.Zero, factorQR.R[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Make sure the Q*R is the original matrix.
|
|||
var matrixQfromR = factorQR.Q * factorQR.R; |
|||
for (var i = 0; i < matrixQfromR.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixQfromR.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Real, matrixQfromR[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Imaginary, matrixQfromR[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure the Q is unitary --> (Q*)x(Q) = I
|
|||
var matrixQсtQ = factorQR.Q.ConjugateTranspose() * factorQR.Q; |
|||
for (var i = 0; i < matrixQсtQ.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixQсtQ.ColumnCount; j++) |
|||
{ |
|||
if (i == j) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Real, 1.0f, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Real, 0.0f, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorQR = matrixA.QR(); |
|||
|
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(order); |
|||
var resultx = factorQR.Solve(vectorb); |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorQR = matrixA.QR(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixX = factorQR.Solve(matrixB); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVectorWhenResultVectorGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorQR = matrixA.QR(); |
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(order); |
|||
var vectorbCopy = vectorb.Clone(); |
|||
var resultx = new DenseVector(order); |
|||
factorQR.Solve(vectorb,resultx); |
|||
|
|||
Assert.AreEqual(vectorb.Count, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure b didn't change.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreEqual(vectorbCopy[i], vectorb[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrixWhenResultMatrixGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorQR = matrixA.QR(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixBCopy = matrixB.Clone(); |
|||
|
|||
var matrixX = new DenseMatrix(order, order); |
|||
factorQR.Solve(matrixB,matrixX); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure B didn't change.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,376 @@ |
|||
// <copyright file="SvdTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using LinearAlgebra.Generic.Factorization; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Factorization; |
|||
|
|||
public class SvdTests |
|||
{ |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void ConstructorNull() |
|||
{ |
|||
new DenseSvd(null, true); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void CanFactorizeIdentity(int order) |
|||
{ |
|||
var I = DenseMatrix.Identity(order); |
|||
var factorSvd = I.Svd(true); |
|||
|
|||
Assert.AreEqual(I.RowCount, factorSvd.U().RowCount); |
|||
Assert.AreEqual(I.RowCount, factorSvd.U().ColumnCount); |
|||
|
|||
Assert.AreEqual(I.ColumnCount, factorSvd.VT().RowCount); |
|||
Assert.AreEqual(I.ColumnCount, factorSvd.VT().ColumnCount); |
|||
|
|||
Assert.AreEqual(I.RowCount, factorSvd.W().RowCount); |
|||
Assert.AreEqual(I.ColumnCount, factorSvd.W().ColumnCount); |
|||
|
|||
for (var i = 0; i < factorSvd.W().RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorSvd.W().ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(i == j ? 1.0f : 0.0f, factorSvd.W()[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1,1)] |
|||
[Row(2,2)] |
|||
[Row(5,5)] |
|||
[Row(10,6)] |
|||
[Row(48,52)] |
|||
[Row(100,93)] |
|||
[MultipleAsserts] |
|||
public void CanFactorizeRandomMatrix(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
// Make sure the U has the right dimensions.
|
|||
Assert.AreEqual(row, factorSvd.U().RowCount); |
|||
Assert.AreEqual(row, factorSvd.U().ColumnCount); |
|||
|
|||
// Make sure the VT has the right dimensions.
|
|||
Assert.AreEqual(column, factorSvd.VT().RowCount); |
|||
Assert.AreEqual(column, factorSvd.VT().ColumnCount); |
|||
|
|||
// Make sure the W has the right dimensions.
|
|||
Assert.AreEqual(row, factorSvd.W().RowCount); |
|||
Assert.AreEqual(column, factorSvd.W().ColumnCount); |
|||
|
|||
// Make sure the U*W*VT is the original matrix.
|
|||
var matrix = factorSvd.U() * factorSvd.W() * factorSvd.VT(); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Real, matrix[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Imaginary, matrix[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(10, 8)] |
|||
[Row(48, 52)] |
|||
[Row(100, 93)] |
|||
[MultipleAsserts] |
|||
public void CheckRankOfNonSquare(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
var mn = Math.Min(row, column); |
|||
Assert.AreEqual(factorSvd.Rank, mn); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(9)] |
|||
[Row(50)] |
|||
[Row(90)] |
|||
[MultipleAsserts] |
|||
public void CheckRankSquare(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
if (factorSvd.Determinant != 0) |
|||
{ |
|||
Assert.AreEqual(factorSvd.Rank, order); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreEqual(factorSvd.Rank, order - 1); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CheckRankOfSquareSingular(int order) |
|||
{ |
|||
var matrixA = new DenseMatrix(order, order); |
|||
matrixA[0, 0] = 1; |
|||
matrixA[order - 1, order - 1] = 1; |
|||
for (var i = 1; i < order - 1; i++) |
|||
{ |
|||
matrixA[i, i - 1] = 1; |
|||
matrixA[i, i + 1] = 1; |
|||
matrixA[i - 1, i] = 1; |
|||
matrixA[i + 1, i] = 1; |
|||
} |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
Assert.AreEqual(factorSvd.Determinant, 0); |
|||
Assert.AreEqual(factorSvd.Rank, order - 1); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(InvalidOperationException))] |
|||
public void CannotSolveMatrixIfVectorsNotComputed() |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(10, 10); |
|||
var factorSvd = matrixA.Svd(false); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(10, 10); |
|||
factorSvd.Solve(matrixB); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(InvalidOperationException))] |
|||
public void CannotSolveVectorIfVectorsNotComputed() |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(10, 10); |
|||
var factorSvd = matrixA.Svd(false); |
|||
|
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(10); |
|||
factorSvd.Solve(vectorb); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(2, 2)] |
|||
[Row(5, 5)] |
|||
[Row(9, 10)] |
|||
[Row(50, 50)] |
|||
[Row(90, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(row); |
|||
var resultx = factorSvd.Solve(vectorb); |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(4, 4)] |
|||
[Row(7, 8)] |
|||
[Row(10, 10)] |
|||
[Row(45, 50)] |
|||
[Row(80, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int row, int count) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, count); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(row, count); |
|||
var matrixX = factorSvd.Solve(matrixB); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(2, 2)] |
|||
[Row(5, 5)] |
|||
[Row(9, 10)] |
|||
[Row(50, 50)] |
|||
[Row(90, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVectorWhenResultVectorGiven(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorSvd = matrixA.Svd(true); |
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(row); |
|||
var vectorbCopy = vectorb.Clone(); |
|||
var resultx = new DenseVector(column); |
|||
factorSvd.Solve(vectorb,resultx); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure b didn't change.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreEqual(vectorbCopy[i], vectorb[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(4, 4)] |
|||
[Row(7, 8)] |
|||
[Row(10, 10)] |
|||
[Row(45, 50)] |
|||
[Row(80, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrixWhenResultMatrixGiven(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(row, column); |
|||
var matrixBCopy = matrixB.Clone(); |
|||
|
|||
var matrixX = new DenseMatrix(column, column); |
|||
factorSvd.Solve(matrixB,matrixX); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure B didn't change.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,304 @@ |
|||
// <copyright file="UserCholeskyTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization |
|||
{ |
|||
using LinearAlgebra.Generic.Factorization; |
|||
using MbUnit.Framework; |
|||
|
|||
public class UserCholeskyTests |
|||
{ |
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void CanFactorizeIdentity(int order) |
|||
{ |
|||
var I = UserDefinedMatrix.Identity(order); |
|||
var factorC = I.Cholesky(); |
|||
|
|||
Assert.AreEqual(I.RowCount, factorC.Factor.RowCount); |
|||
Assert.AreEqual(I.ColumnCount, factorC.Factor.ColumnCount); |
|||
|
|||
for (var i = 0; i < factorC.Factor.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorC.Factor.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(i == j ? 1.0f : 0.0f, factorC.Factor[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void CholeskyFailsWithDiagonalNonPositiveDefiniteMatrix() |
|||
{ |
|||
var I = UserDefinedMatrix.Identity(10); |
|||
I[3, 3] = -4.0f; |
|||
I.Cholesky(); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(3,5)] |
|||
[Row(5,3)] |
|||
[ExpectedArgumentException] |
|||
public void CholeskyFailsWithNonSquareMatrix(int row, int col) |
|||
{ |
|||
var I = new UserDefinedMatrix(row, col); |
|||
I.Cholesky(); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void IdentityDeterminantIsOne(int order) |
|||
{ |
|||
var I = UserDefinedMatrix.Identity(order); |
|||
var factorC = I.Cholesky(); |
|||
Assert.AreEqual(1.0f, factorC.Determinant); |
|||
Assert.AreEqual(0.0f, factorC.DeterminantLn); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanFactorizeRandomMatrix(int order) |
|||
{ |
|||
var matrixX = MatrixLoader.GenerateRandomPositiveDefiniteHermitianUserDefinedMatrix(order); |
|||
var chol = matrixX.Cholesky(); |
|||
var factorC = chol.Factor; |
|||
|
|||
// Make sure the Cholesky factor has the right dimensions.
|
|||
Assert.AreEqual(order, factorC.RowCount); |
|||
Assert.AreEqual(order, factorC.ColumnCount); |
|||
|
|||
// Make sure the Cholesky factor is lower triangular.
|
|||
for (var i = 0; i < factorC.RowCount; i++) |
|||
{ |
|||
for (var j = i+1; j < factorC.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(0.0f, factorC[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure the cholesky factor times it's conjugate transpose is the original matrix.
|
|||
var matrixXfromC = factorC * factorC.ConjugateTranspose(); |
|||
for (var i = 0; i < matrixXfromC.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixXfromC.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixX[i,j].Real, matrixXfromC[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixX[i, j].Imaginary, matrixXfromC[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianUserDefinedMatrix(order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var chol = matrixA.Cholesky(); |
|||
var b = MatrixLoader.GenerateRandomUserDefinedVector(order); |
|||
var x = chol.Solve(b); |
|||
|
|||
Assert.AreEqual(b.Count, x.Count); |
|||
|
|||
var bReconstruct = matrixA * x; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(b[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(b[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1,1)] |
|||
[Row(2,4)] |
|||
[Row(5,8)] |
|||
[Row(10,3)] |
|||
[Row(50,10)] |
|||
[Row(100,100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int row, int col) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianUserDefinedMatrix(row); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var chol = matrixA.Cholesky(); |
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(row, col); |
|||
var matrixX = chol.Solve(matrixB); |
|||
|
|||
Assert.AreEqual(matrixB.RowCount, matrixX.RowCount); |
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVectorWhenResultVectorGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianUserDefinedMatrix(order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var chol = matrixA.Cholesky(); |
|||
var b = MatrixLoader.GenerateRandomUserDefinedVector(order); |
|||
var bCopy = b.Clone(); |
|||
var x = new UserDefinedVector(order); |
|||
chol.Solve(b, x); |
|||
|
|||
Assert.AreEqual(b.Count, x.Count); |
|||
|
|||
var bReconstruct = matrixA * x; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(b[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(b[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure b didn't change.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreEqual(bCopy[i], b[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(2, 4)] |
|||
[Row(5, 8)] |
|||
[Row(10, 3)] |
|||
[Row(50, 10)] |
|||
[Row(100, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrixWhenResultMatrixGiven(int row, int col) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianUserDefinedMatrix(row); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var chol = matrixA.Cholesky(); |
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(row, col); |
|||
var matrixBCopy = matrixB.Clone(); |
|||
var matrixX = new UserDefinedMatrix(row, col); |
|||
chol.Solve(matrixB, matrixX); |
|||
|
|||
Assert.AreEqual(matrixB.RowCount, matrixX.RowCount); |
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure B didn't change.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,370 @@ |
|||
// <copyright file="UserLUTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Generic.Factorization; |
|||
using MbUnit.Framework; |
|||
|
|||
public class UserLUTests |
|||
{ |
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void CanFactorizeIdentity(int order) |
|||
{ |
|||
var matrixI = UserDefinedMatrix.Identity(order); |
|||
var factorLU = matrixI.LU(); |
|||
|
|||
// Check lower triangular part.
|
|||
var matrixL = factorLU.L; |
|||
Assert.AreEqual(matrixI.RowCount, matrixL.RowCount); |
|||
Assert.AreEqual(matrixI.ColumnCount, matrixL.ColumnCount); |
|||
for (var i = 0; i < matrixL.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixL.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(i == j ? Complex32.One : Complex32.Zero, matrixL[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Check upper triangular part.
|
|||
var matrixU = factorLU.U; |
|||
Assert.AreEqual(matrixI.RowCount, matrixU.RowCount); |
|||
Assert.AreEqual(matrixI.ColumnCount, matrixU.ColumnCount); |
|||
for (var i = 0; i < matrixU.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixU.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(i == j ? Complex32.One : Complex32.Zero, matrixU[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(3,5)] |
|||
[Row(5,3)] |
|||
[ExpectedArgumentException] |
|||
public void LUFailsWithNonSquareMatrix(int row, int col) |
|||
{ |
|||
var I = new UserDefinedMatrix(row, col); |
|||
I.LU(); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void IdentityDeterminantIsOne(int order) |
|||
{ |
|||
var I = UserDefinedMatrix.Identity(order); |
|||
var lu = I.LU(); |
|||
Assert.AreEqual(Complex32.One, lu.Determinant); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanFactorizeRandomMatrix(int order) |
|||
{ |
|||
var matrixX = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var factorLU = matrixX.LU(); |
|||
var matrixL = factorLU.L; |
|||
var matrixU = factorLU.U; |
|||
|
|||
// Make sure the factors have the right dimensions.
|
|||
Assert.AreEqual(order, matrixL.RowCount); |
|||
Assert.AreEqual(order, matrixL.ColumnCount); |
|||
Assert.AreEqual(order, matrixU.RowCount); |
|||
Assert.AreEqual(order, matrixU.ColumnCount); |
|||
|
|||
// Make sure the L factor is lower triangular.
|
|||
for (var i = 0; i < matrixL.RowCount; i++) |
|||
{ |
|||
Assert.AreEqual(1.0f, matrixL[i, i]); |
|||
for (var j = i+1; j < matrixL.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(Complex32.Zero, matrixL[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure the U factor is upper triangular.
|
|||
for (var i = 0; i < matrixL.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < i; j++) |
|||
{ |
|||
Assert.AreEqual(Complex32.Zero, matrixU[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure the LU factor times it's transpose is the original matrix.
|
|||
var matrixXfromLU = matrixL * matrixU; |
|||
var permutationInverse = factorLU.P.Inverse(); |
|||
matrixXfromLU.PermuteRows(permutationInverse); |
|||
for (var i = 0; i < matrixXfromLU.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixXfromLU.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixX[i, j].Real, matrixXfromLU[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixX[i, j].Imaginary, matrixXfromLU[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
|
|||
var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order); |
|||
var resultx = factorLU.Solve(vectorb); |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixX = factorLU.Solve(matrixB); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVectorWhenResultVectorGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order); |
|||
var vectorbCopy = vectorb.Clone(); |
|||
var resultx = new UserDefinedVector(order); |
|||
factorLU.Solve(vectorb, resultx); |
|||
|
|||
Assert.AreEqual(vectorb.Count, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure b didn't change.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreEqual(vectorbCopy[i], vectorb[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrixWhenResultMatrixGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixBCopy = matrixB.Clone(); |
|||
|
|||
var matrixX = new UserDefinedMatrix(order, order); |
|||
factorLU.Solve(matrixB, matrixX); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure B didn't change.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanInverse(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorLU = matrixA.LU(); |
|||
|
|||
var matrixAInverse = factorLU.Inverse(); |
|||
|
|||
// The inverse dimension is equal A
|
|||
Assert.AreEqual(matrixAInverse.RowCount, matrixAInverse.RowCount); |
|||
Assert.AreEqual(matrixAInverse.ColumnCount, matrixAInverse.ColumnCount); |
|||
|
|||
var matrixIdentity = matrixA * matrixAInverse; |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Check if multiplication of A and AI produced identity matrix.
|
|||
for (var i = 0; i < matrixIdentity.RowCount; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixIdentity[i, i].Real, Complex32.One.Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixIdentity[i, i].Imaginary, Complex32.One.Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,341 @@ |
|||
// <copyright file="UserQRTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization |
|||
{ |
|||
using LinearAlgebra.Generic.Factorization; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32.Factorization; |
|||
|
|||
public class UserQRTests |
|||
{ |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void ConstructorNull() |
|||
{ |
|||
new UserQR(null); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void WideMatrixThrowsInvalidMatrixOperationException() |
|||
{ |
|||
new UserQR(new UserDefinedMatrix(3, 4)); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void CanFactorizeIdentity(int order) |
|||
{ |
|||
var I = UserDefinedMatrix.Identity(order); |
|||
var factorQR = I.QR(); |
|||
|
|||
Assert.AreEqual(I.RowCount, factorQR.R.RowCount); |
|||
Assert.AreEqual(I.ColumnCount, factorQR.R.ColumnCount); |
|||
|
|||
for (var i = 0; i < factorQR.R.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorQR.R.ColumnCount; j++) |
|||
{ |
|||
if (i == j) |
|||
{ |
|||
Assert.AreEqual(-1.0f, factorQR.R[i, j]); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreEqual(0.0f, factorQR.R[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void IdentityDeterminantIsOne(int order) |
|||
{ |
|||
var I = UserDefinedMatrix.Identity(order); |
|||
var factorQR = I.QR(); |
|||
Assert.AreEqual(1.0f, factorQR.Determinant); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1,1)] |
|||
[Row(2,2)] |
|||
[Row(5,5)] |
|||
[Row(10,6)] |
|||
[Row(50,48)] |
|||
[Row(100,98)] |
|||
[MultipleAsserts] |
|||
public void CanFactorizeRandomMatrix(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column); |
|||
var factorQR = matrixA.QR(); |
|||
|
|||
// Make sure the R has the right dimensions.
|
|||
Assert.AreEqual(row, factorQR.R.RowCount); |
|||
Assert.AreEqual(column, factorQR.R.ColumnCount); |
|||
|
|||
// Make sure the Q has the right dimensions.
|
|||
Assert.AreEqual(row, factorQR.Q.RowCount); |
|||
Assert.AreEqual(row, factorQR.Q.ColumnCount); |
|||
|
|||
// Make sure the R factor is upper triangular.
|
|||
for (var i = 0; i < factorQR.R.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorQR.R.ColumnCount; j++) |
|||
{ |
|||
if (i > j) |
|||
{ |
|||
Assert.AreEqual(0.0f, factorQR.R[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Make sure the Q*R is the original matrix.
|
|||
var matrixQfromR = factorQR.Q * factorQR.R; |
|||
for (var i = 0; i < matrixQfromR.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixQfromR.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Real, matrixQfromR[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Imaginary, matrixQfromR[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure the Q is unitary --> (Q*)x(Q) = I
|
|||
var matrixQсtQ = factorQR.Q.ConjugateTranspose() * factorQR.Q; |
|||
for (var i = 0; i < matrixQсtQ.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixQсtQ.ColumnCount; j++) |
|||
{ |
|||
if (i == j) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Real, 1.0f, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Real, 0.0f, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorQR = matrixA.QR(); |
|||
|
|||
var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order); |
|||
var resultx = factorQR.Solve(vectorb); |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorQR = matrixA.QR(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixX = factorQR.Solve(matrixB); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVectorWhenResultVectorGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorQR = matrixA.QR(); |
|||
var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order); |
|||
var vectorbCopy = vectorb.Clone(); |
|||
var resultx = new UserDefinedVector(order); |
|||
factorQR.Solve(vectorb,resultx); |
|||
|
|||
Assert.AreEqual(vectorb.Count, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure b didn't change.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreEqual(vectorbCopy[i], vectorb[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(4)] |
|||
[Row(8)] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrixWhenResultMatrixGiven(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorQR = matrixA.QR(); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var matrixBCopy = matrixB.Clone(); |
|||
|
|||
var matrixX = new UserDefinedMatrix(order, order); |
|||
factorQR.Solve(matrixB,matrixX); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure B didn't change.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,376 @@ |
|||
// <copyright file="UserSvdTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using LinearAlgebra.Generic.Factorization; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32.Factorization; |
|||
|
|||
public class UserSvdTests |
|||
{ |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void ConstructorNull() |
|||
{ |
|||
new UserSvd(null, true); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(10)] |
|||
[Row(100)] |
|||
public void CanFactorizeIdentity(int order) |
|||
{ |
|||
var I = UserDefinedMatrix.Identity(order); |
|||
var factorSvd = I.Svd(true); |
|||
|
|||
Assert.AreEqual(I.RowCount, factorSvd.U().RowCount); |
|||
Assert.AreEqual(I.RowCount, factorSvd.U().ColumnCount); |
|||
|
|||
Assert.AreEqual(I.ColumnCount, factorSvd.VT().RowCount); |
|||
Assert.AreEqual(I.ColumnCount, factorSvd.VT().ColumnCount); |
|||
|
|||
Assert.AreEqual(I.RowCount, factorSvd.W().RowCount); |
|||
Assert.AreEqual(I.ColumnCount, factorSvd.W().ColumnCount); |
|||
|
|||
for (var i = 0; i < factorSvd.W().RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < factorSvd.W().ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(i == j ? Complex32.One : Complex32.Zero, factorSvd.W()[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1,1)] |
|||
[Row(2,2)] |
|||
[Row(5,5)] |
|||
[Row(10,6)] |
|||
[Row(48,52)] |
|||
[Row(100,93)] |
|||
[MultipleAsserts] |
|||
public void CanFactorizeRandomMatrix(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
// Make sure the U has the right dimensions.
|
|||
Assert.AreEqual(row, factorSvd.U().RowCount); |
|||
Assert.AreEqual(row, factorSvd.U().ColumnCount); |
|||
|
|||
// Make sure the VT has the right dimensions.
|
|||
Assert.AreEqual(column, factorSvd.VT().RowCount); |
|||
Assert.AreEqual(column, factorSvd.VT().ColumnCount); |
|||
|
|||
// Make sure the W has the right dimensions.
|
|||
Assert.AreEqual(row, factorSvd.W().RowCount); |
|||
Assert.AreEqual(column, factorSvd.W().ColumnCount); |
|||
|
|||
// Make sure the U*W*VT is the original matrix.
|
|||
var matrix = factorSvd.U() * factorSvd.W() * factorSvd.VT(); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Real, matrix[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixA[i, j].Imaginary, matrix[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(10, 8)] |
|||
[Row(48, 52)] |
|||
[Row(100, 93)] |
|||
[MultipleAsserts] |
|||
public void CheckRankOfNonSquare(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
var mn = Math.Min(row, column); |
|||
Assert.AreEqual(factorSvd.Rank, mn); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(5)] |
|||
[Row(9)] |
|||
[Row(50)] |
|||
[Row(90)] |
|||
[MultipleAsserts] |
|||
public void CheckRankSquare(int order) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
if (factorSvd.Determinant != 0) |
|||
{ |
|||
Assert.AreEqual(factorSvd.Rank, order); |
|||
} |
|||
else |
|||
{ |
|||
Assert.AreEqual(factorSvd.Rank, order - 1); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(10)] |
|||
[Row(50)] |
|||
[Row(100)] |
|||
[MultipleAsserts] |
|||
public void CheckRankOfSquareSingular(int order) |
|||
{ |
|||
var matrixA = new UserDefinedMatrix(order, order); |
|||
matrixA[0, 0] = 1; |
|||
matrixA[order - 1, order - 1] = 1; |
|||
for (var i = 1; i < order - 1; i++) |
|||
{ |
|||
matrixA[i, i - 1] = 1; |
|||
matrixA[i, i + 1] = 1; |
|||
matrixA[i - 1, i] = 1; |
|||
matrixA[i + 1, i] = 1; |
|||
} |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
Assert.AreEqual(factorSvd.Determinant, 0); |
|||
Assert.AreEqual(factorSvd.Rank, order - 1); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(InvalidOperationException))] |
|||
public void CannotSolveMatrixIfVectorsNotComputed() |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(10, 10); |
|||
var factorSvd = matrixA.Svd(false); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(10, 10); |
|||
factorSvd.Solve(matrixB); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(InvalidOperationException))] |
|||
public void CannotSolveVectorIfVectorsNotComputed() |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(10, 10); |
|||
var factorSvd = matrixA.Svd(false); |
|||
|
|||
var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(10); |
|||
factorSvd.Solve(vectorb); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(2, 2)] |
|||
[Row(5, 5)] |
|||
[Row(9, 10)] |
|||
[Row(50, 50)] |
|||
[Row(90, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(row); |
|||
var resultx = factorSvd.Solve(vectorb); |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(4, 4)] |
|||
[Row(7, 8)] |
|||
[Row(10, 10)] |
|||
[Row(45, 50)] |
|||
[Row(80, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int row, int count) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, count); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(row, count); |
|||
var matrixX = factorSvd.Solve(matrixB); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(2, 2)] |
|||
[Row(5, 5)] |
|||
[Row(9, 10)] |
|||
[Row(50, 50)] |
|||
[Row(90, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVectorWhenResultVectorGiven(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorSvd = matrixA.Svd(true); |
|||
var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(row); |
|||
var vectorbCopy = vectorb.Clone(); |
|||
var resultx = new UserDefinedVector(column); |
|||
factorSvd.Solve(vectorb,resultx); |
|||
|
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, 1e-3f); |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure b didn't change.
|
|||
for (var i = 0; i < vectorb.Count; i++) |
|||
{ |
|||
Assert.AreEqual(vectorbCopy[i], vectorb[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 1)] |
|||
[Row(4, 4)] |
|||
[Row(7, 8)] |
|||
[Row(10, 10)] |
|||
[Row(45, 50)] |
|||
[Row(80, 100)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrixWhenResultMatrixGiven(int row, int column) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column); |
|||
var matrixACopy = matrixA.Clone(); |
|||
var factorSvd = matrixA.Svd(true); |
|||
|
|||
var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column); |
|||
var matrixBCopy = matrixB.Clone(); |
|||
|
|||
var matrixX = new UserDefinedMatrix(column, column); |
|||
factorSvd.Solve(matrixB,matrixX); |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f); |
|||
} |
|||
} |
|||
|
|||
// Make sure A didn't change.
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); |
|||
} |
|||
} |
|||
|
|||
// Make sure B didn't change.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,184 @@ |
|||
// <copyright file="MatrixLoader.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System.Collections.Generic; |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
|
|||
public abstract class MatrixLoader |
|||
{ |
|||
protected Dictionary<string, Complex32[,]> TestData2D; |
|||
protected Dictionary<string, Matrix<Complex32>> TestMatrices; |
|||
|
|||
protected abstract Matrix<Complex32> CreateMatrix(int rows, int columns); |
|||
protected abstract Matrix<Complex32> CreateMatrix(Complex32[,] data); |
|||
protected abstract Vector<Complex32> CreateVector(int size); |
|||
protected abstract Vector<Complex32> CreateVector(Complex32[] data); |
|||
|
|||
[SetUp] |
|||
public virtual void SetupMatrices() |
|||
{ |
|||
TestData2D = new Dictionary<string, Complex32[,]> |
|||
{ |
|||
{ "Singular3x3", new[,] { { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(2.0f, 1) }, { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(2.0f, 1) }, { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(2.0f, 1) } } }, |
|||
{ "Square3x3", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1) }, { Complex32.Zero, new Complex32(1.1f, 1), new Complex32(2.2f, 1) }, { new Complex32(-4.4f, 1), new Complex32(5.5f, 1), new Complex32(6.6f, 1) } } }, |
|||
{ "Square4x4", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1), new Complex32(-4.4f, 1) }, { Complex32.Zero, new Complex32(1.1f, 1), new Complex32(2.2f, 1), new Complex32(3.3f, 1) }, { new Complex32(1.0f, 1), new Complex32(2.1f, 1), new Complex32(6.2f, 1), new Complex32(4.3f, 1) }, { new Complex32(-4.4f, 1), new Complex32(5.5f, 1), new Complex32(6.6f, 1), new Complex32(-7.7f, 1) } } }, |
|||
{ "Singular4x4", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1), new Complex32(-4.4f, 1) }, { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1), new Complex32(-4.4f, 1) }, { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1), new Complex32(-4.4f, 1) }, { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1), new Complex32(-4.4f, 1) } } }, |
|||
{ "Tall3x2", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1) }, { Complex32.Zero, new Complex32(1.1f, 1) }, { new Complex32(-4.4f, 1), new Complex32(5.5f, 1) } } }, |
|||
{ "Wide2x3", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1) }, { Complex32.Zero, new Complex32(1.1f, 1), new Complex32(2.2f, 1) } } }, |
|||
}; |
|||
|
|||
TestMatrices = new Dictionary<string, Matrix<Complex32>>(); |
|||
foreach (var name in TestData2D.Keys) |
|||
{ |
|||
TestMatrices.Add(name, CreateMatrix(TestData2D[name])); |
|||
} |
|||
} |
|||
|
|||
public static Matrix<Complex32> GenerateRandomDenseMatrix(int row, int col) |
|||
{ |
|||
// Fill a matrix with standard random numbers.
|
|||
var normal = new Distributions.Normal |
|||
{ |
|||
RandomSource = new Random.MersenneTwister(1) |
|||
}; |
|||
var matrixA = new DenseMatrix(row, col); |
|||
for (var i = 0; i < row; i++) |
|||
{ |
|||
for (var j = 0; j < col; j++) |
|||
{ |
|||
matrixA[i, j] = new Complex32((float)normal.Sample(), (float)normal.Sample()); |
|||
} |
|||
} |
|||
|
|||
// Generate a matrix which is positive definite.
|
|||
return matrixA; |
|||
} |
|||
|
|||
public static Matrix<Complex32> GenerateRandomPositiveDefiniteHermitianDenseMatrix(int order) |
|||
{ |
|||
// Fill a matrix with standard random numbers.
|
|||
var normal = new Distributions.Normal |
|||
{ |
|||
RandomSource = new Random.MersenneTwister(1) |
|||
}; |
|||
var matrixA = new DenseMatrix(order); |
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
for (var j = 0; j < order; j++) |
|||
{ |
|||
matrixA[i, j] = new Complex32((float)normal.Sample(), (float)normal.Sample()); |
|||
} |
|||
} |
|||
|
|||
// Generate a Hermitian matrix which is positive definite.
|
|||
return matrixA.ConjugateTranspose() * matrixA; |
|||
} |
|||
|
|||
public static Vector<Complex32> GenerateRandomDenseVector(int order) |
|||
{ |
|||
// Fill a matrix with standard random numbers.
|
|||
var normal = new Distributions.Normal |
|||
{ |
|||
RandomSource = new Random.MersenneTwister(1) |
|||
}; |
|||
var v = new DenseVector(order); |
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
v[i] = new Complex32((float)normal.Sample(), (float)normal.Sample()); |
|||
} |
|||
|
|||
// Generate a matrix which is positive definite.
|
|||
return v; |
|||
} |
|||
|
|||
public static Matrix<Complex32> GenerateRandomUserDefinedMatrix(int row, int col) |
|||
{ |
|||
// Fill a matrix with standard random numbers.
|
|||
var normal = new Distributions.Normal |
|||
{ |
|||
RandomSource = new Random.MersenneTwister(1) |
|||
}; |
|||
var matrixA = new UserDefinedMatrix(row, col); |
|||
for (var i = 0; i < row; i++) |
|||
{ |
|||
for (var j = 0; j < col; j++) |
|||
{ |
|||
matrixA[i, j] = new Complex32((float)normal.Sample(), (float)normal.Sample()); |
|||
} |
|||
} |
|||
|
|||
// Generate a matrix which is positive definite.
|
|||
return matrixA; |
|||
} |
|||
|
|||
public static Matrix<Complex32> GenerateRandomPositiveDefiniteHermitianUserDefinedMatrix(int order) |
|||
{ |
|||
// Fill a matrix with standard random numbers.
|
|||
var normal = new Distributions.Normal |
|||
{ |
|||
RandomSource = new Random.MersenneTwister(1) |
|||
}; |
|||
var matrixA = new UserDefinedMatrix(order); |
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
for (var j = 0; j < order; j++) |
|||
{ |
|||
matrixA[i, j] = new Complex32((float)normal.Sample(), (float)normal.Sample()); |
|||
} |
|||
} |
|||
|
|||
// Generate a Hermitian matrix which is positive definite.
|
|||
return matrixA.ConjugateTranspose() * matrixA; |
|||
} |
|||
|
|||
public static Vector<Complex32> GenerateRandomUserDefinedVector(int order) |
|||
{ |
|||
// Fill a matrix with standard random numbers.
|
|||
var normal = new Distributions.Normal |
|||
{ |
|||
RandomSource = new Random.MersenneTwister(1) |
|||
}; |
|||
var v = new UserDefinedVector(order); |
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
v[i] = new Complex32((float)normal.Sample(), (float)normal.Sample()); |
|||
} |
|||
|
|||
// Generate a matrix which is positive definite.
|
|||
return v; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,894 @@ |
|||
// <copyright file="MatrixTests.Arithmetic.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-2010 Math.NET
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using Distributions; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
|
|||
public abstract partial class MatrixTests |
|||
{ |
|||
[Test] |
|||
[Row(1.0f, 1.0f)] |
|||
[Row(2.0f, 1.0f)] |
|||
[Row(2.2f, 1.0f)] |
|||
[MultipleAsserts] |
|||
public void CanMultiplyWithComplex(float real, float imaginary) |
|||
{ |
|||
var value = new Complex32(real, imaginary); |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var clone = matrix.Clone(); |
|||
clone.Multiply(value); |
|||
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(matrix[i, j] * value, clone[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanMultiplyWithVector() |
|||
{ |
|||
var matrixA = TestMatrices["Singular3x3"]; |
|||
var x = new DenseVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1) }); |
|||
var y = matrixA * x; |
|||
|
|||
Assert.AreEqual(matrixA.RowCount, y.Count); |
|||
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
var ar = matrixA.Row(i); |
|||
var dot = ar * x; |
|||
AssertHelpers.AreEqual(dot, y[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanMultiplyWithVectorIntoResult() |
|||
{ |
|||
var matrixA = TestMatrices["Singular3x3"]; |
|||
var x = new DenseVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1) }); |
|||
var y = new DenseVector(3); |
|||
matrixA.Multiply(x, y); |
|||
|
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
var ar = matrixA.Row(i); |
|||
var dot = ar * x; |
|||
AssertHelpers.AreEqual(dot, y[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanMultiplyWithVectorIntoResultWhenUpdatingInputArgument() |
|||
{ |
|||
var matrixA = TestMatrices["Singular3x3"]; |
|||
var x = new DenseVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1) }); |
|||
var y = x; |
|||
matrixA.Multiply(x, x); |
|||
|
|||
Assert.AreSame(y, x); |
|||
|
|||
y = new DenseVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1) }); |
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
var ar = matrixA.Row(i); |
|||
var dot = ar * y; |
|||
AssertHelpers.AreEqual(dot, x[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void MultiplyWithVectorIntoResultFailsWhenResultIsNull() |
|||
{ |
|||
var matrixA = TestMatrices["Singular3x3"]; |
|||
var x = new DenseVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1) }); |
|||
Vector<Complex32> y = null; |
|||
matrixA.Multiply(x, y); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void MultiplyWithVectorIntoResultFailsWhenResultIsTooLarge() |
|||
{ |
|||
var matrixA = TestMatrices["Singular3x3"]; |
|||
var x = new DenseVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1) }); |
|||
Vector<Complex32> y = new DenseVector(4); |
|||
matrixA.Multiply(x, y); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1.0, 1.0)] |
|||
[Row(2.0, 1.0)] |
|||
[Row(2.2, 1.0)] |
|||
[MultipleAsserts] |
|||
public void CanOperatorLeftMultiplyWithComplex(float real, float imaginary) |
|||
{ |
|||
var value = new Complex32(real, imaginary); |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var clone = matrix * value; |
|||
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(matrix[i, j] * value, clone[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1.0, 1.0)] |
|||
[Row(2.0, 1.0)] |
|||
[Row(2.2, 1.0)] |
|||
[MultipleAsserts] |
|||
public void CanOperatorRightMultiplyWithComplex(float real, float imaginary) |
|||
{ |
|||
var value = new Complex32(real, imaginary); |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var clone = matrix * value; |
|||
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(matrix[i, j] * value, clone[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1.0, 1.0)] |
|||
[Row(2.0, 1.0)] |
|||
[Row(2.2, 1.0)] |
|||
[MultipleAsserts] |
|||
public void CanMultiplyWithComplexIntoResult(float real, float imaginary) |
|||
{ |
|||
var value = new Complex32(real, imaginary); |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var result = matrix.Clone(); |
|||
matrix.Multiply(value, result); |
|||
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(matrix[i, j] * value, result[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void MultiplyWithComplexIntoResultFailsWhenResultIsNull() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
Matrix<Complex32> result = null; |
|||
matrix.Multiply(2.3f, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void MultiplyWithComplexFailsWhenResultHasMoreRows() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var result = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); |
|||
matrix.Multiply(2.3f, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void MultiplyWithComplexFailsWhenResultHasMoreColumns() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var result = CreateMatrix(matrix.RowCount, matrix.ColumnCount + 1); |
|||
matrix.Multiply(2.3f, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void OperatorLeftMultiplyWithComplexFailsWhenMatrixIsNull() |
|||
{ |
|||
Matrix<Complex32> matrix = null; |
|||
var result = 2.3f * matrix; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void OperatorRightMultiplyWithComplexFailsWhenMatrixIsNull() |
|||
{ |
|||
Matrix<Complex32> matrix = null; |
|||
var result = matrix * 2.3f; |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3", "Square3x3")] |
|||
[Row("Singular4x4", "Square4x4")] |
|||
public void CanAddMatrix(string mtxA, string mtxB) |
|||
{ |
|||
var matrixA = TestMatrices[mtxA]; |
|||
var matrixB = TestMatrices[mtxB]; |
|||
|
|||
var matrix = matrixA.Clone(); |
|||
matrix.Add(matrixB); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(matrix[i, j], matrixA[i, j] + matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void AddMatrixThrowsExceptionWhenArgumentIsNull() |
|||
{ |
|||
var matrix = TestMatrices["Singular4x4"]; |
|||
Matrix<Complex32> other = null; |
|||
matrix.Add(other); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentOutOfRangeException))] |
|||
public void AddMatrixThrowsExceptionArgumentHasTooFewColumns() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Tall3x2"]; |
|||
matrix.Add(other); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentOutOfRangeException))] |
|||
public void AddMatrixThrowsExceptionArgumentHasTooFewRows() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Wide2x3"]; |
|||
matrix.Add(other); |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3", "Square3x3")] |
|||
[Row("Singular4x4", "Square4x4")] |
|||
public void AddOperator(string mtxA, string mtxB) |
|||
{ |
|||
var matrixA = TestMatrices[mtxA]; |
|||
var matrixB = TestMatrices[mtxB]; |
|||
|
|||
var result = matrixA + matrixB; |
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(result[i, j], matrixA[i, j] + matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void AddOperatorThrowsExceptionWhenLeftsideIsNull() |
|||
{ |
|||
Matrix<Complex32> matrix = null; |
|||
var other = TestMatrices["Singular3x3"]; |
|||
var result = matrix + other; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void AddOperatorThrowsExceptionWhenRightsideIsNull() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
Matrix<Complex32> other = null; |
|||
var result = matrix + other; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentOutOfRangeException))] |
|||
public void AddOperatorThrowsExceptionWhenRightsideHasTooFewColumns() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Tall3x2"]; |
|||
var result = matrix + other; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentOutOfRangeException))] |
|||
public void AddOperatorThrowsExceptionWhenRightsideHasTooFewRows() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Wide2x3"]; |
|||
var result = matrix + other; |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3", "Square3x3")] |
|||
[Row("Singular4x4", "Square4x4")] |
|||
public void CanSubtractMatrix(string mtxA, string mtxB) |
|||
{ |
|||
var matrixA = TestMatrices[mtxA]; |
|||
var matrixB = TestMatrices[mtxB]; |
|||
|
|||
var matrix = matrixA.Clone(); |
|||
matrix.Subtract(matrixB); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(matrix[i, j], matrixA[i, j] - matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void SubtractMatrixThrowsExceptionWhenRightSideIsNull() |
|||
{ |
|||
var matrix = TestMatrices["Singular4x4"]; |
|||
Matrix<Complex32> other = null; |
|||
matrix.Subtract(other); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentOutOfRangeException))] |
|||
public void SubtractMatrixThrowsExceptionWhenRightSideHasTooFewColumns() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Tall3x2"]; |
|||
matrix.Subtract(other); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentOutOfRangeException))] |
|||
public void SubtractMatrixThrowsExceptionWhenRightSideHasTooFewRows() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Wide2x3"]; |
|||
matrix.Subtract(other); |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3", "Square3x3")] |
|||
[Row("Singular4x4", "Square4x4")] |
|||
public void SubtractOperator(string mtxA, string mtxB) |
|||
{ |
|||
var matrixA = TestMatrices[mtxA]; |
|||
var matrixB = TestMatrices[mtxB]; |
|||
|
|||
var result = matrixA - matrixB; |
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(result[i, j], matrixA[i, j] - matrixB[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void SubtractOperatorThrowsExceptionWhenLeftsideIsNull() |
|||
{ |
|||
Matrix<Complex32> matrix = null; |
|||
var other = TestMatrices["Singular3x3"]; |
|||
var result = matrix - other; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void SubtractOperatorThrowsExceptionWhenRightsideIsNull() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
Matrix<Complex32> other = null; |
|||
var result = matrix - other; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentOutOfRangeException))] |
|||
public void SubtractOperatorThrowsExceptionWhenRightsideHasTooFewColumns() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Tall3x2"]; |
|||
var result = matrix - other; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentOutOfRangeException))] |
|||
public void SubtractOperatorThrowsExceptionWhenRightsideHasTooFewRows() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Wide2x3"]; |
|||
var result = matrix - other; |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3", "Square3x3")] |
|||
[Row("Singular4x4", "Square4x4")] |
|||
[Row("Wide2x3", "Square3x3")] |
|||
[Row("Wide2x3", "Tall3x2")] |
|||
[Row("Tall3x2", "Wide2x3")] |
|||
[MultipleAsserts] |
|||
public void CanMultiplyMatrixWithMatrix(string nameA, string nameB) |
|||
{ |
|||
var matrixA = TestMatrices[nameA]; |
|||
var matrixB = TestMatrices[nameB]; |
|||
var matrixC = matrixA * matrixB; |
|||
|
|||
Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); |
|||
Assert.AreEqual(matrixC.ColumnCount, matrixB.ColumnCount); |
|||
|
|||
for (var i = 0; i < matrixC.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixC.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Column(j), matrixC[i, j], 15); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3")] |
|||
[Row("Singular4x4")] |
|||
[Row("Wide2x3")] |
|||
[Row("Tall3x2")] |
|||
[MultipleAsserts] |
|||
public void CanTransposeAndMultiplyMatrixWithMatrix(string nameA) |
|||
{ |
|||
var matrixA = TestMatrices[nameA]; |
|||
var matrixB = TestMatrices[nameA]; |
|||
var matrixC = matrixA.TransposeAndMultiply(matrixB); |
|||
|
|||
Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); |
|||
Assert.AreEqual(matrixC.ColumnCount, matrixB.RowCount); |
|||
|
|||
for (var i = 0; i < matrixC.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixC.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Row(j), matrixC[i, j], 15); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentException))] |
|||
public void TransposeAndMultiplyMatrixMatrixFailsWhenSizesAreIncompatible() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Tall3x2"]; |
|||
var result = matrix.TransposeAndMultiply(other); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void TransposeAndMultiplyMatrixMatrixFailsWhenRightArgumentIsNull() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
Matrix<Complex32> other = null; |
|||
var result = matrix.TransposeAndMultiply(other); |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3")] |
|||
[Row("Singular4x4")] |
|||
[Row("Wide2x3")] |
|||
[Row("Wide2x3")] |
|||
[Row("Tall3x2")] |
|||
[MultipleAsserts] |
|||
public void CanTransposeAndMultiplyMatrixWithMatrixIntoResult(string nameA) |
|||
{ |
|||
var matrixA = TestMatrices[nameA]; |
|||
var matrixB = TestMatrices[nameA]; |
|||
var matrixC = CreateMatrix(matrixA.RowCount, matrixB.RowCount); |
|||
matrixA.TransposeAndMultiply(matrixB, matrixC); |
|||
|
|||
Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); |
|||
Assert.AreEqual(matrixC.ColumnCount, matrixB.RowCount); |
|||
|
|||
for (var i = 0; i < matrixC.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixC.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Row(j), matrixC[i, j], 15); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentException))] |
|||
public void MultiplyMatrixMatrixFailsWhenSizesAreIncompatible() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var other = TestMatrices["Wide2x3"]; |
|||
var result = matrix * other; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void MultiplyMatrixMatrixFailsWhenLeftArgumentIsNull() |
|||
{ |
|||
Matrix<Complex32> matrix = null; |
|||
var other = TestMatrices["Wide2x3"]; |
|||
var result = matrix * other; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void MultiplyMatrixMatrixFailsWhenRightArgumentIsNull() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
Matrix<Complex32> other = null; |
|||
var result = matrix * other; |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3", "Square3x3")] |
|||
[Row("Singular4x4", "Square4x4")] |
|||
[Row("Wide2x3", "Square3x3")] |
|||
[Row("Wide2x3", "Tall3x2")] |
|||
[Row("Tall3x2", "Wide2x3")] |
|||
[MultipleAsserts] |
|||
public virtual void CanMultiplyMatrixWithMatrixIntoResult(string nameA, string nameB) |
|||
{ |
|||
var matrixA = TestMatrices[nameA]; |
|||
var matrixB = TestMatrices[nameB]; |
|||
var matrixC = CreateMatrix(matrixA.RowCount, matrixB.ColumnCount); |
|||
matrixA.Multiply(matrixB, matrixC); |
|||
|
|||
Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); |
|||
Assert.AreEqual(matrixC.ColumnCount, matrixB.ColumnCount); |
|||
|
|||
for (var i = 0; i < matrixC.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixC.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Column(j), matrixC[i, j], 15); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3")] |
|||
[Row("Square3x3")] |
|||
[Row("Square4x4")] |
|||
[Row("Tall3x2")] |
|||
[Row("Wide2x3")] |
|||
[MultipleAsserts] |
|||
public void CanNegate(string name) |
|||
{ |
|||
var matrix = TestMatrices[name]; |
|||
var copy = matrix.Clone(); |
|||
|
|||
copy.Negate(); |
|||
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(-matrix[i, j], copy[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3")] |
|||
[Row("Square3x3")] |
|||
[Row("Square4x4")] |
|||
[Row("Tall3x2")] |
|||
[Row("Wide2x3")] |
|||
[MultipleAsserts] |
|||
public void CanNegateIntoResult(string name) |
|||
{ |
|||
var matrix = TestMatrices[name]; |
|||
var copy = matrix.Clone(); |
|||
|
|||
matrix.Negate(copy); |
|||
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(-matrix[i, j], copy[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void NegateIntoResultFailsWhenResultIsNull() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
Matrix<Complex32> copy = null; |
|||
matrix.Negate(copy); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void NegateIntoResultFailsWhenResultHasMoreRows() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var target = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); |
|||
matrix.Negate(target); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void NegateIntoResultFailsWhenResultHasMoreColumns() |
|||
{ |
|||
var matrix = TestMatrices["Singular3x3"]; |
|||
var target = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); |
|||
matrix.Negate(target); |
|||
} |
|||
|
|||
|
|||
[Test] |
|||
public void KroneckerProduct() |
|||
{ |
|||
var matrixA = TestMatrices["Wide2x3"]; |
|||
var matrixB = TestMatrices["Square3x3"]; |
|||
var result = CreateMatrix(matrixA.RowCount * matrixB.RowCount, matrixA.ColumnCount * matrixB.ColumnCount); |
|||
matrixA.KroneckerProduct(matrixB, result); |
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
for (var ii = 0; ii < matrixB.RowCount; ii++) |
|||
{ |
|||
for (var jj = 0; jj < matrixB.ColumnCount; jj++) |
|||
{ |
|||
AssertHelpers.AreEqual(result[i * matrixB.RowCount + ii, j * matrixB.ColumnCount + jj], matrixA[i, j] * matrixB[ii, jj]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void KroneckerProductResult() |
|||
{ |
|||
var matrixA = TestMatrices["Wide2x3"]; |
|||
var matrixB = TestMatrices["Square3x3"]; |
|||
var result = matrixA.KroneckerProduct(matrixB); |
|||
for (var i = 0; i < matrixA.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixA.ColumnCount; j++) |
|||
{ |
|||
for (var ii = 0; ii < matrixB.RowCount; ii++) |
|||
{ |
|||
for (var jj = 0; jj < matrixB.ColumnCount; jj++) |
|||
{ |
|||
AssertHelpers.AreEqual(result[i * matrixB.RowCount + ii, j * matrixB.ColumnCount + jj], matrixA[i, j] * matrixB[ii, jj]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(-4, ExpectedException = typeof(ArgumentOutOfRangeException))] |
|||
public void NormalizeColumns(int pValue) |
|||
{ |
|||
var matrix = TestMatrices["Square4x4"]; |
|||
|
|||
var result = matrix.NormalizeColumns(pValue); |
|||
for (var j = 0; j < result.ColumnCount; j++) |
|||
{ |
|||
var col = result.Column(j); |
|||
AssertHelpers.AlmostEqual(Complex32.One, (float)col.Norm(pValue), 6); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1)] |
|||
[Row(2)] |
|||
[Row(-3, ExpectedException = typeof(ArgumentOutOfRangeException))] |
|||
public void NormalizeRows(int pValue) |
|||
{ |
|||
var matrix = TestMatrices["Square4x4"].NormalizeRows(pValue); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
var row = matrix.Row(i); |
|||
AssertHelpers.AlmostEqual(Complex32.One, (float)row.Norm(pValue), 6); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void PointwiseMultiplyResult() |
|||
{ |
|||
foreach (var data in TestMatrices.Values) |
|||
{ |
|||
var other = data.Clone(); |
|||
var result = data.Clone(); |
|||
data.PointwiseMultiply(other, result); |
|||
for (var i = 0; i < data.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < data.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(data[i, j] * other[i, j], result[i, j]); |
|||
} |
|||
} |
|||
|
|||
result = data.PointwiseMultiply(other); |
|||
for (var i = 0; i < data.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < data.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(data[i, j] * other[i, j], result[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void PointwiseMultiplyWithNullOtherShouldThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
Matrix<Complex32> other = null; |
|||
var result = matrix.Clone(); |
|||
matrix.PointwiseMultiply(other, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void PointwiseMultiplyWithResultNullShouldThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
var other = matrix.Clone(); |
|||
matrix.PointwiseMultiply(other, null); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentException))] |
|||
public void PointwiseMultiplyWithInvalidOtherMatrixDimensionsShouldThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
var other = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); |
|||
var result = matrix.Clone(); |
|||
matrix.PointwiseMultiply(other, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentException))] |
|||
public void PointwiseMultiplyWithInvalidResultMatrixDimensionsShouldThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
var other = matrix.Clone(); |
|||
var result = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); |
|||
matrix.PointwiseMultiply(other, result); |
|||
} |
|||
|
|||
[Test] |
|||
public virtual void PointwiseDivideResult() |
|||
{ |
|||
foreach (var data in TestMatrices.Values) |
|||
{ |
|||
var other = data.Clone(); |
|||
var result = data.Clone(); |
|||
data.PointwiseDivide(other, result); |
|||
for (var i = 0; i < data.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < data.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(data[i, j] / other[i, j], result[i, j]); |
|||
} |
|||
} |
|||
|
|||
result = data.PointwiseDivide(other); |
|||
for (var i = 0; i < data.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < data.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(data[i, j] / other[i, j], result[i, j]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void PointwiseDivideWithNullOtherShouldThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
Matrix<Complex32> other = null; |
|||
var result = matrix.Clone(); |
|||
matrix.PointwiseDivide(other, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentNullException))] |
|||
public void PointwiseDivideWithResultNullShouldThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
var other = matrix.Clone(); |
|||
matrix.PointwiseDivide(other, null); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentException))] |
|||
public void PointwiseDivideWithInvalidOtherMatrixDimensionsShouldThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
var other = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); |
|||
var result = matrix.Clone(); |
|||
matrix.PointwiseDivide(other, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentException))] |
|||
public void PointwiseDivideWithInvalidResultMatrixDimensionsShouldThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
var other = matrix.Clone(); |
|||
var result = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); |
|||
matrix.PointwiseDivide(other, result); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(0, ExpectedException = typeof(ArgumentException))] |
|||
[Row(-2, ExpectedException = typeof(ArgumentException))] |
|||
public void RandomWithNonPositiveNumberOfRowsShouldThrowException(int numberOfRows) |
|||
{ |
|||
var matrix = CreateMatrix(2, 3); |
|||
matrix = matrix.Random(numberOfRows, 4, new ContinuousUniform()); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(0, ExpectedException = typeof(ArgumentException))] |
|||
[Row(-2, ExpectedException = typeof(ArgumentException))] |
|||
public void RandomWithNonPositiveNumberOfRowsShouldThrowException2(int numberOfRows) |
|||
{ |
|||
var matrix = CreateMatrix(2, 3); |
|||
matrix = matrix.Random(numberOfRows, 4, new DiscreteUniform(0, 2)); |
|||
} |
|||
|
|||
[Test] |
|||
public void Trace() |
|||
{ |
|||
var matrix = TestMatrices["Square3x3"]; |
|||
var trace = matrix.Trace(); |
|||
AssertHelpers.AreEqual(new Complex32(6.6f, 3), trace); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void TraceOfNonSquareMatrixShouldThrowException() |
|||
{ |
|||
var matrix = TestMatrices["Wide2x3"]; |
|||
var trace = matrix.Trace(); |
|||
} |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -0,0 +1,287 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Iterative |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers; |
|||
using LinearAlgebra.Complex32.Solvers.Iterative; |
|||
using LinearAlgebra.Complex32.Solvers.StopCriterium; |
|||
using LinearAlgebra.Generic; |
|||
using LinearAlgebra.Generic.Solvers.Status; |
|||
using LinearAlgebra.Generic.Solvers.StopCriterium; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public class BiCgStabTest |
|||
{ |
|||
private const float ConvergenceBoundary = 1e-5f; |
|||
private const int MaximumIterations = 1000; |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void SolveWideMatrix() |
|||
{ |
|||
var matrix = new SparseMatrix(2, 3); |
|||
Vector<Complex32> input = new DenseVector(2); |
|||
|
|||
var solver = new BiCgStab(); |
|||
solver.Solve(matrix, input); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void SolveLongMatrix() |
|||
{ |
|||
var matrix = new SparseMatrix(3, 2); |
|||
Vector<Complex32> input = new DenseVector(3); |
|||
|
|||
var solver = new BiCgStab(); |
|||
solver.Solve(matrix, input); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveUnitMatrixAndBackMultiply() |
|||
{ |
|||
// Create the identity matrix
|
|||
Matrix<Complex32> matrix = SparseMatrix.Identity(100); |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, Complex32.One); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
var solver = new BiCgStab(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveScaledUnitMatrixAndBackMultiply() |
|||
{ |
|||
// Create the identity matrix
|
|||
Matrix<Complex32> matrix = SparseMatrix.Identity(100); |
|||
|
|||
// Scale it with a funny number
|
|||
matrix.Multiply(new Complex32((float)Math.PI, (float)Math.PI)); |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, Complex32.One); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
var solver = new BiCgStab(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolvePoissonMatrixAndBackMultiply() |
|||
{ |
|||
// Create the matrix
|
|||
var matrix = new SparseMatrix(25); |
|||
|
|||
// Assemble the matrix. We assume we're solving the Poisson equation
|
|||
// on a rectangular 5 x 5 grid
|
|||
const int GridSize = 5; |
|||
|
|||
// The pattern is:
|
|||
// 0 .... 0 -1 0 0 0 0 0 0 0 0 -1 4 -1 0 0 0 0 0 0 0 0 -1 0 0 ... 0
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
// Insert the first set of -1's
|
|||
if (i > (GridSize - 1)) |
|||
{ |
|||
matrix[i, i - GridSize] = -1; |
|||
} |
|||
|
|||
// Insert the second set of -1's
|
|||
if (i > 0) |
|||
{ |
|||
matrix[i, i - 1] = -1; |
|||
} |
|||
|
|||
// Insert the centerline values
|
|||
matrix[i, i] = 4; |
|||
|
|||
// Insert the first trailing set of -1's
|
|||
if (i < matrix.RowCount - 1) |
|||
{ |
|||
matrix[i, i + 1] = -1; |
|||
} |
|||
|
|||
// Insert the second trailing set of -1's
|
|||
if (i < matrix.RowCount - GridSize) |
|||
{ |
|||
matrix[i, i + GridSize] = -1; |
|||
} |
|||
} |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, Complex32.One); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
var solver = new BiCgStab(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(5)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
for (var iteration = 5; iteration > 3; iteration--) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(order); |
|||
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(1000), |
|||
new ResidualStopCriterium((float)Math.Pow(1.0/10.0, iteration)), |
|||
}); |
|||
var solver = new BiCgStab(monitor); |
|||
|
|||
var resultx = solver.Solve(matrixA, vectorb); |
|||
|
|||
if (!(monitor.Status is CalculationConverged)) |
|||
{ |
|||
// Solution was not found, try again downgrading convergence boundary
|
|||
continue; |
|||
} |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
Assert.Fail("Solution was not found in 3 tries"); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(5)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int order) |
|||
{ |
|||
for (var iteration = 5; iteration > 3; iteration--) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(1000), |
|||
new ResidualStopCriterium((float)Math.Pow(1.0 / 10.0, iteration)) |
|||
}); |
|||
var solver = new BiCgStab(monitor); |
|||
var matrixX = solver.Solve(matrixA, matrixB); |
|||
|
|||
if (!(monitor.Status is CalculationConverged)) |
|||
{ |
|||
// Solution was not found, try again downgrading convergence boundary
|
|||
continue; |
|||
} |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
} |
|||
} |
|||
return; |
|||
} |
|||
|
|||
Assert.Fail("Solution was not found in 3 tries"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,289 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Iterative |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers; |
|||
using LinearAlgebra.Complex32.Solvers.Iterative; |
|||
using LinearAlgebra.Complex32.Solvers.StopCriterium; |
|||
using LinearAlgebra.Generic; |
|||
using LinearAlgebra.Generic.Solvers.Status; |
|||
using LinearAlgebra.Generic.Solvers.StopCriterium; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public class GpBiCgTest |
|||
{ |
|||
private const float ConvergenceBoundary = 1e-5f; |
|||
private const int MaximumIterations = 1000; |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void SolveWideMatrix() |
|||
{ |
|||
var matrix = new SparseMatrix(2, 3); |
|||
Vector<Complex32> input = new DenseVector(2); |
|||
|
|||
var solver = new GpBiCg(); |
|||
solver.Solve(matrix, input); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void SolveLongMatrix() |
|||
{ |
|||
var matrix = new SparseMatrix(3, 2); |
|||
Vector<Complex32> input = new DenseVector(3); |
|||
|
|||
var solver = new GpBiCg(); |
|||
solver.Solve(matrix, input); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveUnitMatrixAndBackMultiply() |
|||
{ |
|||
// Create the identity matrix
|
|||
Matrix<Complex32> matrix = SparseMatrix.Identity(100); |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, 1); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
var solver = new GpBiCg(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveScaledUnitMatrixAndBackMultiply() |
|||
{ |
|||
// Create the identity matrix
|
|||
Matrix<Complex32> matrix = SparseMatrix.Identity(100); |
|||
|
|||
// Scale it with a funny number
|
|||
matrix.Multiply((float)Math.PI); |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, 1); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
|
|||
var solver = new GpBiCg(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolvePoissonMatrixAndBackMultiply() |
|||
{ |
|||
// Create the matrix
|
|||
var matrix = new SparseMatrix(25); |
|||
|
|||
// Assemble the matrix. We assume we're solving the Poisson equation
|
|||
// on a rectangular 5 x 5 grid
|
|||
const int GridSize = 5; |
|||
|
|||
// The pattern is:
|
|||
// 0 .... 0 -1 0 0 0 0 0 0 0 0 -1 4 -1 0 0 0 0 0 0 0 0 -1 0 0 ... 0
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
// Insert the first set of -1's
|
|||
if (i > (GridSize - 1)) |
|||
{ |
|||
matrix[i, i - GridSize] = -1; |
|||
} |
|||
|
|||
// Insert the second set of -1's
|
|||
if (i > 0) |
|||
{ |
|||
matrix[i, i - 1] = -1; |
|||
} |
|||
|
|||
// Insert the centerline values
|
|||
matrix[i, i] = 4; |
|||
|
|||
// Insert the first trailing set of -1's
|
|||
if (i < matrix.RowCount - 1) |
|||
{ |
|||
matrix[i, i + 1] = -1; |
|||
} |
|||
|
|||
// Insert the second trailing set of -1's
|
|||
if (i < matrix.RowCount - GridSize) |
|||
{ |
|||
matrix[i, i + GridSize] = -1; |
|||
} |
|||
} |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, 1); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
|
|||
var solver = new GpBiCg(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(5)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
for (var iteration = 5; iteration > 3; iteration--) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(order); |
|||
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(1000), |
|||
new ResidualStopCriterium((float)Math.Pow(1.0/10.0, iteration)), |
|||
}); |
|||
var solver = new GpBiCg(monitor); |
|||
|
|||
var resultx = solver.Solve(matrixA, vectorb); |
|||
|
|||
if (!(monitor.Status is CalculationConverged)) |
|||
{ |
|||
// Solution was not found, try again downgrading convergence boundary
|
|||
continue; |
|||
} |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
Assert.Fail("Solution was not found in 3 tries"); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(5)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int order) |
|||
{ |
|||
for (var iteration = 5; iteration > 3; iteration--) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(1000), |
|||
new ResidualStopCriterium((float)Math.Pow(1.0 / 10.0, iteration)) |
|||
}); |
|||
var solver = new GpBiCg(monitor); |
|||
var matrixX = solver.Solve(matrixA, matrixB); |
|||
|
|||
if (!(monitor.Status is CalculationConverged)) |
|||
{ |
|||
// Solution was not found, try again downgrading convergence boundary
|
|||
continue; |
|||
} |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
} |
|||
} |
|||
return; |
|||
} |
|||
|
|||
Assert.Fail("Solution was not found in 3 tries"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,287 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Iterative |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers; |
|||
using LinearAlgebra.Complex32.Solvers.Iterative; |
|||
using LinearAlgebra.Complex32.Solvers.StopCriterium; |
|||
using LinearAlgebra.Generic; |
|||
using LinearAlgebra.Generic.Solvers.Status; |
|||
using LinearAlgebra.Generic.Solvers.StopCriterium; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public class MlkBiCgStabTest |
|||
{ |
|||
private const float ConvergenceBoundary = 1e-5f; |
|||
private const int MaximumIterations = 1000; |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void SolveWideMatrix() |
|||
{ |
|||
var matrix = new SparseMatrix(2, 3); |
|||
Vector<Complex32> input = new DenseVector(2); |
|||
|
|||
var solver = new MlkBiCgStab(); |
|||
solver.Solve(matrix, input); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void SolveLongMatrix() |
|||
{ |
|||
var matrix = new SparseMatrix(3, 2); |
|||
Vector<Complex32> input = new DenseVector(3); |
|||
|
|||
var solver = new MlkBiCgStab(); |
|||
solver.Solve(matrix, input); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveUnitMatrixAndBackMultiply() |
|||
{ |
|||
// Create the identity matrix
|
|||
Matrix<Complex32> matrix = SparseMatrix.Identity(100); |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, 1); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
|
|||
var solver = new MlkBiCgStab(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveScaledUnitMatrixAndBackMultiply() |
|||
{ |
|||
// Create the identity matrix
|
|||
Matrix<Complex32> matrix = SparseMatrix.Identity(100); |
|||
|
|||
// Scale it with a funny number
|
|||
matrix.Multiply((float)Math.PI); |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, 1); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
var solver = new MlkBiCgStab(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolvePoissonMatrixAndBackMultiply() |
|||
{ |
|||
// Create the matrix
|
|||
var matrix = new SparseMatrix(25); |
|||
// Assemble the matrix. We assume we're solving the Poisson equation
|
|||
// on a rectangular 5 x 5 grid
|
|||
const int GridSize = 5; |
|||
|
|||
// The pattern is:
|
|||
// 0 .... 0 -1 0 0 0 0 0 0 0 0 -1 4 -1 0 0 0 0 0 0 0 0 -1 0 0 ... 0
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
// Insert the first set of -1's
|
|||
if (i > (GridSize - 1)) |
|||
{ |
|||
matrix[i, i - GridSize] = -1; |
|||
} |
|||
|
|||
// Insert the second set of -1's
|
|||
if (i > 0) |
|||
{ |
|||
matrix[i, i - 1] = -1; |
|||
} |
|||
|
|||
// Insert the centerline values
|
|||
matrix[i, i] = 4; |
|||
|
|||
// Insert the first trailing set of -1's
|
|||
if (i < matrix.RowCount - 1) |
|||
{ |
|||
matrix[i, i + 1] = -1; |
|||
} |
|||
|
|||
// Insert the second trailing set of -1's
|
|||
if (i < matrix.RowCount - GridSize) |
|||
{ |
|||
matrix[i, i + GridSize] = -1; |
|||
} |
|||
} |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, 1); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
var solver = new MlkBiCgStab(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(5)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
for (var iteration = 5; iteration > 3; iteration--) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(order); |
|||
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(1000), |
|||
new ResidualStopCriterium((float)Math.Pow(1.0/10.0, iteration)), |
|||
}); |
|||
var solver = new MlkBiCgStab(monitor); |
|||
|
|||
var resultx = solver.Solve(matrixA, vectorb); |
|||
|
|||
if (!(monitor.Status is CalculationConverged)) |
|||
{ |
|||
// Solution was not found, try again downgrading convergence boundary
|
|||
continue; |
|||
} |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
Assert.Fail("Solution was not found in 3 tries"); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(5)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int order) |
|||
{ |
|||
for (var iteration = 5; iteration > 3; iteration--) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(1000), |
|||
new ResidualStopCriterium((float)Math.Pow(1.0 / 10.0, iteration)) |
|||
}); |
|||
var solver = new MlkBiCgStab(monitor); |
|||
var matrixX = solver.Solve(matrixA, matrixB); |
|||
|
|||
if (!(monitor.Status is CalculationConverged)) |
|||
{ |
|||
// Solution was not found, try again downgrading convergence boundary
|
|||
continue; |
|||
} |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
} |
|||
} |
|||
return; |
|||
} |
|||
|
|||
Assert.Fail("Solution was not found in 3 tries"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,287 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Iterative |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers; |
|||
using LinearAlgebra.Complex32.Solvers.Iterative; |
|||
using LinearAlgebra.Complex32.Solvers.StopCriterium; |
|||
using LinearAlgebra.Generic; |
|||
using LinearAlgebra.Generic.Solvers.Status; |
|||
using LinearAlgebra.Generic.Solvers.StopCriterium; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public class TFQMRTest |
|||
{ |
|||
private const float ConvergenceBoundary = 1e-5f; |
|||
private const int MaximumIterations = 1000; |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void SolveWideMatrix() |
|||
{ |
|||
var matrix = new SparseMatrix(2, 3); |
|||
Vector<Complex32> input = new DenseVector(2); |
|||
|
|||
var solver = new TFQMR(); |
|||
solver.Solve(matrix, input); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void SolveLongMatrix() |
|||
{ |
|||
var matrix = new SparseMatrix(3, 2); |
|||
Vector<Complex32> input = new DenseVector(3); |
|||
|
|||
var solver = new TFQMR(); |
|||
solver.Solve(matrix, input); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveUnitMatrixAndBackMultiply() |
|||
{ |
|||
// Create the identity matrix
|
|||
Matrix<Complex32> matrix = SparseMatrix.Identity(100); |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, 1); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
|
|||
var solver = new TFQMR(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveScaledUnitMatrixAndBackMultiply() |
|||
{ |
|||
// Create the identity matrix
|
|||
Matrix<Complex32> matrix = SparseMatrix.Identity(100); |
|||
|
|||
// Scale it with a funny number
|
|||
matrix.Multiply((float)Math.PI); |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, 1); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
var solver = new TFQMR(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolvePoissonMatrixAndBackMultiply() |
|||
{ |
|||
// Create the matrix
|
|||
var matrix = new SparseMatrix(25); |
|||
// Assemble the matrix. We assume we're solving the Poisson equation
|
|||
// on a rectangular 5 x 5 grid
|
|||
const int GridSize = 5; |
|||
|
|||
// The pattern is:
|
|||
// 0 .... 0 -1 0 0 0 0 0 0 0 0 -1 4 -1 0 0 0 0 0 0 0 0 -1 0 0 ... 0
|
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
// Insert the first set of -1's
|
|||
if (i > (GridSize - 1)) |
|||
{ |
|||
matrix[i, i - GridSize] = -1; |
|||
} |
|||
|
|||
// Insert the second set of -1's
|
|||
if (i > 0) |
|||
{ |
|||
matrix[i, i - 1] = -1; |
|||
} |
|||
|
|||
// Insert the centerline values
|
|||
matrix[i, i] = 4; |
|||
|
|||
// Insert the first trailing set of -1's
|
|||
if (i < matrix.RowCount - 1) |
|||
{ |
|||
matrix[i, i + 1] = -1; |
|||
} |
|||
|
|||
// Insert the second trailing set of -1's
|
|||
if (i < matrix.RowCount - GridSize) |
|||
{ |
|||
matrix[i, i + GridSize] = -1; |
|||
} |
|||
} |
|||
|
|||
// Create the y vector
|
|||
Vector<Complex32> y = new DenseVector(matrix.RowCount, 1); |
|||
|
|||
// Create an iteration monitor which will keep track of iterative convergence
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(MaximumIterations), |
|||
new ResidualStopCriterium(ConvergenceBoundary), |
|||
new DivergenceStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
var solver = new TFQMR(monitor); |
|||
|
|||
// Solve equation Ax = y
|
|||
var x = solver.Solve(matrix, y); |
|||
|
|||
// Now compare the results
|
|||
Assert.IsNotNull(x, "#02"); |
|||
Assert.AreEqual(y.Count, x.Count, "#03"); |
|||
|
|||
// Back multiply the vector
|
|||
var z = matrix.Multiply(x); |
|||
|
|||
// Check that the solution converged
|
|||
Assert.IsTrue(monitor.Status is CalculationConverged, "#04"); |
|||
|
|||
// Now compare the vectors
|
|||
for (var i = 0; i < y.Count; i++) |
|||
{ |
|||
Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(5)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomVector(int order) |
|||
{ |
|||
for (var iteration = 5; iteration > 3; iteration--) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var vectorb = MatrixLoader.GenerateRandomDenseVector(order); |
|||
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(1000), |
|||
new ResidualStopCriterium((float)Math.Pow(1.0/10.0, iteration)), |
|||
}); |
|||
var solver = new TFQMR(monitor); |
|||
|
|||
var resultx = solver.Solve(matrixA, vectorb); |
|||
|
|||
if (!(monitor.Status is CalculationConverged)) |
|||
{ |
|||
// Solution was not found, try again downgrading convergence boundary
|
|||
continue; |
|||
} |
|||
|
|||
Assert.AreEqual(matrixA.ColumnCount, resultx.Count); |
|||
var bReconstruct = matrixA * resultx; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(vectorb[i].Real, bReconstruct[i].Real, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
Assert.AreApproximatelyEqual(vectorb[i].Imaginary, bReconstruct[i].Imaginary, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
Assert.Fail("Solution was not found in 3 tries"); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(5)] |
|||
[MultipleAsserts] |
|||
public void CanSolveForRandomMatrix(int order) |
|||
{ |
|||
for (var iteration = 5; iteration > 3; iteration--) |
|||
{ |
|||
var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); |
|||
|
|||
var monitor = new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new IterationCountStopCriterium(1000), |
|||
new ResidualStopCriterium((float)Math.Pow(1.0 / 10.0, iteration)) |
|||
}); |
|||
var solver = new TFQMR(monitor); |
|||
var matrixX = solver.Solve(matrixA, matrixB); |
|||
|
|||
if (!(monitor.Status is CalculationConverged)) |
|||
{ |
|||
// Solution was not found, try again downgrading convergence boundary
|
|||
continue; |
|||
} |
|||
|
|||
// The solution X row dimension is equal to the column dimension of A
|
|||
Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); |
|||
// The solution X has the same number of columns as B
|
|||
Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); |
|||
|
|||
var matrixBReconstruct = matrixA * matrixX; |
|||
|
|||
// Check the reconstruction.
|
|||
for (var i = 0; i < matrixB.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrixB.ColumnCount; j++) |
|||
{ |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
Assert.AreApproximatelyEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, (float)Math.Pow(1.0 / 10.0, iteration - 3)); |
|||
} |
|||
} |
|||
return; |
|||
} |
|||
|
|||
Assert.Fail("Solution was not found in 3 tries"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,355 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers; |
|||
using LinearAlgebra.Complex32.Solvers.StopCriterium; |
|||
using LinearAlgebra.Generic.Solvers.Status; |
|||
using LinearAlgebra.Generic.Solvers.StopCriterium; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public class IteratorTest |
|||
{ |
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CreateWithNullCollection() |
|||
{ |
|||
var iterator = new Iterator(null); |
|||
Assert.IsNotNull(iterator, "Should have an iterator"); |
|||
Assert.AreEqual(0, iterator.NumberOfCriteria, "There shouldn't be any criteria"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CreateWithEmptyCollection() |
|||
{ |
|||
var iterator = new Iterator(new IIterationStopCriterium<Complex32>[] { }); |
|||
Assert.IsNotNull(iterator, "Should have an iterator"); |
|||
Assert.AreEqual(0, iterator.NumberOfCriteria, "There shouldn't be any criteria"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CreateWithCollectionWithNulls() |
|||
{ |
|||
var iterator = new Iterator(new IIterationStopCriterium<Complex32>[] { null, null }); |
|||
Assert.IsNotNull(iterator, "Should have an iterator"); |
|||
Assert.AreEqual(0, iterator.NumberOfCriteria, "There shouldn't be any criteria"); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void CreateWithDuplicates() |
|||
{ |
|||
new Iterator(new IIterationStopCriterium<Complex32>[] |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new FailureStopCriterium() |
|||
}); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CreateWithCollection() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
new ResidualStopCriterium() |
|||
}; |
|||
var iterator = new Iterator(criteria); |
|||
Assert.IsNotNull(iterator, "Should have an iterator"); |
|||
|
|||
// Check that we have all the criteria
|
|||
Assert.AreEqual(criteria.Count, iterator.NumberOfCriteria, "Incorrect criterium count"); |
|||
var enumerator = iterator.StoredStopCriteria; |
|||
while (enumerator.MoveNext()) |
|||
{ |
|||
var criterium = enumerator.Current; |
|||
Assert.IsTrue(criteria.Exists( c => ReferenceEquals(c, criterium)), "Criterium missing"); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void AddWithNullStopCriterium() |
|||
{ |
|||
var iterator = new Iterator(); |
|||
iterator.Add(null); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void AddWithExistingStopCriterium() |
|||
{ |
|||
var iterator = new Iterator(); |
|||
iterator.Add(new FailureStopCriterium()); |
|||
Assert.AreEqual(1, iterator.NumberOfCriteria, "Incorrect criterium count"); |
|||
|
|||
iterator.Add(new FailureStopCriterium()); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Add() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
new ResidualStopCriterium() |
|||
}; |
|||
var iterator = new Iterator(); |
|||
Assert.AreEqual(0, iterator.NumberOfCriteria, "Incorrect criterium count"); |
|||
|
|||
foreach (var criterium in criteria) |
|||
{ |
|||
iterator.Add(criterium); |
|||
Assert.IsTrue(iterator.Contains(criterium), "Missing criterium"); |
|||
} |
|||
|
|||
// Check that we have all the criteria
|
|||
Assert.AreEqual(criteria.Count, iterator.NumberOfCriteria, "Incorrect criterium count"); |
|||
var enumerator = iterator.StoredStopCriteria; |
|||
while (enumerator.MoveNext()) |
|||
{ |
|||
var criterium = enumerator.Current; |
|||
Assert.IsTrue(criteria.Exists( c => ReferenceEquals(c, criterium)), "Criterium missing"); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void RemoveWithNullStopCriterium() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
new ResidualStopCriterium() |
|||
}; |
|||
var iterator = new Iterator(criteria); |
|||
Assert.AreEqual(criteria.Count, iterator.NumberOfCriteria, "Incorrect criterium count"); |
|||
|
|||
iterator.Remove(null); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void RemoveWithNonExistingStopCriterium() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
}; |
|||
var iterator = new Iterator(criteria); |
|||
Assert.AreEqual(criteria.Count, iterator.NumberOfCriteria, "Incorrect criterium count"); |
|||
|
|||
iterator.Remove(new ResidualStopCriterium()); |
|||
Assert.AreEqual(criteria.Count, iterator.NumberOfCriteria, "Incorrect criterium count"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Remove() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
new ResidualStopCriterium() |
|||
}; |
|||
var iterator = new Iterator(criteria); |
|||
Assert.AreEqual(criteria.Count, iterator.NumberOfCriteria, "Incorrect criterium count"); |
|||
|
|||
foreach (var criterium in criteria) |
|||
{ |
|||
iterator.Remove(criterium); |
|||
Assert.IsFalse(iterator.Contains(criterium), "Did not remove the criterium"); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void DetermineStatusWithoutStopCriteria() |
|||
{ |
|||
var iterator = new Iterator(); |
|||
iterator.DetermineStatus(0, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 5), |
|||
new DenseVector(3, 6)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedException(typeof(ArgumentOutOfRangeException))] |
|||
public void DetermineStatusWithNegativeIterationNumber() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
new ResidualStopCriterium() |
|||
}; |
|||
var iterator = new Iterator(criteria); |
|||
|
|||
iterator.DetermineStatus(-1, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 5), |
|||
new DenseVector(3, 6)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DetermineStatusWithNullSolutionVector() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
new ResidualStopCriterium() |
|||
}; |
|||
var iterator = new Iterator(criteria); |
|||
|
|||
iterator.DetermineStatus(1, |
|||
null, |
|||
new DenseVector(3, 5), |
|||
new DenseVector(3, 6)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DetermineStatusWithNullSourceVector() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
new ResidualStopCriterium() |
|||
}; |
|||
var iterator = new Iterator(criteria); |
|||
|
|||
iterator.DetermineStatus(1, |
|||
new DenseVector(3, 5), |
|||
null, |
|||
new DenseVector(3, 6)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DetermineStatusWithNullResidualVector() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
new ResidualStopCriterium() |
|||
}; |
|||
var iterator = new Iterator(criteria); |
|||
|
|||
iterator.DetermineStatus(1, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 5), |
|||
null); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatus() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(1) |
|||
}; |
|||
|
|||
var iterator = new Iterator(criteria); |
|||
|
|||
// First step, nothing should happen.
|
|||
iterator.DetermineStatus(0, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 4)); |
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), iterator.Status, "Incorrect status"); |
|||
|
|||
// Second step, should run out of iterations.
|
|||
iterator.DetermineStatus(1, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 4)); |
|||
Assert.IsInstanceOfType(typeof(CalculationStoppedWithoutConvergence), iterator.Status, "Incorrect status"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetToPrecalculationState() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(1) |
|||
}; |
|||
|
|||
var iterator = new Iterator(criteria); |
|||
|
|||
// First step, nothing should happen.
|
|||
iterator.DetermineStatus(0, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 4)); |
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), iterator.Status, "Incorrect status"); |
|||
|
|||
iterator.ResetToPrecalculationState(); |
|||
Assert.IsInstanceOfType(typeof(CalculationIndetermined), iterator.Status, "Incorrect status"); |
|||
Assert.IsInstanceOfType(typeof(CalculationIndetermined), criteria[0].Status, "Incorrect status"); |
|||
Assert.IsInstanceOfType(typeof(CalculationIndetermined), criteria[1].Status, "Incorrect status"); |
|||
Assert.IsInstanceOfType(typeof(CalculationIndetermined), criteria[2].Status, "Incorrect status"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Clone() |
|||
{ |
|||
var criteria = new List<IIterationStopCriterium<Complex32>> |
|||
{ |
|||
new FailureStopCriterium(), |
|||
new DivergenceStopCriterium(), |
|||
new IterationCountStopCriterium(), |
|||
new ResidualStopCriterium() |
|||
}; |
|||
|
|||
var iterator = new Iterator(criteria); |
|||
|
|||
var clonedIterator = iterator.Clone(); |
|||
Assert.IsInstanceOfType(typeof(Iterator), clonedIterator, "Incorrect type"); |
|||
|
|||
var clone = clonedIterator as Iterator; |
|||
Assert.IsNotNull(clone); |
|||
// ReSharper disable PossibleNullReferenceException
|
|||
Assert.AreEqual(iterator.NumberOfCriteria, clone.NumberOfCriteria, "Incorrect criterium count"); |
|||
// ReSharper restore PossibleNullReferenceException
|
|||
|
|||
var enumerator = clone.StoredStopCriteria; |
|||
while (enumerator.MoveNext()) |
|||
{ |
|||
var criterium = enumerator.Current; |
|||
Assert.IsTrue(criteria.Exists(c => c.GetType().Equals(criterium.GetType())), "Criterium missing"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers.Preconditioners; |
|||
using LinearAlgebra.Generic; |
|||
using LinearAlgebra.Generic.Solvers.Preconditioners; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public sealed class DiagonalTest : PreconditionerTest |
|||
{ |
|||
internal override IPreConditioner<Complex32> CreatePreconditioner() |
|||
{ |
|||
return new Diagonal(); |
|||
} |
|||
|
|||
protected override void CheckResult(IPreConditioner<Complex32> preconditioner, SparseMatrix matrix, Vector<Complex32> vector, Vector<Complex32> result) |
|||
{ |
|||
Assert.AreEqual(typeof(Diagonal), preconditioner.GetType(), "#01"); |
|||
|
|||
// Compute M * result = product
|
|||
// compare vector and product. Should be equal
|
|||
Vector<Complex32> product = new DenseVector(result.Count); |
|||
matrix.Multiply(result, product); |
|||
|
|||
for (var i = 0; i < product.Count; i++) |
|||
{ |
|||
Assert.IsTrue(vector[i].Real.AlmostEqual(product[i].Real, -Epsilon.Magnitude()), "#02-" + i); |
|||
Assert.IsTrue(vector[i].Imaginary.AlmostEqual(product[i].Imaginary, -Epsilon.Magnitude()), "#03-" + i); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,504 @@ |
|||
// NOTE: This class file Build Action is not set to Compile by default. Because IlutpElementSorter class is internal. If you want
|
|||
// NOTE: to test IlutpElementSorter you should make it public, set Build Action=Compile of this file (in properties) and run tets.
|
|||
// NOTE: After all tests passed please do all actions vice versa. IlutpElementSorter class is only for internal usage.
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers.Preconditioners; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public sealed class IluptElementSorterTest |
|||
{ |
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithIncreasingIntergerArray() |
|||
{ |
|||
var sortedIndices = new [] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; |
|||
IlutpElementSorter.SortIntegersDecreasing(sortedIndices); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
Assert.AreEqual(sortedIndices.Length - 1 - i, sortedIndices[i], "#01-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithDecreasingIntegerArray() |
|||
{ |
|||
var sortedIndices = new [] { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; |
|||
IlutpElementSorter.SortIntegersDecreasing(sortedIndices); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
Assert.AreEqual(sortedIndices.Length - 1 - i, sortedIndices[i], "#01-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithRandomIntegerArray() |
|||
{ |
|||
var sortedIndices = new []{ 5, 2, 8, 6, 0, 4, 1, 7, 3, 9 }; |
|||
IlutpElementSorter.SortIntegersDecreasing(sortedIndices); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
Assert.AreEqual(sortedIndices.Length - 1 - i, sortedIndices[i], "#01-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithDuplicateEntries() |
|||
{ |
|||
var sortedIndices = new []{ 1, 1, 1, 1, 2, 2, 2, 2, 3, 4 }; |
|||
IlutpElementSorter.SortIntegersDecreasing(sortedIndices); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 0) |
|||
{ |
|||
Assert.AreEqual(4, sortedIndices[i], "#01-" + i); |
|||
} |
|||
else |
|||
{ |
|||
if (i == 1) |
|||
{ |
|||
Assert.AreEqual(3, sortedIndices[i], "#01-" + i); |
|||
} |
|||
else |
|||
{ |
|||
if (i < 6) |
|||
{ |
|||
if (sortedIndices[i] != 2) |
|||
{ |
|||
Assert.Fail("#01-" + i); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (sortedIndices[i] != 1) |
|||
{ |
|||
Assert.Fail("#01-" + i); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithSpecialConstructedIntegerArray() |
|||
{ |
|||
var sortedIndices = new []{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; |
|||
IlutpElementSorter.SortIntegersDecreasing(sortedIndices); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 0) |
|||
{ |
|||
Assert.AreEqual(1, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
sortedIndices = new []{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
|||
IlutpElementSorter.SortIntegersDecreasing(sortedIndices); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 0) |
|||
{ |
|||
Assert.AreEqual(1, sortedIndices[i], "#02-" + i); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
sortedIndices = new []{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; |
|||
IlutpElementSorter.SortIntegersDecreasing(sortedIndices); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 0) |
|||
{ |
|||
Assert.AreEqual(1, sortedIndices[i], "#03-" + i); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
sortedIndices = new []{ 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 }; |
|||
IlutpElementSorter.SortIntegersDecreasing(sortedIndices); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 9) |
|||
{ |
|||
Assert.AreEqual(0, sortedIndices[i], "#04-" + i); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithIncreasingDoubleArray() |
|||
{ |
|||
var sortedIndices = new int[10]; |
|||
Vector<Complex32> values = new DenseVector(10); |
|||
values[0] = 0; |
|||
values[1] = 1; |
|||
values[2] = 2; |
|||
values[3] = 3; |
|||
values[4] = 4; |
|||
values[5] = 5; |
|||
values[6] = 6; |
|||
values[7] = 7; |
|||
values[8] = 8; |
|||
values[9] = 9; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
|
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, sortedIndices.Length - 1, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
Assert.AreEqual(sortedIndices.Length - 1 - i, sortedIndices[i], "#01-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithDecreasingDoubleArray() |
|||
{ |
|||
var sortedIndices = new int[10]; |
|||
Vector<Complex32> values = new DenseVector(10); |
|||
values[0] = 9; |
|||
values[1] = 8; |
|||
values[2] = 7; |
|||
values[3] = 6; |
|||
values[4] = 5; |
|||
values[5] = 4; |
|||
values[6] = 3; |
|||
values[7] = 2; |
|||
values[8] = 1; |
|||
values[9] = 0; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
|
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, sortedIndices.Length - 1, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
Assert.AreEqual(i, sortedIndices[i], "#01-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithRandomDoubleArray() |
|||
{ |
|||
var sortedIndices = new int[10]; |
|||
Vector<Complex32> values = new DenseVector(10); |
|||
values[0] = 5; |
|||
values[1] = 2; |
|||
values[2] = 8; |
|||
values[3] = 6; |
|||
values[4] = 0; |
|||
values[5] = 4; |
|||
values[6] = 1; |
|||
values[7] = 7; |
|||
values[8] = 3; |
|||
values[9] = 9; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
|
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, sortedIndices.Length - 1, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
switch (i) |
|||
{ |
|||
case 0: |
|||
Assert.AreEqual(9, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
case 1: |
|||
Assert.AreEqual(2, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
case 2: |
|||
Assert.AreEqual(7, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
case 3: |
|||
Assert.AreEqual(3, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
case 4: |
|||
Assert.AreEqual(0, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
case 5: |
|||
Assert.AreEqual(5, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
case 6: |
|||
Assert.AreEqual(8, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
case 7: |
|||
Assert.AreEqual(1, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
case 8: |
|||
Assert.AreEqual(6, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
case 9: |
|||
Assert.AreEqual(4, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithDuplicateDoubleEntries() |
|||
{ |
|||
var sortedIndices = new int[10]; |
|||
Vector<Complex32> values = new DenseVector(10); |
|||
values[0] = 1; |
|||
values[1] = 1; |
|||
values[2] = 1; |
|||
values[3] = 1; |
|||
values[4] = 2; |
|||
values[5] = 2; |
|||
values[6] = 2; |
|||
values[7] = 2; |
|||
values[8] = 3; |
|||
values[9] = 4; |
|||
|
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, sortedIndices.Length - 1, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 0) |
|||
{ |
|||
Assert.AreEqual(9, sortedIndices[i], "#01-" + i); |
|||
} |
|||
else |
|||
{ |
|||
if (i == 1) |
|||
{ |
|||
Assert.AreEqual(8, sortedIndices[i], "#01-" + i); |
|||
} |
|||
else |
|||
{ |
|||
if (i < 6) |
|||
{ |
|||
if ((sortedIndices[i] != 4) && |
|||
(sortedIndices[i] != 5) && |
|||
(sortedIndices[i] != 6) && |
|||
(sortedIndices[i] != 7)) |
|||
{ |
|||
Assert.Fail("#01-" + i); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if ((sortedIndices[i] != 0) && |
|||
(sortedIndices[i] != 1) && |
|||
(sortedIndices[i] != 2) && |
|||
(sortedIndices[i] != 3)) |
|||
{ |
|||
Assert.Fail("#01-" + i); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithSpecialConstructedDoubleArray() |
|||
{ |
|||
var sortedIndices = new int[10]; |
|||
Vector<Complex32> values = new DenseVector(10); |
|||
values[0] = 0; |
|||
values[1] = 0; |
|||
values[2] = 0; |
|||
values[3] = 0; |
|||
values[4] = 0; |
|||
values[5] = 1; |
|||
values[6] = 0; |
|||
values[7] = 0; |
|||
values[8] = 0; |
|||
values[9] = 0; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, sortedIndices.Length - 1, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 0) |
|||
{ |
|||
Assert.AreEqual(5, sortedIndices[i], "#01-" + i); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
values[0] = 1; |
|||
values[1] = 0; |
|||
values[2] = 0; |
|||
values[3] = 0; |
|||
values[4] = 0; |
|||
values[5] = 0; |
|||
values[6] = 0; |
|||
values[7] = 0; |
|||
values[8] = 0; |
|||
values[9] = 0; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, sortedIndices.Length - 1, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 0) |
|||
{ |
|||
Assert.AreEqual(0, sortedIndices[i], "#02-" + i); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
values[0] = 0; |
|||
values[1] = 0; |
|||
values[2] = 0; |
|||
values[3] = 0; |
|||
values[4] = 0; |
|||
values[5] = 0; |
|||
values[6] = 0; |
|||
values[7] = 0; |
|||
values[8] = 0; |
|||
values[9] = 1; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, sortedIndices.Length - 1, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 0) |
|||
{ |
|||
Assert.AreEqual(9, sortedIndices[i], "#03-" + i); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
values[0] = 1; |
|||
values[1] = 1; |
|||
values[2] = 1; |
|||
values[3] = 0; |
|||
values[4] = 1; |
|||
values[5] = 1; |
|||
values[6] = 1; |
|||
values[7] = 1; |
|||
values[8] = 1; |
|||
values[9] = 1; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, sortedIndices.Length - 1, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
if (i == 9) |
|||
{ |
|||
Assert.AreEqual(3, sortedIndices[i], "#04-" + i); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithIncreasingDoubleArrayWithLowerBound() |
|||
{ |
|||
var sortedIndices = new int[10]; |
|||
Vector<Complex32> values = new DenseVector(10); |
|||
values[0] = 0; |
|||
values[1] = 1; |
|||
values[2] = 2; |
|||
values[3] = 3; |
|||
values[4] = 4; |
|||
values[5] = 5; |
|||
values[6] = 6; |
|||
values[7] = 7; |
|||
values[8] = 8; |
|||
values[9] = 9; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
|
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(4, sortedIndices.Length - 1, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length - 4; i++) |
|||
{ |
|||
Assert.AreEqual(sortedIndices.Length - 1 - i, sortedIndices[i], "#01-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithIncreasingDoubleArrayWithUpperBound() |
|||
{ |
|||
var sortedIndices = new int[10]; |
|||
Vector<Complex32> values = new DenseVector(10); |
|||
values[0] = 0; |
|||
values[1] = 1; |
|||
values[2] = 2; |
|||
values[3] = 3; |
|||
values[4] = 4; |
|||
values[5] = 5; |
|||
values[6] = 6; |
|||
values[7] = 7; |
|||
values[8] = 8; |
|||
values[9] = 9; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
|
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(0, sortedIndices.Length - 5, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length - 5; i++) |
|||
{ |
|||
Assert.AreEqual(sortedIndices.Length - 5 - i, sortedIndices[i], "#01-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void HeapSortWithIncreasingDoubleArrayWithLowerAndUpperBound() |
|||
{ |
|||
var sortedIndices = new int[10]; |
|||
Vector<Complex32> values = new DenseVector(10); |
|||
values[0] = 0; |
|||
values[1] = 1; |
|||
values[2] = 2; |
|||
values[3] = 3; |
|||
values[4] = 4; |
|||
values[5] = 5; |
|||
values[6] = 6; |
|||
values[7] = 7; |
|||
values[8] = 8; |
|||
values[9] = 9; |
|||
for (var i = 0; i < sortedIndices.Length; i++) |
|||
{ |
|||
sortedIndices[i] = i; |
|||
} |
|||
|
|||
IlutpElementSorter.SortDoubleIndicesDecreasing(2, sortedIndices.Length - 3, sortedIndices, values); |
|||
for (var i = 0; i < sortedIndices.Length - 4; i++) |
|||
{ |
|||
Assert.AreEqual(sortedIndices.Length - 3 - i, sortedIndices[i], "#01-" + i); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,254 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using System.Reflection; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers.Preconditioners; |
|||
using LinearAlgebra.Generic; |
|||
using LinearAlgebra.Generic.Solvers.Preconditioners; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public sealed class IlutpPreconditionerTest : PreconditionerTest |
|||
{ |
|||
private double _dropTolerance = 0.1; |
|||
private double _fillLevel = 1.0; |
|||
private double _pivotTolerance = 1.0; |
|||
|
|||
[SetUp] |
|||
public void Setup() |
|||
{ |
|||
_dropTolerance = 0.1; |
|||
_fillLevel = 1.0; |
|||
_pivotTolerance = 1.0; |
|||
} |
|||
|
|||
private static T GetMethod<T>(Ilutp ilutp, string methodName) |
|||
{ |
|||
var type = ilutp.GetType(); |
|||
var methodInfo = type.GetMethod(methodName, |
|||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, |
|||
null, |
|||
CallingConventions.Standard, |
|||
new Type[0], |
|||
null); |
|||
var obj = methodInfo.Invoke(ilutp, null); |
|||
return (T)obj; |
|||
} |
|||
|
|||
private static SparseMatrix GetUpperTriangle(Ilutp ilutp) |
|||
{ |
|||
return GetMethod<SparseMatrix>(ilutp, "UpperTriangle"); |
|||
} |
|||
|
|||
private static SparseMatrix GetLowerTriangle(Ilutp ilutp) |
|||
{ |
|||
return GetMethod<SparseMatrix>(ilutp, "LowerTriangle"); |
|||
} |
|||
|
|||
private static int[] GetPivots(Ilutp ilutp) |
|||
{ |
|||
return GetMethod<int[]>(ilutp, "Pivots"); |
|||
} |
|||
|
|||
private static SparseMatrix CreateReverseUnitMatrix(int size) |
|||
{ |
|||
var matrix = new SparseMatrix(size); |
|||
for (var i = 0; i < size; i++) |
|||
{ |
|||
matrix[i, size - 1 - i] = 2; |
|||
} |
|||
|
|||
return matrix; |
|||
} |
|||
|
|||
private Ilutp InternalCreatePreconditioner() |
|||
{ |
|||
var result = new Ilutp |
|||
{ |
|||
DropTolerance = _dropTolerance, |
|||
FillLevel = _fillLevel, |
|||
PivotTolerance = _pivotTolerance |
|||
}; |
|||
return result; |
|||
} |
|||
|
|||
internal override IPreConditioner<Complex32> CreatePreconditioner() |
|||
{ |
|||
_pivotTolerance = 0; |
|||
_dropTolerance = 0.0; |
|||
_fillLevel = 100; |
|||
return InternalCreatePreconditioner(); |
|||
} |
|||
|
|||
protected override void CheckResult(IPreConditioner<Complex32> preconditioner, SparseMatrix matrix, Vector<Complex32> vector, Vector<Complex32> result) |
|||
{ |
|||
Assert.AreEqual(typeof(Ilutp), preconditioner.GetType(), "#01"); |
|||
|
|||
// Compute M * result = product
|
|||
// compare vector and product. Should be equal
|
|||
Vector<Complex32> product = new DenseVector(result.Count); |
|||
matrix.Multiply(result, product); |
|||
for (var i = 0; i < product.Count; i++) |
|||
{ |
|||
Assert.IsTrue(vector[i].Real.AlmostEqual(product[i].Real, -Epsilon.Magnitude()), "#02-" + i); |
|||
Assert.IsTrue(vector[i].Imaginary.AlmostEqual(product[i].Imaginary, -Epsilon.Magnitude()), "#03-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveReturningOldVectorWithoutPivoting() |
|||
{ |
|||
const int Size = 10; |
|||
|
|||
var newMatrix = CreateUnitMatrix(Size); |
|||
var vector = CreateStandardBcVector(Size); |
|||
|
|||
// set the pivot tolerance to zero so we don't pivot
|
|||
_pivotTolerance = 0.0; |
|||
_dropTolerance = 0.0; |
|||
_fillLevel = 100; |
|||
var preconditioner = CreatePreconditioner(); |
|||
preconditioner.Initialize(newMatrix); |
|||
Vector<Complex32> result = new DenseVector(vector.Count); |
|||
preconditioner.Approximate(vector, result); |
|||
CheckResult(preconditioner, newMatrix, vector, result); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveReturningOldVectorWithPivoting() |
|||
{ |
|||
const int Size = 10; |
|||
var newMatrix = CreateUnitMatrix(Size); |
|||
var vector = CreateStandardBcVector(Size); |
|||
|
|||
// Set the pivot tolerance to 1 so we always pivot (if necessary)
|
|||
_pivotTolerance = 1.0; |
|||
_dropTolerance = 0.0; |
|||
_fillLevel = 100; |
|||
var preconditioner = CreatePreconditioner(); |
|||
preconditioner.Initialize(newMatrix); |
|||
Vector<Complex32> result = new DenseVector(vector.Count); |
|||
preconditioner.Approximate(vector, result); |
|||
CheckResult(preconditioner, newMatrix, vector, result); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CompareWithOriginalDenseMatrixWithoutPivoting() |
|||
{ |
|||
var sparseMatrix = new SparseMatrix(3); |
|||
sparseMatrix[0, 0] = -1; |
|||
sparseMatrix[0, 1] = 5; |
|||
sparseMatrix[0, 2] = 6; |
|||
sparseMatrix[1, 0] = 3; |
|||
sparseMatrix[1, 1] = -6; |
|||
sparseMatrix[1, 2] = 1; |
|||
sparseMatrix[2, 0] = 6; |
|||
sparseMatrix[2, 1] = 8; |
|||
sparseMatrix[2, 2] = 9; |
|||
var ilu = new Ilutp |
|||
{ |
|||
PivotTolerance = 0.0, |
|||
DropTolerance = 0, |
|||
FillLevel = 10 |
|||
}; |
|||
ilu.Initialize(sparseMatrix); |
|||
var l = GetLowerTriangle(ilu); |
|||
|
|||
// Assert l is lower triagonal
|
|||
for (var i = 0; i < l.RowCount; i++) |
|||
{ |
|||
for (var j = i + 1; j < l.RowCount; j++) |
|||
{ |
|||
Assert.IsTrue(0.0.AlmostEqual(l[i,j].Magnitude, -Epsilon.Magnitude()), "#01-" + i + "-" + j); |
|||
} |
|||
} |
|||
|
|||
var u = GetUpperTriangle(ilu); |
|||
|
|||
// Assert u is upper triagonal
|
|||
for (var i = 0; i < u.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < i; j++) |
|||
{ |
|||
Assert.IsTrue(0.0.AlmostEqual(u[i,j].Magnitude, -Epsilon.Magnitude()), "#02-" + i + "-" + j); |
|||
} |
|||
} |
|||
|
|||
var original = l.Multiply(u); |
|||
for (var i = 0; i < sparseMatrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < sparseMatrix.ColumnCount; j++) |
|||
{ |
|||
Assert.IsTrue(sparseMatrix[i,j].Real.AlmostEqual(original[i, j].Real, -Epsilon.Magnitude()), "#03-" + i + "-" + j); |
|||
Assert.IsTrue(sparseMatrix[i, j].Imaginary.AlmostEqual(original[i, j].Imaginary, -Epsilon.Magnitude()), "#04-" + i + "-" + j); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CompareWithOriginalDenseMatrixWithPivoting() |
|||
{ |
|||
var sparseMatrix = new SparseMatrix(3); |
|||
sparseMatrix[0, 0] = -1; |
|||
sparseMatrix[0, 1] = 5; |
|||
sparseMatrix[0, 2] = 6; |
|||
sparseMatrix[1, 0] = 3; |
|||
sparseMatrix[1, 1] = -6; |
|||
sparseMatrix[1, 2] = 1; |
|||
sparseMatrix[2, 0] = 6; |
|||
sparseMatrix[2, 1] = 8; |
|||
sparseMatrix[2, 2] = 9; |
|||
var ilu = new Ilutp |
|||
{ |
|||
PivotTolerance = 1.0, |
|||
DropTolerance = 0, |
|||
FillLevel = 10 |
|||
}; |
|||
ilu.Initialize(sparseMatrix); |
|||
var l = GetLowerTriangle(ilu); |
|||
var u = GetUpperTriangle(ilu); |
|||
var pivots = GetPivots(ilu); |
|||
var p = new SparseMatrix(l.RowCount); |
|||
for (var i = 0; i < p.RowCount; i++) |
|||
{ |
|||
p[i, pivots[i]] = 1.0f; |
|||
} |
|||
|
|||
var temp = l.Multiply(u); |
|||
var original = temp.Multiply(p); |
|||
for (var i = 0; i < sparseMatrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < sparseMatrix.ColumnCount; j++) |
|||
{ |
|||
Assert.IsTrue(sparseMatrix[i, j].Real.AlmostEqual(original[i, j].Real, -Epsilon.Magnitude()), "#01-" + i + "-" + j); |
|||
Assert.IsTrue(sparseMatrix[i, j].Imaginary.AlmostEqual(original[i, j].Imaginary, -Epsilon.Magnitude()), "#02-" + i + "-" + j); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void SolveWithPivoting() |
|||
{ |
|||
const int Size = 10; |
|||
var newMatrix = CreateReverseUnitMatrix(Size); |
|||
var vector = CreateStandardBcVector(Size); |
|||
var preconditioner = new Ilutp |
|||
{ |
|||
PivotTolerance = 1.0, |
|||
DropTolerance = 0, |
|||
FillLevel = 10 |
|||
}; |
|||
preconditioner.Initialize(newMatrix); |
|||
Vector<Complex32> result = new DenseVector(vector.Count); |
|||
preconditioner.Approximate(vector, result); |
|||
CheckResult(preconditioner, newMatrix, vector, result); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using System.Reflection; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers.Preconditioners; |
|||
using LinearAlgebra.Generic; |
|||
using LinearAlgebra.Generic.Solvers.Preconditioners; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public sealed class IncompleteLUFactorizationTest : PreconditionerTest |
|||
{ |
|||
private static T GetMethod<T>(IncompleteLU ilu, string methodName) |
|||
{ |
|||
var type = ilu.GetType(); |
|||
var methodInfo = type.GetMethod(methodName, |
|||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, |
|||
null, |
|||
CallingConventions.Standard, |
|||
new Type[0], |
|||
null); |
|||
var obj = methodInfo.Invoke(ilu, null); |
|||
return (T)obj; |
|||
} |
|||
|
|||
private static Matrix<Complex32> GetUpperTriangle(IncompleteLU ilu) |
|||
{ |
|||
return GetMethod<Matrix<Complex32>>(ilu, "UpperTriangle"); |
|||
} |
|||
|
|||
private static Matrix<Complex32> GetLowerTriangle(IncompleteLU ilu) |
|||
{ |
|||
return GetMethod<Matrix<Complex32>>(ilu, "LowerTriangle"); |
|||
} |
|||
|
|||
internal override IPreConditioner<Complex32> CreatePreconditioner() |
|||
{ |
|||
return new IncompleteLU(); |
|||
} |
|||
|
|||
protected override void CheckResult(IPreConditioner<Complex32> preconditioner, SparseMatrix matrix, Vector<Complex32> vector, Vector<Complex32> result) |
|||
{ |
|||
Assert.AreEqual(typeof(IncompleteLU), preconditioner.GetType(), "#01"); |
|||
|
|||
// Compute M * result = product
|
|||
// compare vector and product. Should be equal
|
|||
Vector<Complex32> product = new DenseVector(result.Count); |
|||
matrix.Multiply(result, product); |
|||
|
|||
for (var i = 0; i < product.Count; i++) |
|||
{ |
|||
Assert.IsTrue(vector[i].Real.AlmostEqual(product[i].Real, -Epsilon.Magnitude()), "#02-" + i); |
|||
Assert.IsTrue(vector[i].Imaginary.AlmostEqual(product[i].Imaginary, -Epsilon.Magnitude()), "#03-" + i); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CompareWithOriginalDenseMatrix() |
|||
{ |
|||
var sparseMatrix = new SparseMatrix(3); |
|||
sparseMatrix[0, 0] = -1; |
|||
sparseMatrix[0, 1] = 5; |
|||
sparseMatrix[0, 2] = 6; |
|||
sparseMatrix[1, 0] = 3; |
|||
sparseMatrix[1, 1] = -6; |
|||
sparseMatrix[1, 2] = 1; |
|||
sparseMatrix[2, 0] = 6; |
|||
sparseMatrix[2, 1] = 8; |
|||
sparseMatrix[2, 2] = 9; |
|||
var ilu = new IncompleteLU(); |
|||
ilu.Initialize(sparseMatrix); |
|||
var original = GetLowerTriangle(ilu).Multiply(GetUpperTriangle(ilu)); |
|||
|
|||
for (var i = 0; i < sparseMatrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < sparseMatrix.ColumnCount; j++) |
|||
{ |
|||
Assert.IsTrue(sparseMatrix[i, j].Real.AlmostEqual(original[i, j].Real, -Epsilon.Magnitude()), "#01-" + i + "-" + j); |
|||
Assert.IsTrue(sparseMatrix[i, j].Imaginary.AlmostEqual(original[i, j].Imaginary, -Epsilon.Magnitude()), "#02-" + i + "-" + j); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,128 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Generic; |
|||
using LinearAlgebra.Generic.Solvers.Preconditioners; |
|||
using MbUnit.Framework; |
|||
|
|||
public abstract class PreconditionerTest |
|||
{ |
|||
protected const double Epsilon = 1e-5; |
|||
|
|||
internal SparseMatrix CreateUnitMatrix(int size) |
|||
{ |
|||
var matrix = new SparseMatrix(size); |
|||
for (var i = 0; i < size; i++) |
|||
{ |
|||
matrix[i, i] = 2; |
|||
} |
|||
|
|||
return matrix; |
|||
} |
|||
|
|||
protected Vector<Complex32> CreateStandardBcVector(int size) |
|||
{ |
|||
Vector<Complex32> vector = new DenseVector(size); |
|||
for (var i = 0; i < size; i++) |
|||
{ |
|||
vector[i] = i + 1; |
|||
} |
|||
|
|||
return vector; |
|||
} |
|||
|
|||
internal abstract IPreConditioner<Complex32> CreatePreconditioner(); |
|||
|
|||
protected abstract void CheckResult(IPreConditioner<Complex32> preconditioner, SparseMatrix matrix, Vector<Complex32> vector, Vector<Complex32> result); |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ApproximateWithUnitMatrixReturningNewVector() |
|||
{ |
|||
const int Size = 10; |
|||
|
|||
var newMatrix = CreateUnitMatrix(Size); |
|||
var vector = CreateStandardBcVector(Size); |
|||
|
|||
var preconditioner = CreatePreconditioner(); |
|||
preconditioner.Initialize(newMatrix); |
|||
|
|||
var result = preconditioner.Approximate(vector); |
|||
|
|||
CheckResult(preconditioner, newMatrix, vector, result); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ApproximateReturningOldVector() |
|||
{ |
|||
const int Size = 10; |
|||
var newMatrix = CreateUnitMatrix(Size); |
|||
var vector = CreateStandardBcVector(Size); |
|||
|
|||
var preconditioner = CreatePreconditioner(); |
|||
preconditioner.Initialize(newMatrix); |
|||
|
|||
Vector<Complex32> result = new DenseVector(vector.Count); |
|||
preconditioner.Approximate(vector, result); |
|||
|
|||
CheckResult(preconditioner, newMatrix, vector, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void ApproximateWithVectorWithIncorrectLength() |
|||
{ |
|||
const int Size = 10; |
|||
var newMatrix = CreateUnitMatrix(Size); |
|||
var vector = CreateStandardBcVector(Size); |
|||
|
|||
var preconditioner = CreatePreconditioner(); |
|||
preconditioner.Initialize(newMatrix); |
|||
|
|||
Vector<Complex32> result = new DenseVector(vector.Count + 10); |
|||
preconditioner.Approximate(vector, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void ApproximateWithNullVector() |
|||
{ |
|||
const int Size = 10; |
|||
var newMatrix = CreateUnitMatrix(Size); |
|||
var vector = CreateStandardBcVector(Size); |
|||
|
|||
var preconditioner = CreatePreconditioner(); |
|||
preconditioner.Initialize(newMatrix); |
|||
|
|||
Vector<Complex32> result = new DenseVector(vector.Count + 10); |
|||
preconditioner.Approximate(null, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void ApproximateWithNullResultVector() |
|||
{ |
|||
const int Size = 10; |
|||
var newMatrix = CreateUnitMatrix(Size); |
|||
var vector = CreateStandardBcVector(Size); |
|||
|
|||
var preconditioner = CreatePreconditioner(); |
|||
preconditioner.Initialize(newMatrix); |
|||
|
|||
Vector<Complex32> result = null; |
|||
preconditioner.Approximate(vector, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void ApproximateWithNonInitializedPreconditioner() |
|||
{ |
|||
const int Size = 10; |
|||
var vector = CreateStandardBcVector(Size); |
|||
var preconditioner = CreatePreconditioner(); |
|||
preconditioner.Approximate(vector); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.Preconditioners |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers.Preconditioners; |
|||
using LinearAlgebra.Generic; |
|||
using LinearAlgebra.Generic.Solvers.Preconditioners; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public sealed class UnitPreconditionerTest : PreconditionerTest |
|||
{ |
|||
internal override IPreConditioner<Complex32> CreatePreconditioner() |
|||
{ |
|||
return new UnitPreconditioner(); |
|||
} |
|||
|
|||
protected override void CheckResult(IPreConditioner<Complex32> preconditioner, SparseMatrix matrix, Vector<Complex32> vector, Vector<Complex32> result) |
|||
{ |
|||
Assert.AreEqual(typeof(UnitPreconditioner), preconditioner.GetType(), "#01"); |
|||
|
|||
// Unit preconditioner is doing nothing. Vector and result should be equal
|
|||
|
|||
for (var i = 0; i < vector.Count; i++) |
|||
{ |
|||
Assert.IsTrue(vector[i] == result[i], "#02-" + i); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,234 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.StopCriterium |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers.StopCriterium; |
|||
using LinearAlgebra.Generic.Solvers.Status; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public sealed class DivergenceStopCriteriumTest |
|||
{ |
|||
[Test] |
|||
[ExpectedArgumentOutOfRangeException] |
|||
public void CreateWithNegativeMaximumIncrease() |
|||
{ |
|||
new DivergenceStopCriterium(-0.1); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentOutOfRangeException] |
|||
public void CreateWithIllegalMinimumIterations() |
|||
{ |
|||
new DivergenceStopCriterium(2); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Create() |
|||
{ |
|||
var criterium = new DivergenceStopCriterium(0.1, 3); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
Assert.AreEqual(0.1, criterium.MaximumRelativeIncrease, "Incorrect maximum"); |
|||
Assert.AreEqual(3, criterium.MinimumNumberOfIterations, "Incorrect iteration count"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetMaximumIncrease() |
|||
{ |
|||
var criterium = new DivergenceStopCriterium(0.5, 3); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
Assert.AreEqual(0.5, criterium.MaximumRelativeIncrease, "Incorrect maximum"); |
|||
|
|||
criterium.ResetMaximumRelativeIncreaseToDefault(); |
|||
Assert.AreEqual(DivergenceStopCriterium.DefaultMaximumRelativeIncrease, criterium.MaximumRelativeIncrease, "Incorrect value"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetMinimumIterationsBelowMaximum() |
|||
{ |
|||
var criterium = new DivergenceStopCriterium(0.5, 15); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
Assert.AreEqual(15, criterium.MinimumNumberOfIterations, "Incorrect iteration count"); |
|||
|
|||
criterium.ResetNumberOfIterationsToDefault(); |
|||
Assert.AreEqual(DivergenceStopCriterium.DefaultMinimumNumberOfIterations, criterium.MinimumNumberOfIterations, "Incorrect value"); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentOutOfRangeException] |
|||
public void DetermineStatusWithIllegalIterationNumber() |
|||
{ |
|||
var criterium = new DivergenceStopCriterium(0.5, 15); |
|||
criterium.DetermineStatus(-1, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 5), |
|||
new DenseVector(3, 6)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DetermineStatusWithNullResidualVector() |
|||
{ |
|||
var criterium = new DivergenceStopCriterium(0.5, 15); |
|||
criterium.DetermineStatus(1, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 5), |
|||
null); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatusWithTooFewIterations() |
|||
{ |
|||
const float Increase = 0.5f; |
|||
const int Iterations = 10; |
|||
|
|||
var criterium = new DivergenceStopCriterium(Increase, Iterations); |
|||
|
|||
// Add residuals. We should not diverge because we'll have to few iterations
|
|||
for (var i = 0; i < Iterations - 1; i++) |
|||
{ |
|||
criterium.DetermineStatus(i, |
|||
new DenseVector(new [] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32((i + 1) * (Increase + 0.1f), 0) })); |
|||
|
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Status check fail."); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatusWithNoDivergence() |
|||
{ |
|||
const float Increase = 0.5f; |
|||
const int Iterations = 10; |
|||
|
|||
var criterium = new DivergenceStopCriterium(Increase, Iterations); |
|||
|
|||
// Add residuals. We should not diverge because we won't have enough increase
|
|||
for (var i = 0; i < Iterations * 2; i++) |
|||
{ |
|||
criterium.DetermineStatus(i, |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new [] { new Complex32((i + 1) * (Increase - 0.01f), 0) })); |
|||
|
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Status check fail."); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatusWithDivergenceThroughNaN() |
|||
{ |
|||
const float Increase = 0.5f; |
|||
const int Iterations = 10; |
|||
|
|||
var criterium = new DivergenceStopCriterium(Increase, Iterations); |
|||
|
|||
// Add residuals. We should not diverge because we'll have to few iterations
|
|||
for (var i = 0; i < Iterations - 5; i++) |
|||
{ |
|||
criterium.DetermineStatus(i, |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new [] { new Complex32((i + 1) * (Increase - 0.01f), 0) })); |
|||
|
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Status check fail."); |
|||
} |
|||
|
|||
// Now make it fail by throwing in a NaN
|
|||
criterium.DetermineStatus(Iterations, |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new [] { new Complex32(float.NaN, 0) })); |
|||
|
|||
Assert.IsInstanceOfType(typeof(CalculationDiverged), criterium.Status, "Status check fail."); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatusWithDivergence() |
|||
{ |
|||
const float Increase = 0.5f; |
|||
const int Iterations = 10; |
|||
|
|||
var criterium = new DivergenceStopCriterium(Increase, Iterations); |
|||
|
|||
// Add residuals. We should not diverge because we'll have one to few iterations
|
|||
float previous = 1; |
|||
for (var i = 0; i < Iterations - 1; i++) |
|||
{ |
|||
previous *= (1 + Increase + 0.01f); |
|||
criterium.DetermineStatus(i, |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(previous, 0) })); |
|||
|
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Status check fail."); |
|||
} |
|||
|
|||
// Add the final residual. Now we should have divergence
|
|||
previous *= (1 + Increase + 0.01f); |
|||
criterium.DetermineStatus(Iterations - 1, |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(previous, 0) })); |
|||
|
|||
Assert.IsInstanceOfType(typeof(CalculationDiverged), criterium.Status, "Status check fail."); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetCalculationState() |
|||
{ |
|||
const float Increase = 0.5f; |
|||
const int Iterations = 10; |
|||
|
|||
var criterium = new DivergenceStopCriterium(Increase, Iterations); |
|||
|
|||
// Add residuals. Blow it up instantly
|
|||
criterium.DetermineStatus(1, |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(1.0f, 0) }), |
|||
new DenseVector(new[] { new Complex32(float.NaN, 0) })); |
|||
|
|||
Assert.IsInstanceOfType(typeof(CalculationDiverged), criterium.Status, "Status check fail."); |
|||
|
|||
// Reset the state
|
|||
criterium.ResetToPrecalculationState(); |
|||
|
|||
Assert.AreEqual(Increase, criterium.MaximumRelativeIncrease, "Incorrect maximum"); |
|||
Assert.AreEqual(Iterations, criterium.MinimumNumberOfIterations, "Incorrect iteration count"); |
|||
Assert.IsInstanceOfType(typeof(CalculationIndetermined), criterium.Status, "Status check fail."); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Clone() |
|||
{ |
|||
const float Increase = 0.5f; |
|||
const int Iterations = 10; |
|||
|
|||
var criterium = new DivergenceStopCriterium(Increase, Iterations); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var clone = criterium.Clone(); |
|||
Assert.IsInstanceOfType(typeof(DivergenceStopCriterium), clone, "Wrong criterium type"); |
|||
|
|||
var clonedCriterium = clone as DivergenceStopCriterium; |
|||
Assert.IsNotNull(clonedCriterium); |
|||
// ReSharper disable PossibleNullReferenceException
|
|||
Assert.AreEqual(criterium.MaximumRelativeIncrease, clonedCriterium.MaximumRelativeIncrease, "Incorrect maximum"); |
|||
Assert.AreEqual(criterium.MinimumNumberOfIterations, clonedCriterium.MinimumNumberOfIterations, "Incorrect iteration count"); |
|||
// ReSharper restore PossibleNullReferenceException
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,134 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.StopCriterium |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers.StopCriterium; |
|||
using LinearAlgebra.Generic.Solvers.Status; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public sealed class FailureStopCriteriumTest |
|||
{ |
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Create() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "Should have a criterium now"); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentOutOfRangeException] |
|||
public void DetermineStatusWithIllegalIterationNumber() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(-1, new DenseVector(3, 4), new DenseVector(3, 5), new DenseVector(3, 6)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DetermineStatusWithNullSolutionVector() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(1, null, new DenseVector(3, 6), new DenseVector(4, 4)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DetermineStatusWithNullResidualVector() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(1, new DenseVector(3, 4), new DenseVector(3, 6), null); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void DetermineStatusWithNonMatchingVectors() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(1, new DenseVector(3, 4), new DenseVector(3, 6), new DenseVector(4, 4)); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatusWithResidualNaN() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var solution = new DenseVector(new[] { new Complex32(1.0f, 0), new Complex32(1.0f, 0), new Complex32(2.0f, 0) }); |
|||
var source = new DenseVector(new[] { new Complex32(1001.0f, 0), Complex32.Zero, new Complex32(2003.0f, 0) }); |
|||
var residual = new DenseVector(new[] { new Complex32(1000, 0), new Complex32(float.NaN, 0), new Complex32(2001, 0) }); |
|||
|
|||
criterium.DetermineStatus(5, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationFailure), criterium.Status, "Should be failed"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatusWithSolutionNaN() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var solution = new DenseVector(new[] { new Complex32(1.0f, 0), new Complex32(1.0f, 0), new Complex32(float.NaN, 0) }); |
|||
var source = new DenseVector(new[] { new Complex32(1001.0f, 0), Complex32.Zero, new Complex32(2003.0f, 0) }); |
|||
var residual = new DenseVector(new[] { new Complex32(1000, 0), new Complex32(1000, 0), new Complex32(2001, 0) }); |
|||
|
|||
criterium.DetermineStatus(5, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationFailure), criterium.Status, "Should be failed"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatus() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var solution = new DenseVector(new[] { new Complex32(3.0f, 0), new Complex32(2.0f, 0), new Complex32(1, 0) }); |
|||
var source = new DenseVector(new[] { new Complex32(1001.0f, 0), Complex32.Zero, new Complex32(2003.0f, 0) }); |
|||
var residual = new DenseVector(new[] { new Complex32(1.0f, 0), new Complex32(2.0f, 0), new Complex32(3, 0) }); |
|||
|
|||
criterium.DetermineStatus(5, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Should be running"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetCalculationState() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var solution = new DenseVector(new[] { new Complex32(1.0f, 0), new Complex32(1.0f, 0), new Complex32(2, 0) }); |
|||
var source = new DenseVector(new[] { new Complex32(1001.0f, 0), Complex32.Zero, new Complex32(2003.0f, 0) }); |
|||
var residual = new DenseVector(new[] { new Complex32(1000, 0), new Complex32(1000, 0), new Complex32(2001, 0) }); |
|||
|
|||
criterium.DetermineStatus(5, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Should be running"); |
|||
|
|||
criterium.ResetToPrecalculationState(); |
|||
Assert.IsInstanceOfType(typeof(CalculationIndetermined), criterium.Status, "Should not have started"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Clone() |
|||
{ |
|||
var criterium = new FailureStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var clone = criterium.Clone(); |
|||
Assert.IsInstanceOfType(typeof(FailureStopCriterium), clone, "Wrong criterium type"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.StopCriterium |
|||
{ |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers.StopCriterium; |
|||
using LinearAlgebra.Generic.Solvers.Status; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public sealed class IterationCountStopCriteriumTest |
|||
{ |
|||
[Test] |
|||
[ExpectedArgumentOutOfRangeException] |
|||
public void CreateWithIllegalMinimumIterations() |
|||
{ |
|||
new IterationCountStopCriterium(-1); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Create() |
|||
{ |
|||
var criterium = new IterationCountStopCriterium(10); |
|||
Assert.IsNotNull(criterium, "A criterium should have been created"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetMaximumIterations() |
|||
{ |
|||
var criterium = new IterationCountStopCriterium(10); |
|||
Assert.IsNotNull(criterium, "A criterium should have been created"); |
|||
Assert.AreEqual(10, criterium.MaximumNumberOfIterations, "Incorrect maximum number of iterations"); |
|||
|
|||
criterium.ResetMaximumNumberOfIterationsToDefault(); |
|||
Assert.AreNotEqual(10, criterium.MaximumNumberOfIterations, "Should have reset"); |
|||
Assert.AreEqual(IterationCountStopCriterium.DefaultMaximumNumberOfIterations, criterium.MaximumNumberOfIterations, "Reset to the wrong value"); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentOutOfRangeException] |
|||
public void DetermineStatusWithIllegalIterationNumber() |
|||
{ |
|||
var criterium = new IterationCountStopCriterium(10); |
|||
Assert.IsNotNull(criterium, "A criterium should have been created"); |
|||
|
|||
criterium.DetermineStatus(-1, new DenseVector(3, 1), new DenseVector(3, 2), new DenseVector(3,3)); |
|||
Assert.Fail(); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatus() |
|||
{ |
|||
var criterium = new IterationCountStopCriterium(10); |
|||
Assert.IsNotNull(criterium, "A criterium should have been created"); |
|||
|
|||
criterium.DetermineStatus(5, new DenseVector(3, 1), new DenseVector(3, 2), new DenseVector(3, 3)); |
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Should be running"); |
|||
|
|||
criterium.DetermineStatus(10, new DenseVector(3, 1), new DenseVector(3, 2), new DenseVector(3, 3)); |
|||
Assert.IsInstanceOfType(typeof(CalculationStoppedWithoutConvergence), criterium.Status, "Should be finished"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetCalculationState() |
|||
{ |
|||
var criterium = new IterationCountStopCriterium(10); |
|||
Assert.IsNotNull(criterium, "A criterium should have been created"); |
|||
|
|||
criterium.DetermineStatus(5, new DenseVector(3, 1), new DenseVector(3, 2), new DenseVector(3, 3)); |
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Should be running"); |
|||
|
|||
criterium.ResetToPrecalculationState(); |
|||
Assert.IsInstanceOfType(typeof(CalculationIndetermined), criterium.Status, "Should not have started"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Clone() |
|||
{ |
|||
var criterium = new IterationCountStopCriterium(10); |
|||
Assert.IsNotNull(criterium, "A criterium should have been created"); |
|||
Assert.AreEqual(10, criterium.MaximumNumberOfIterations, "Incorrect maximum"); |
|||
|
|||
var clone = criterium.Clone(); |
|||
Assert.IsInstanceOfType(typeof(IterationCountStopCriterium), clone, "Wrong criterium type"); |
|||
|
|||
var clonedCriterium = clone as IterationCountStopCriterium; |
|||
Assert.IsNotNull(clonedCriterium); |
|||
// ReSharper disable PossibleNullReferenceException
|
|||
Assert.AreEqual(criterium.MaximumNumberOfIterations, clonedCriterium.MaximumNumberOfIterations, "Clone failed"); |
|||
// ReSharper restore PossibleNullReferenceException
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,262 @@ |
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Solvers.StopCriterium |
|||
{ |
|||
using Numerics; |
|||
using LinearAlgebra.Complex32; |
|||
using LinearAlgebra.Complex32.Solvers.StopCriterium; |
|||
using LinearAlgebra.Generic.Solvers.Status; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public sealed class ResidualStopCriteriumTest |
|||
{ |
|||
[Test] |
|||
[ExpectedArgumentOutOfRangeException] |
|||
public void CreateWithNegativeMaximum() |
|||
{ |
|||
new ResidualStopCriterium(-0.1); |
|||
Assert.Fail(); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentOutOfRangeException] |
|||
public void CreateWithIllegalMinimumIterations() |
|||
{ |
|||
new ResidualStopCriterium(-1); |
|||
Assert.Fail(); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Create() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
Assert.AreEqual(1e-8, criterium.Maximum, "Incorrect maximum"); |
|||
Assert.AreEqual(50, criterium.MinimumIterationsBelowMaximum, "Incorrect iteration count"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetMaximum() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.ResetMaximumResidualToDefault(); |
|||
Assert.AreEqual(ResidualStopCriterium.DefaultMaximumResidual, criterium.Maximum, "Incorrect maximum"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetMinimumIterationsBelowMaximum() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.ResetMinimumIterationsBelowMaximumToDefault(); |
|||
Assert.AreEqual(ResidualStopCriterium.DefaultMinimumIterationsBelowMaximum, criterium.MinimumIterationsBelowMaximum, "Incorrect iteration count"); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentOutOfRangeException] |
|||
public void DetermineStatusWithIllegalIterationNumber() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(-1, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 5), |
|||
new DenseVector(3, 6)); |
|||
Assert.Fail(); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DetermineStatusWithNullSolutionVector() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(1, |
|||
null, |
|||
new DenseVector(3, 5), |
|||
new DenseVector(3, 6)); |
|||
Assert.Fail(); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DetermineStatusWithNullSourceVector() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(1, |
|||
new DenseVector(3, 4), |
|||
null, |
|||
new DenseVector(3, 6)); |
|||
Assert.Fail(); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DetermineStatusWithNullResidualVector() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(1, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 5), |
|||
null); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void DetermineStatusWithNonMatchingSolutionVector() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(1, |
|||
new DenseVector(4, 4), |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 4)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void DetermineStatusWithNonMatchingSourceVector() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(1, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(4, 4), |
|||
new DenseVector(3, 4)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void DetermineStatusWithNonMatchingResidualVector() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-8, 50); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
criterium.DetermineStatus(1, |
|||
new DenseVector(3, 4), |
|||
new DenseVector(3, 4), |
|||
new DenseVector(4, 4)); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatusWithSourceNaN() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-3, 10); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var solution = new DenseVector(new[] { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(2.0f, 1) }); |
|||
var source = new DenseVector(new[] { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(float.NaN, 1) }); |
|||
var residual = new DenseVector(new[] { new Complex32(1000.0f, 1), new Complex32(1000.0f, 1), new Complex32(2001.0f, 1) }); |
|||
|
|||
criterium.DetermineStatus(5, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationDiverged), criterium.Status, "Should be diverged"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatusWithResidualNaN() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-3, 10); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var solution = new DenseVector(new[] { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(2.0f, 1) }); |
|||
var source = new DenseVector(new[] { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(2.0f, 1) }); |
|||
var residual = new DenseVector(new[] { new Complex32(1000.0f, 1), new Complex32(float.NaN, 1), new Complex32(2001.0f, 1) }); |
|||
|
|||
criterium.DetermineStatus(5, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationDiverged), criterium.Status, "Should be diverged"); |
|||
} |
|||
|
|||
// Bugfix: The unit tests for the BiCgStab solver run with a super simple matrix equation
|
|||
// which converges at the first iteration. The default settings for the
|
|||
// residual stop criterium should be able to handle this.
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatusWithConvergenceAtFirstIteration() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var solution = new DenseVector(new[] { Complex32.One, Complex32.One, Complex32.One }); |
|||
var source = new DenseVector(new[] { Complex32.One, Complex32.One, Complex32.One }); |
|||
var residual = new DenseVector(new[] { Complex32.Zero, Complex32.Zero, Complex32.Zero }); |
|||
|
|||
criterium.DetermineStatus(0, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationConverged), criterium.Status, "Should be done"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void DetermineStatus() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-3, 10); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
// Note that the solution vector isn't actually being used so ...
|
|||
var solution = new DenseVector(new[] { new Complex32(float.NaN, float.NaN), new Complex32(float.NaN, float.NaN), new Complex32(float.NaN, float.NaN) }); |
|||
|
|||
// Set the source values
|
|||
var source = new DenseVector(new[] { new Complex32(1.000f, 1), new Complex32(1.000f, 1), new Complex32(2.001f, 1) }); |
|||
|
|||
// Set the residual values
|
|||
var residual = new DenseVector(new[] { new Complex32(0.001f, 0), new Complex32(0.001f, 0), new Complex32(0.002f, 0) }); |
|||
|
|||
criterium.DetermineStatus(5, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Should still be running"); |
|||
|
|||
criterium.DetermineStatus(16, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationConverged), criterium.Status, "Should be done"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ResetCalculationState() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-3, 10); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var solution = new DenseVector(new[] { new Complex32(0.001f, 1), new Complex32(0.001f, 1), new Complex32(0.002f, 1) }); |
|||
var source = new DenseVector(new[] { new Complex32(0.001f, 1), new Complex32(0.001f, 1), new Complex32(0.002f, 1) }); |
|||
var residual = new DenseVector(new[] { new Complex32(1.000f, 0), new Complex32(1.000f, 0), new Complex32(2.001f, 0) }); |
|||
|
|||
criterium.DetermineStatus(5, solution, source, residual); |
|||
Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Should be running"); |
|||
|
|||
criterium.ResetToPrecalculationState(); |
|||
Assert.IsInstanceOfType(typeof(CalculationIndetermined), criterium.Status, "Should not have started"); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void Clone() |
|||
{ |
|||
var criterium = new ResidualStopCriterium(1e-3, 10); |
|||
Assert.IsNotNull(criterium, "There should be a criterium"); |
|||
|
|||
var clone = criterium.Clone(); |
|||
Assert.IsInstanceOfType(typeof(ResidualStopCriterium), clone, "Wrong criterium type"); |
|||
|
|||
var clonedCriterium = clone as ResidualStopCriterium; |
|||
Assert.IsNotNull(clonedCriterium); |
|||
// ReSharper disable PossibleNullReferenceException
|
|||
Assert.AreEqual(criterium.Maximum, clonedCriterium.Maximum, "Clone failed"); |
|||
Assert.AreEqual(criterium.MinimumIterationsBelowMaximum, clonedCriterium.MinimumIterationsBelowMaximum, "Clone failed"); |
|||
// ReSharper restore PossibleNullReferenceException
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,164 @@ |
|||
// <copyright file="SparseMatrixTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System.Collections.Generic; |
|||
using Numerics; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32; |
|||
|
|||
public class SparseMatrixTests : MatrixTests |
|||
{ |
|||
protected override Matrix<Complex32> CreateMatrix(int rows, int columns) |
|||
{ |
|||
return new SparseMatrix(rows, columns); |
|||
} |
|||
|
|||
protected override Matrix<Complex32> CreateMatrix(Complex32[,] data) |
|||
{ |
|||
return new SparseMatrix(data); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new SparseVector(size); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(Complex32[] data) |
|||
{ |
|||
return new SparseVector(data); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateMatrixFrom1DArray() |
|||
{ |
|||
var testData = new Dictionary<string, Matrix<Complex32>> |
|||
{ |
|||
{ "Singular3x3", new SparseMatrix(3, 3, new[] { new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(2.0f, 1), new Complex32(2.0f, 1) }) }, |
|||
{ "Square3x3", new SparseMatrix(3, 3, new[] { new Complex32(-1.1f, 1), Complex32.Zero, new Complex32(-4.4f, 1), new Complex32(-2.2f, 1), new Complex32(1.1f, 1), new Complex32(5.5f, 1), new Complex32(-3.3f, 1), new Complex32(2.2f, 1), new Complex32(6.6f, 1) }) }, |
|||
{ "Square4x4", new SparseMatrix(4, 4, new[] { new Complex32(-1.1f, 1), Complex32.Zero, new Complex32(1.0f, 1), new Complex32(-4.4f, 1), new Complex32(-2.2f, 1), new Complex32(1.1f, 1), new Complex32(2.1f, 1), new Complex32(5.5f, 1), new Complex32(-3.3f, 1), new Complex32(2.2f, 1), new Complex32(6.2f, 1), new Complex32(6.6f, 1), new Complex32(-4.4f, 1), new Complex32(3.3f, 1), new Complex32(4.3f, 1), new Complex32(-7.7f, 1) }) }, |
|||
{ "Tall3x2", new SparseMatrix(3, 2, new[] { new Complex32(-1.1f, 1), Complex32.Zero, new Complex32(-4.4f, 1), new Complex32(-2.2f, 1), new Complex32(1.1f, 1), new Complex32(5.5f, 1) }) }, |
|||
{ "Wide2x3", new SparseMatrix(2, 3, new[] { new Complex32(-1.1f, 1), Complex32.Zero, new Complex32(-2.2f, 1), new Complex32(1.1f, 1), new Complex32(-3.3f, 1), new Complex32(2.2f, 1) }) } |
|||
}; |
|||
|
|||
foreach (var name in testData.Keys) |
|||
{ |
|||
Assert.AreEqual(TestMatrices[name], testData[name]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void MatrixFrom2DArrayIsCopy() |
|||
{ |
|||
var matrix = new SparseMatrix(TestData2D["Singular3x3"]); |
|||
matrix[0, 0] = 10.0f; |
|||
AssertHelpers.AreEqual(new Complex32(1.0f, 1), TestData2D["Singular3x3"][0, 0]); |
|||
} |
|||
|
|||
[Test] |
|||
[Row("Singular3x3")] |
|||
[Row("Singular3x3")] |
|||
[Row("Square3x3")] |
|||
[Row("Square4x4")] |
|||
[Row("Tall3x2")] |
|||
[Row("Wide2x3")] |
|||
public void CanCreateMatrixFrom2DArray(string name) |
|||
{ |
|||
var matrix = new SparseMatrix(TestData2D[name]); |
|||
for (var i = 0; i < TestData2D[name].GetLength(0); i++) |
|||
{ |
|||
for (var j = 0; j < TestData2D[name].GetLength(1); j++) |
|||
{ |
|||
AssertHelpers.AreEqual(TestData2D[name][i, j], matrix[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateMatrixWithUniformValues() |
|||
{ |
|||
var matrix = new SparseMatrix(10, 10, new Complex32(10.0f, 1)); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(matrix[i, j], new Complex32(10.0f, 1)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateIdentity() |
|||
{ |
|||
var matrix = SparseMatrix.Identity(5); |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (var j = 0; j < matrix.ColumnCount; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(i == j ? Complex32.One : Complex32.Zero, matrix[i, j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(0)] |
|||
[Row(-1)] |
|||
[ExpectedArgumentException] |
|||
public void IdentityFailsWithZeroOrNegativeOrder(int order) |
|||
{ |
|||
SparseMatrix.Identity(order); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateHeavySparseMatrix() |
|||
{ |
|||
var matrix = new SparseMatrix(500, 1000); |
|||
var nonzero = 0; |
|||
var rnd = new System.Random(); |
|||
|
|||
for (int i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
for (int j = 0; j < matrix.ColumnCount; j++ ) |
|||
{ |
|||
var value = rnd.Next(10) * rnd.Next(10) * rnd.Next(10) * rnd.Next(10) * rnd.Next(10); |
|||
if (value != 0) |
|||
{ |
|||
nonzero++; |
|||
} |
|||
matrix[i, j] = value; |
|||
} |
|||
} |
|||
|
|||
Assert.AreEqual(matrix.NonZerosCount, nonzero); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,99 @@ |
|||
// <copyright file="SparseVector.TextHandling.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using System.Globalization; |
|||
using LinearAlgebra.Complex32; |
|||
using MbUnit.Framework; |
|||
|
|||
public class SparseVectorTextHandlingTest |
|||
{ |
|||
[Test] |
|||
[Row("2", "2")] |
|||
[Row("(3)", "3")] |
|||
[Row("[1,2,3]", "1,2,3")]
|
|||
[Row(" [ 1.1 , 2.1 , 3.1 ] ", "1.1,2.1,3.1")]
|
|||
[Row(" [ -1.1 , 2.1 , +3.1 ] ", "-1.1,2.1,3.1")]
|
|||
[Row(" [1.2,3.4 , 5.6] ", "1.2,3.4,5.6")]
|
|||
[Row("[1+1i,2+1i,3+1i]", "1 + 1i,2 + 1i,3 + 1i")]
|
|||
[Row(" [ 1.1 + 1i , 2.1+1i , 3.1+1i ] ", "1.1 + 1i,2.1 + 1i,3.1 + 1i")]
|
|||
[Row(" [ -1.1 + 1i , 2.1-1i , +3.1+1i ] ", "-1.1 + 1i,2.1 - 1i,3.1 + 1i")]
|
|||
[Row(" [1.2+2.3i ,3.4+4.5i , 5.6+ 6.7i] ", "1.2 + 2.3i,3.4 + 4.5i,5.6 + 6.7i")]
|
|||
public void CanParseComplexSparseVectorsWithInvariant(string stringToParse, string expectedToString) |
|||
{ |
|||
var formatProvider = CultureInfo.InvariantCulture; |
|||
SparseVector vector = SparseVector.Parse(stringToParse, formatProvider); |
|||
|
|||
Assert.AreEqual(expectedToString, vector.ToString(formatProvider)); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(" 1.2 + 1i , 3.4 + 1i , 5.6 + 1i ", "1.2 + 1i,3.4 + 1i,5.6 + 1i", "en-US")] |
|||
[Row(" 1.2 + 1i ; 3.4 + 1i ; 5.6 + 1i ", "1.2 + 1i;3.4 + 1i;5.6 + 1i", "de-CH")] |
|||
[Row(" 1,2 + 1i ; 3,4 + 1i ; 5,6 + 1i ", "1,2 + 1i;3,4 + 1i;5,6 + 1i", "de-DE")] |
|||
public void CanParseComplexSparseVectorsWithCulture(string stringToParse, string expectedToString, string culture) |
|||
{ |
|||
var formatProvider = CultureInfo.GetCultureInfo(culture); |
|||
SparseVector vector = SparseVector.Parse(stringToParse, formatProvider); |
|||
|
|||
Assert.AreEqual(expectedToString, vector.ToString(formatProvider)); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ParseThrowsFormatExceptionIfMissingClosingParen() |
|||
{ |
|||
Assert.Throws<FormatException>(() => SparseVector.Parse("(1")); |
|||
Assert.Throws<FormatException>(() => SparseVector.Parse("[1")); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(null)] |
|||
[Row("")] |
|||
[Row(",")] |
|||
[Row("1,")] |
|||
[Row(",1")] |
|||
[Row(",1,2,")] |
|||
[Row("1,,2,,3")] |
|||
[Row("1e+")] |
|||
[Row("1e")] |
|||
[Row("()")] |
|||
[Row("[ ]")]
|
|||
public void TryParseReturnsFalseWhenGivenBadValueWithInvariant(string str) |
|||
{ |
|||
SparseVector vector; |
|||
var ret = SparseVector.TryParse(str, CultureInfo.InvariantCulture, out vector); |
|||
Assert.IsFalse(ret); |
|||
Assert.IsNull(vector); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,415 @@ |
|||
// <copyright file="SparseVectorTest.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Numerics; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
using LinearAlgebra.Complex32; |
|||
|
|||
public class SparseVectorTest : VectorTests |
|||
{ |
|||
protected override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new SparseVector(size); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(IList<Complex32> data) |
|||
{ |
|||
var vector = new SparseVector(data.Count); |
|||
for (var index = 0; index < data.Count; index++) |
|||
{ |
|||
vector[index] = data[index]; |
|||
} |
|||
return vector; |
|||
} |
|||
|
|||
#region Test similar to DenseVector
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateSparseVectorFromArray() |
|||
{ |
|||
var data = new Complex32[Data.Length]; |
|||
Array.Copy(Data, data, Data.Length); |
|||
var vector = new SparseVector(data); |
|||
|
|||
for (var i = 0; i < data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(data[i], vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateSparseVectorFromAnotherSparseVector() |
|||
{ |
|||
var vector = new SparseVector(Data); |
|||
var other = new SparseVector(vector); |
|||
|
|||
Assert.AreNotSame(vector, other); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateSparseVectorFromAnotherVector() |
|||
{ |
|||
var vector = (Vector<Complex32>)new SparseVector(Data); |
|||
var other = new SparseVector(vector); |
|||
|
|||
Assert.AreNotSame(vector, other); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateSparseVectorFromUserDefinedVector() |
|||
{ |
|||
var vector = new UserDefinedVector(Data); |
|||
var other = new SparseVector(vector); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateSparseVectorWithConstantValues() |
|||
{ |
|||
var vector = new SparseVector(5, new Complex32(5, 1)); |
|||
Assert.ForAll(vector, value => value == new Complex32(5,1)); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateSparseMatrix() |
|||
{ |
|||
var vector = new SparseVector(3); |
|||
var matrix = vector.CreateMatrix(2, 3); |
|||
Assert.AreEqual(2, matrix.RowCount); |
|||
Assert.AreEqual(3, matrix.ColumnCount); |
|||
} |
|||
|
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanConvertSparseVectorToArray() |
|||
{ |
|||
var vector = new SparseVector(Data); |
|||
var array = vector.ToArray(); |
|||
Assert.IsInstanceOfType(typeof(Complex32[]), array); |
|||
Assert.AreElementsEqual(vector, array); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanConvertArrayToSparseVector() |
|||
{ |
|||
var array = new[] { Complex32.Zero, new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1), new Complex32(4.0f, 1) }; |
|||
var vector = new SparseVector(array); |
|||
Assert.IsInstanceOfType(typeof(SparseVector), vector); |
|||
Assert.AreElementsEqual(array, array); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCallUnaryPlusOperatorOnSparseVector() |
|||
{ |
|||
var vector = new SparseVector(Data); |
|||
var other = +vector; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanAddTwoSparseVectorsUsingOperator() |
|||
{ |
|||
var vector = new SparseVector(Data); |
|||
var other = new SparseVector(Data); |
|||
var result = vector + other; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCallUnaryNegationOperatorOnSparseVector() |
|||
{ |
|||
var vector = new SparseVector(Data); |
|||
var other = -vector; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(-Data[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanSubtractTwoSparseVectorsUsingOperator() |
|||
{ |
|||
var vector = new SparseVector(Data); |
|||
var other = new SparseVector(Data); |
|||
var result = vector - other; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(Complex32.Zero, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanMultiplySparseVectorByComplexUsingOperators() |
|||
{ |
|||
var vector = new SparseVector(Data); |
|||
vector = vector * new Complex32(2.0f, 1); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
|
|||
vector = vector * 1.0f; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
|
|||
vector = new SparseVector(Data); |
|||
vector = new Complex32(2.0f, 1) * vector; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
|
|||
vector = 1.0f * vector; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanDivideSparseVectorByComplexUsingOperators() |
|||
{ |
|||
var vector = new SparseVector(Data); |
|||
vector = vector / new Complex32(2.0f, 1); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
|
|||
vector = vector / 1.0f; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / new Complex32(2.0f, 1), vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCalculateOuterProductForSparseVector() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = CreateVector(Data); |
|||
Matrix<Complex32> m = Vector<Complex32>.OuterProduct(vector1, vector2); |
|||
for (var i = 0; i < vector1.Count; i++) |
|||
{ |
|||
for (var j = 0; j < vector2.Count; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(m[i, j], vector1[i] * vector2[j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void OuterProducForSparseVectortWithFirstParameterNullShouldThrowException() |
|||
{ |
|||
SparseVector vector1 = null; |
|||
var vector2 = CreateVector(Data); |
|||
Vector<Complex32>.OuterProduct(vector1, vector2); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void OuterProductForSparseVectorWithSecondParameterNullShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
SparseVector vector2 = null; |
|||
Vector<Complex32>.OuterProduct(vector1, vector2); |
|||
} |
|||
#endregion
|
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCreateSparseVectorFromDenseVector() |
|||
{ |
|||
var vector = (Vector<Complex32>)new DenseVector(Data); |
|||
var other = new SparseVector(vector); |
|||
|
|||
Assert.AreNotSame(vector, other); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CheckSparseMechanismBySettingValues() |
|||
{ |
|||
var vector = new SparseVector(10000); |
|||
|
|||
//Add non-zero elements
|
|||
vector[200] = 1.5f; |
|||
AssertHelpers.AreEqual(1.5f, vector[200]); |
|||
Assert.AreEqual(1, vector.NonZerosCount); |
|||
|
|||
vector[500] = 3.5f; |
|||
AssertHelpers.AreEqual(3.5f, vector[500]); |
|||
Assert.AreEqual(2, vector.NonZerosCount); |
|||
|
|||
vector[800] = 5.5f; |
|||
AssertHelpers.AreEqual(5.5f, vector[800]); |
|||
Assert.AreEqual(3, vector.NonZerosCount); |
|||
|
|||
vector[0] = 7.5f; |
|||
AssertHelpers.AreEqual(7.5f, vector[0]); |
|||
Assert.AreEqual(4, vector.NonZerosCount); |
|||
|
|||
//Remove non-zero elements
|
|||
vector[200] = 0; |
|||
AssertHelpers.AreEqual(0, vector[200]); |
|||
Assert.AreEqual(3, vector.NonZerosCount); |
|||
|
|||
vector[500] = 0; |
|||
AssertHelpers.AreEqual(0, vector[500]); |
|||
Assert.AreEqual(2, vector.NonZerosCount); |
|||
|
|||
vector[800] = 0; |
|||
AssertHelpers.AreEqual(0, vector[800]); |
|||
Assert.AreEqual(1, vector.NonZerosCount); |
|||
|
|||
vector[0] = 0; |
|||
AssertHelpers.AreEqual(0, vector[0]); |
|||
Assert.AreEqual(0, vector.NonZerosCount); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CheckSparseMechanismByZeroMultiply() |
|||
{ |
|||
var vector = new SparseVector(10000); |
|||
|
|||
//Add non-zero elements
|
|||
vector[200] = 1.5f; |
|||
vector[500] = 3.5f; |
|||
vector[800] = 5.5f; |
|||
vector[0] = 7.5f; |
|||
|
|||
//Multiply by 0
|
|||
vector *= 0; |
|||
AssertHelpers.AreEqual(0, vector[200]); |
|||
AssertHelpers.AreEqual(0, vector[500]); |
|||
AssertHelpers.AreEqual(0, vector[800]); |
|||
AssertHelpers.AreEqual(0, vector[0]); |
|||
Assert.AreEqual(0, vector.NonZerosCount); |
|||
} |
|||
|
|||
|
|||
[Test] |
|||
public void CanDotProductOfTwoSparseVectors() |
|||
{ |
|||
var vectorA = new SparseVector(10000); |
|||
vectorA[200] = 1; |
|||
vectorA[500] = 3; |
|||
vectorA[800] = 5; |
|||
vectorA[100] = 7; |
|||
vectorA[900] = 9; |
|||
|
|||
var vectorB = new SparseVector(10000); |
|||
vectorB[300] = 3; |
|||
vectorB[500] = 5; |
|||
vectorB[800] = 7; |
|||
|
|||
|
|||
AssertHelpers.AreEqual(50.0f, vectorA.DotProduct(vectorB)); |
|||
} |
|||
|
|||
[Test] |
|||
public void CreateHugeSparseVector() |
|||
{ |
|||
var data = new Complex32[1000000]; |
|||
var rnd = new Random(); |
|||
for (var i = 0; i < 1000000; i++) |
|||
data[i] = new Complex32(rnd.Next(), rnd.Next()); |
|||
|
|||
var vector = new SparseVector(data); |
|||
} |
|||
|
|||
[Test] |
|||
public void PointwiseMultiplySparseVector() |
|||
{ |
|||
var zeroArray = new[] { Complex32.Zero, new Complex32(1.0f, 1), Complex32.Zero, new Complex32(1.0f, 1), Complex32.Zero }; |
|||
var vector1 = new SparseVector(Data); |
|||
var vector2 = new SparseVector(zeroArray); |
|||
var result = new SparseVector(vector1.Count); |
|||
|
|||
vector1.PointwiseMultiply(vector2, result); |
|||
|
|||
for (var i = 0; i < vector1.Count; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * zeroArray[i], result[i]); |
|||
} |
|||
Assert.AreEqual(2, result.NonZerosCount); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,210 @@ |
|||
// <copyright file="UserDefinedMatrixTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using Distributions; |
|||
using LinearAlgebra.Generic; |
|||
using Threading; |
|||
|
|||
internal class UserDefinedMatrix : Matrix<Complex32> |
|||
{ |
|||
private readonly Complex32[,] _data; |
|||
|
|||
public UserDefinedMatrix(int order): base(order, order) |
|||
{ |
|||
_data = new Complex32[order, order]; |
|||
} |
|||
|
|||
public UserDefinedMatrix(int rows, int columns) : base(rows, columns) |
|||
{ |
|||
_data = new Complex32[rows, columns]; |
|||
} |
|||
|
|||
public UserDefinedMatrix(Complex32[,] data) : base(data.GetLength(0), data.GetLength(1)) |
|||
{ |
|||
_data = (Complex32[,])data.Clone(); |
|||
} |
|||
|
|||
public override Complex32 At(int row, int column) |
|||
{ |
|||
return _data[row, column]; |
|||
} |
|||
|
|||
public override void At(int row, int column, Complex32 value) |
|||
{ |
|||
_data[row, column] = value; |
|||
} |
|||
|
|||
public override Matrix<Complex32> CreateMatrix(int numberOfRows, int numberOfColumns) |
|||
{ |
|||
return new UserDefinedMatrix(numberOfRows, numberOfColumns); |
|||
} |
|||
|
|||
public override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new UserDefinedVector(size); |
|||
} |
|||
|
|||
public static UserDefinedMatrix Identity(int order) |
|||
{ |
|||
var m = new UserDefinedMatrix(order, order); |
|||
for (var i = 0; i < order; i++) |
|||
{ |
|||
m[i, i] = 1.0f; |
|||
} |
|||
|
|||
return m; |
|||
} |
|||
|
|||
public override void Negate() |
|||
{ |
|||
Multiply(-Complex32.One); |
|||
} |
|||
|
|||
public override Matrix<Complex32> Random(int numberOfRows, int numberOfColumns, IContinuousDistribution distribution) |
|||
{ |
|||
if (numberOfRows < 1) |
|||
{ |
|||
throw new ArgumentException("numberOfRows"); |
|||
} |
|||
|
|||
if (numberOfColumns < 1) |
|||
{ |
|||
throw new ArgumentException("numberOfColumns"); |
|||
} |
|||
|
|||
var matrix = CreateMatrix(numberOfRows, numberOfColumns); |
|||
CommonParallel.For( |
|||
0, |
|||
ColumnCount, |
|||
j => |
|||
{ |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
matrix[i, j] = new Complex32((float)distribution.Sample(), (float)distribution.Sample()); |
|||
} |
|||
}); |
|||
|
|||
return matrix; |
|||
} |
|||
|
|||
public override Matrix<Complex32> Random(int numberOfRows, int numberOfColumns, IDiscreteDistribution distribution) |
|||
{ |
|||
if (numberOfRows < 1) |
|||
{ |
|||
throw new ArgumentException("numberOfRows"); |
|||
} |
|||
|
|||
if (numberOfColumns < 1) |
|||
{ |
|||
throw new ArgumentException("numberOfColumns"); |
|||
} |
|||
|
|||
var matrix = CreateMatrix(numberOfRows, numberOfColumns); |
|||
CommonParallel.For( |
|||
0, |
|||
ColumnCount, |
|||
j => |
|||
{ |
|||
for (var i = 0; i < matrix.RowCount; i++) |
|||
{ |
|||
matrix[i, j] = new Complex32(distribution.Sample(), distribution.Sample()); |
|||
} |
|||
}); |
|||
|
|||
return matrix; |
|||
} |
|||
|
|||
protected sealed override Complex32 AddT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 + val2; |
|||
} |
|||
|
|||
protected sealed override Complex32 SubtractT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 - val2; |
|||
} |
|||
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
protected sealed override Complex32 DivideT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 / val2; |
|||
} |
|||
|
|||
protected sealed override double AbsoluteT(Complex32 val1) |
|||
{ |
|||
return val1.Magnitude; |
|||
} |
|||
|
|||
public override Matrix<Complex32> ConjugateTranspose() |
|||
{ |
|||
var ret = CreateMatrix(ColumnCount, RowCount); |
|||
for (var j = 0; j < ColumnCount; j++) |
|||
{ |
|||
for (var i = 0; i < RowCount; i++) |
|||
{ |
|||
ret.At(j, i, At(i, j).Conjugate()); |
|||
} |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
} |
|||
|
|||
public class UserDefinedMatrixTests : MatrixTests |
|||
{ |
|||
protected override Matrix<Complex32> CreateMatrix(int rows, int columns) |
|||
{ |
|||
return new UserDefinedMatrix(rows, columns); |
|||
} |
|||
|
|||
protected override Matrix<Complex32> CreateMatrix(Complex32[,] data) |
|||
{ |
|||
return new UserDefinedMatrix(data); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new UserDefinedVector(size); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(Complex32[] data) |
|||
{ |
|||
return new UserDefinedVector(data); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,220 @@ |
|||
// <copyright file="UserDefinedVectorTests.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using System.Collections.Generic; |
|||
using Distributions; |
|||
using LinearAlgebra.Generic; |
|||
using Threading; |
|||
|
|||
internal class UserDefinedVector : Vector<Complex32> |
|||
{ |
|||
private readonly Complex32[] _data; |
|||
|
|||
public UserDefinedVector(int size) |
|||
: base(size) |
|||
{ |
|||
_data = new Complex32[size]; |
|||
} |
|||
|
|||
public UserDefinedVector(Complex32[] data) |
|||
: base(data.Length) |
|||
{ |
|||
_data = (Complex32[])data.Clone(); |
|||
} |
|||
|
|||
public override Complex32 this[int index] |
|||
{ |
|||
get |
|||
{ |
|||
return _data[index]; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
_data[index] = value; |
|||
} |
|||
} |
|||
|
|||
public override Matrix<Complex32> CreateMatrix(int rows, int columns) |
|||
{ |
|||
return new UserDefinedMatrix(rows, columns); |
|||
} |
|||
|
|||
public override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new UserDefinedVector(size); |
|||
} |
|||
|
|||
public override Vector<Complex32> Negate() |
|||
{ |
|||
var result = new UserDefinedVector(Count); |
|||
CommonParallel.For( |
|||
0, |
|||
_data.Length, |
|||
index => result[index] = -_data[index]); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
public override Vector<Complex32> Random(int length, IContinuousDistribution randomDistribution) |
|||
{ |
|||
if (length < 1) |
|||
{ |
|||
throw new ArgumentException("length"); |
|||
} |
|||
|
|||
var v = (UserDefinedVector)CreateVector(length); |
|||
for (var index = 0; index < v._data.Length; index++) |
|||
{ |
|||
v._data[index] = new Complex32((float)randomDistribution.Sample(), (float)randomDistribution.Sample()); |
|||
} |
|||
|
|||
return v; |
|||
} |
|||
|
|||
public override Vector<Complex32> Random(int length, IDiscreteDistribution randomDistribution) |
|||
{ |
|||
if (length < 1) |
|||
{ |
|||
throw new ArgumentException("length"); |
|||
} |
|||
|
|||
var v = (UserDefinedVector)CreateVector(length); |
|||
for (var index = 0; index < v._data.Length; index++) |
|||
{ |
|||
v._data[index] = new Complex32(randomDistribution.Sample(), randomDistribution.Sample()); |
|||
} |
|||
|
|||
return v; |
|||
} |
|||
|
|||
public override int MinimumIndex() |
|||
{ |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
public override int MaximumIndex() |
|||
{ |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
public override Vector<Complex32> Normalize(double p) |
|||
{ |
|||
if (p < 0.0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("p"); |
|||
} |
|||
|
|||
var norm = Norm(p); |
|||
var clone = Clone(); |
|||
if (norm == 0.0) |
|||
{ |
|||
return clone; |
|||
} |
|||
|
|||
clone.Multiply(1.0f / (float)norm, clone); |
|||
|
|||
return clone; |
|||
} |
|||
|
|||
protected sealed override Complex32 AddT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 + val2; |
|||
} |
|||
|
|||
protected sealed override Complex32 SubtractT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 - val2; |
|||
} |
|||
|
|||
protected sealed override Complex32 MultiplyT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 * val2; |
|||
} |
|||
|
|||
protected sealed override Complex32 DivideT(Complex32 val1, Complex32 val2) |
|||
{ |
|||
return val1 / val2; |
|||
} |
|||
|
|||
protected sealed override double AbsoluteT(Complex32 val1) |
|||
{ |
|||
return val1.Magnitude; |
|||
} |
|||
|
|||
public override void Conjugate(Vector<Complex32> target) |
|||
{ |
|||
if (target == null) |
|||
{ |
|||
throw new ArgumentNullException("target"); |
|||
} |
|||
|
|||
if (Count != target.Count) |
|||
{ |
|||
throw new ArgumentException("target"); |
|||
} |
|||
|
|||
if (ReferenceEquals(this, target)) |
|||
{ |
|||
var tmp = CreateVector(Count); |
|||
Conjugate(tmp); |
|||
tmp.CopyTo(target); |
|||
} |
|||
|
|||
CommonParallel.For( |
|||
0, |
|||
Count, |
|||
index => target[index] = this[index].Conjugate()); |
|||
} |
|||
} |
|||
|
|||
public class UserDefinedVectorTests : VectorTests |
|||
{ |
|||
protected override Vector<Complex32> CreateVector(int size) |
|||
{ |
|||
return new UserDefinedVector(size); |
|||
} |
|||
|
|||
protected override Vector<Complex32> CreateVector(IList<Complex32> data) |
|||
{ |
|||
var vector = new UserDefinedVector(data.Count); |
|||
for (var index = 0; index < data.Count; index++) |
|||
{ |
|||
vector[index] = data[index]; |
|||
} |
|||
|
|||
return vector; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,902 @@ |
|||
// <copyright file="VectorTests.Arithmetic.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-2010 Math.NET
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
|
|||
public abstract partial class VectorTests |
|||
{ |
|||
[Test] |
|||
public void CanCallPlus() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = vector.Plus(); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void OperatorPlusThrowsArgumentNullExceptionWhenCallOnNullVector() |
|||
{ |
|||
Vector<Complex32> vector = null; |
|||
Vector<Complex32> other = null; |
|||
Assert.Throws<ArgumentNullException>(() => other = +vector); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCallUnaryPlusOperator() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = +vector; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanAddScalarToVector() |
|||
{ |
|||
var copy = CreateVector(Data); |
|||
var vector = copy.Add(2.0f); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] + 2.0f, vector[i]); |
|||
} |
|||
|
|||
vector.Add(0.0f); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] + 2.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanAddScalarToVectorUsingResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var result = CreateVector(Data.Length); |
|||
vector.Add(2.0f, result); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i] + 2.0f, result[i]); |
|||
} |
|||
|
|||
vector.Add(0.0f, result); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentNullExceptionWhenAddingScalarWithNullResultVector() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
Assert.Throws<ArgumentNullException>(() => vector.Add(0.0f, null)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentExceptionWhenAddingScalarWithWrongSizeResultVector() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var result = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => vector.Add(0.0f, result)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentNullExceptionWhenAddingTwoVectorsAndOneIsNull() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
Assert.Throws<ArgumentNullException>(() => vector.Add(null)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentExceptionWhenAddingTwoVectorsOfDifferingSize() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var other = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => vector.Add(other)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentNullExceptionWhenAddingTwoVectorsAndResultIsNull() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var other = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentNullException>(() => vector.Add(other, null)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentExceptionWhenAddingTwoVectorsAndResultIsDifferentSize() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var other = CreateVector(Data.Length); |
|||
var result = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => vector.Add(other, result)); |
|||
} |
|||
|
|||
[Test] |
|||
public void AdditionOperatorThrowsArgumentNullExpectionIfAVectorIsNull() |
|||
{ |
|||
Vector<Complex32> a = null; |
|||
var b = CreateVector(Data.Length); |
|||
Assert.Throws<ArgumentNullException>(() => a += b); |
|||
|
|||
a = b; |
|||
b = null; |
|||
Assert.Throws<ArgumentNullException>(() => a += b); |
|||
} |
|||
|
|||
[Test] |
|||
public void AdditionOperatorThrowsArgumentExpectionIfVectorsAreDifferentSize() |
|||
{ |
|||
var a = CreateVector(Data.Length); |
|||
var b = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => a += b); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanAddTwoVectors() |
|||
{ |
|||
var copy = CreateVector(Data); |
|||
var other = CreateVector(Data); |
|||
var vector = copy.Add(other); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanAddTwoVectorsUsingResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = CreateVector(Data); |
|||
var result = CreateVector(Data.Length); |
|||
vector.Add(other, result); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanAddTwoVectorsUsingOperator() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = CreateVector(Data); |
|||
var result = vector + other; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanAddVectorToItself() |
|||
{ |
|||
var copy = CreateVector(Data); |
|||
var vector = copy.Add(copy); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanAddVectorToItselfUsingResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var result = CreateVector(Data.Length); |
|||
vector.Add(vector, result); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanAddTwoVectorsUsingItselfAsResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = CreateVector(Data); |
|||
vector.Add(other, vector); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCallNegate() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = vector.Negate(); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(-Data[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void OperatorNegateThrowsArgumentNullExceptionWhenCallOnNullVector() |
|||
{ |
|||
Vector<Complex32> vector = null; |
|||
Vector<Complex32> other = null; |
|||
Assert.Throws<ArgumentNullException>(() => other = -vector); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCallUnaryNegationOperator() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = -vector; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(-Data[i], other[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanSubtractScalarFromVector() |
|||
{ |
|||
var copy = CreateVector(Data); |
|||
var vector = copy.Subtract(2.0f); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] - 2.0f, vector[i]); |
|||
} |
|||
|
|||
vector.Subtract(0.0f); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] - 2.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanSubtractScalarFromVectorUsingResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var result = CreateVector(Data.Length); |
|||
vector.Subtract(2.0f, result); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i] - 2.0f, result[i]); |
|||
} |
|||
|
|||
vector.Subtract(0.0f, result); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentNullExceptionWhenSubtractingScalarWithNullResultVector() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
Assert.Throws<ArgumentNullException>(() => vector.Subtract(0.0f, null)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentExceptionWhenSubtractingScalarWithWrongSizeResultVector() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var result = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => vector.Subtract(0.0f, result)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentNullExceptionWhenSubtractingTwoVectorsAndOneIsNull() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
Assert.Throws<ArgumentNullException>(() => vector.Subtract(null)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentExceptionWhenSubtractingTwoVectorsOfDifferingSize() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var other = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => vector.Subtract(other)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentNullExceptionWhenSubtractingTwoVectorsAndResultIsNull() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var other = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentNullException>(() => vector.Subtract(other, null)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentExceptionWhenSubtractingTwoVectorsAndResultIsDifferentSize() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var other = CreateVector(Data.Length); |
|||
var result = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => vector.Subtract(other, result)); |
|||
} |
|||
|
|||
[Test] |
|||
public void SubtractionOperatorThrowsArgumentNullExpectionIfAVectorIsNull() |
|||
{ |
|||
Vector<Complex32> a = null; |
|||
var b = CreateVector(Data.Length); |
|||
Assert.Throws<ArgumentNullException>(() => a -= b); |
|||
|
|||
a = b; |
|||
b = null; |
|||
Assert.Throws<ArgumentNullException>(() => a -= b); |
|||
} |
|||
|
|||
[Test] |
|||
public void SubtractionOperatorThrowsArgumentExpectionIfVectorsAreDifferentSize() |
|||
{ |
|||
var a = CreateVector(Data.Length); |
|||
var b = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => a -= b); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanSubtractTwoVectors() |
|||
{ |
|||
var copy = CreateVector(Data); |
|||
var other = CreateVector(Data); |
|||
var vector = copy.Subtract(other); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(0.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanSubtractTwoVectorsUsingResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = CreateVector(Data); |
|||
var result = CreateVector(Data.Length); |
|||
vector.Subtract(other, result); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(0.0f, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanSubtractTwoVectorsUsingOperator() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = CreateVector(Data); |
|||
var result = vector - other; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(0.0f, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanSubtractVectorFromItself() |
|||
{ |
|||
var copy = CreateVector(Data); |
|||
var vector = copy.Subtract(copy); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(0.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanSubtractVectorFromItselfUsingResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var result = CreateVector(Data.Length); |
|||
vector.Subtract(vector, result); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(0.0f, result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanSubtractTwoVectorsUsingItselfAsResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = CreateVector(Data); |
|||
vector.Subtract(other, vector); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], other[i]); |
|||
AssertHelpers.AreEqual(0.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanDivideVectorByScalar() |
|||
{ |
|||
var copy = CreateVector(Data); |
|||
var vector = copy.Divide(2.0f); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / 2.0f, vector[i]); |
|||
} |
|||
|
|||
vector.Divide(1.0f); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / 2.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanDivideVectorByScalarUsingResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var result = CreateVector(Data.Length); |
|||
vector.Divide(2.0f, result); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i] / 2.0f, result[i]); |
|||
} |
|||
|
|||
vector.Divide(1.0f, result); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanMultiplyVectorByScalar() |
|||
{ |
|||
var copy = CreateVector(Data); |
|||
var vector = copy.Multiply(2.0f); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, vector[i]); |
|||
} |
|||
|
|||
vector.Multiply(1.0f); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanMultiplyVectorByScalarUsingResultVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var result = CreateVector(Data.Length); |
|||
vector.Multiply(2.0f, result); |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], vector[i]); |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, result[i]); |
|||
} |
|||
|
|||
vector.Multiply(1.0f, result); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i], result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentNullExceptionWhenMultiplyingScalarWithNullResultVector() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
Assert.Throws<ArgumentNullException>(() => vector.Multiply(1.0f, null)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentNullExceptionWhenDividingScalarWithNullResultVector() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
Assert.Throws<ArgumentNullException>(() => vector.Divide(1.0f, null)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentExceptionWhenMultiplyingScalarWithWrongSizeResultVector() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var result = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => vector.Multiply(0.0f, result)); |
|||
} |
|||
|
|||
[Test] |
|||
public void ThrowsArgumentExceptionWhenDividingScalarWithWrongSizeResultVector() |
|||
{ |
|||
var vector = CreateVector(Data.Length); |
|||
var result = CreateVector(Data.Length + 1); |
|||
Assert.Throws<ArgumentException>(() => vector.Divide(0.0f, result)); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanMultiplyVectorByScalarUsingOperators() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
vector = vector * 2.0f; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, vector[i]); |
|||
} |
|||
|
|||
vector = vector * 1.0f; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, vector[i]); |
|||
} |
|||
|
|||
vector = CreateVector(Data); |
|||
vector = 2.0f * vector; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, vector[i]); |
|||
} |
|||
|
|||
vector = 1.0f * vector; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * 2.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanDivideVectorByScalarUsingOperators() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
vector = vector / 2.0f; |
|||
|
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / 2.0f, vector[i]); |
|||
} |
|||
|
|||
vector = vector / 1.0f; |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / 2.0f, vector[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void OperatorMultiplyThrowsArgumentNullExceptionWhenVectorIsNull() |
|||
{ |
|||
Vector<Complex32> vector = null; |
|||
Vector<Complex32> result = null; |
|||
Assert.Throws<ArgumentNullException>(() => result = vector * 2.0f); |
|||
Assert.Throws<ArgumentNullException>(() => result = 2.0f * vector); |
|||
} |
|||
|
|||
[Test] |
|||
public void OperatorDivideThrowsArgumentNullExceptionWhenVectorIsNull() |
|||
{ |
|||
Vector<Complex32> vector = null; |
|||
Assert.Throws<ArgumentNullException>(() => vector = vector / 2.0f); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanDotProduct() |
|||
{ |
|||
var dataA = CreateVector(Data); |
|||
var dataB = CreateVector(Data); |
|||
|
|||
AssertHelpers.AreEqual(new Complex32(50, 30), dataA.DotProduct(dataB)); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void DotProductThrowsExceptionWhenArgumentIsNull() |
|||
{ |
|||
var dataA = CreateVector(Data); |
|||
Vector<Complex32> dataB = null; |
|||
|
|||
dataA.DotProduct(dataB); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void DotProductThrowsExceptionWhenArgumentHasDifferentSize() |
|||
{ |
|||
var dataA = CreateVector(Data); |
|||
var dataB = CreateVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1), new Complex32(6, 1) }); |
|||
|
|||
dataA.DotProduct(dataB); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanDotProductUsingOperator() |
|||
{ |
|||
var dataA = CreateVector(Data); |
|||
var dataB = CreateVector(Data); |
|||
|
|||
AssertHelpers.AreEqual(new Complex32(50, 30), dataA * dataB); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void OperatorDotProductThrowsExceptionWhenLeftArgumentIsNull() |
|||
{ |
|||
var dataA = CreateVector(Data); |
|||
Vector<Complex32> dataB = null; |
|||
|
|||
var d = dataA * dataB; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void OperatorDotProductThrowsExceptionWhenRightArgumentIsNull() |
|||
{ |
|||
Vector<Complex32> dataA = null; |
|||
var dataB = CreateVector(Data); |
|||
|
|||
var d = dataA * dataB; |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void OperatorDotProductThrowsExceptionWhenArgumentHasDifferentSize() |
|||
{ |
|||
var dataA = CreateVector(Data); |
|||
var dataB = CreateVector(new[] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1), new Complex32(6, 1) }); |
|||
|
|||
var d = dataA * dataB; |
|||
} |
|||
|
|||
[Test] |
|||
public void PointwiseMultiply() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = vector1.Clone(); |
|||
var result = vector1.PointwiseMultiply(vector2); |
|||
for (var i = 0; i < vector1.Count; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] * Data[i], result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void PointwiseMultiplyWithOtherNullShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
Vector<Complex32> vector2 = null; |
|||
var result = CreateVector(vector1.Count); |
|||
vector1.PointwiseMultiply(vector2, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void PointwiseMultiplyWithResultNullShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = vector1.Clone(); |
|||
Vector<Complex32> result = null; |
|||
vector1.PointwiseMultiply(vector2, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void PointwiseMultiplyWithInvalidResultLengthShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = vector1.Clone(); |
|||
var result = CreateVector(vector1.Count + 1); |
|||
vector1.PointwiseMultiply(vector2, result); |
|||
} |
|||
|
|||
[Test] |
|||
public void PointwiseMultiplyUsingResultVector() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = vector1.Clone(); |
|||
var result = CreateVector(vector1.Count); |
|||
vector1.PointwiseMultiply(vector2, result); |
|||
for (var i = 0; i < vector1.Count; i++) |
|||
{ |
|||
Assert.AreEqual(Data[i] * Data[i], result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void PointWiseDivide() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = vector1.Clone(); |
|||
var result = vector1.PointwiseDivide(vector2); |
|||
for (var i = 0; i < vector1.Count; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / Data[i], result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void PointwiseDivideWithOtherNullShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
Vector<Complex32> vector2 = null; |
|||
var result = CreateVector(vector1.Count); |
|||
vector1.PointwiseDivide(vector2, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void PointwiseDivideWithResultNullShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = vector1.Clone(); |
|||
Vector<Complex32> result = null; |
|||
vector1.PointwiseDivide(vector2, result); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void PointwiseDivideWithInvalidResultLengthShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = vector1.Clone(); |
|||
var result = CreateVector(vector1.Count + 1); |
|||
vector1.PointwiseDivide(vector2, result); |
|||
} |
|||
|
|||
[Test] |
|||
public void PointWiseDivideUsingResultVector() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = vector1.Clone(); |
|||
var result = CreateVector(vector1.Count); |
|||
vector1.PointwiseDivide(vector2, result); |
|||
for (var i = 0; i < vector1.Count; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[i] / Data[i], result[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCalculateOuterProduct() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = CreateVector(Data); |
|||
Matrix<Complex32> m = Vector<Complex32>.OuterProduct(vector1, vector2); |
|||
for (var i = 0; i < vector1.Count; i++) |
|||
{ |
|||
for (var j = 0; j < vector2.Count; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(m[i, j], vector1[i] * vector2[j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void OuterProductWithFirstParameterNullShouldThrowException() |
|||
{ |
|||
Vector<Complex32> vector1 = null; |
|||
var vector2 = CreateVector(Data); |
|||
Vector<Complex32>.OuterProduct(vector1, vector2); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void OutercProductWithSecondParameterNullShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
Vector<Complex32> vector2 = null; |
|||
Vector<Complex32>.OuterProduct(vector1, vector2); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCalculateTensorMultiply() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = CreateVector(Data); |
|||
var m = vector1.TensorMultiply(vector2); |
|||
for (var i = 0; i < vector1.Count; i++) |
|||
{ |
|||
for (var j = 0; j < vector2.Count; j++) |
|||
{ |
|||
AssertHelpers.AreEqual(m[i, j], vector1[i] * vector2[j]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void TensorMultiplyWithNullParameterNullShouldThrowException() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
Vector<Complex32> vector2 = null; |
|||
vector1.TensorMultiply(vector2); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,91 @@ |
|||
// <copyright file="VectorTests.Norm.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-2010 Math.NET
|
|||
//
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
//
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
//
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using Numerics; |
|||
using MbUnit.Framework; |
|||
|
|||
public abstract partial class VectorTests |
|||
{ |
|||
[Test] |
|||
public void CanComputeNorm() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
AssertHelpers.AlmostEqual(7.7459666f, (float)vector.Norm(2), 7); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanComputeNorm1() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
AssertHelpers.AlmostEqual(16.0346843f, (float)vector.Norm(1), 7); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanComputeSquareNorm() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
AssertHelpers.AlmostEqual(60f, (float)vector.Norm(2) * (float)vector.Norm(2), 7); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(1, 16.0346843)] |
|||
[Row(2, 7.7459666)] |
|||
[Row(3, 6.2852839)] |
|||
[Row(10, 5.1608912)] |
|||
public void CanComputeNormP(int p, float expected) |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
AssertHelpers.AlmostEqual(expected, (float)vector.Norm(p), 7); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanComputeNormInfinity() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
AssertHelpers.AlmostEqual(5.0990195, (float)vector.Norm(Double.PositiveInfinity), 7); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanNormalizeVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var result = vector.Normalize(2); |
|||
AssertHelpers.AlmostEqual(new Complex32(0.12909944f, 0.12909944f), result[0], 7); |
|||
AssertHelpers.AlmostEqual(new Complex32(0.25819888f, 0.12909944f), result[1], 7); |
|||
AssertHelpers.AlmostEqual(new Complex32(0.38729833f, 0.12909944f), result[2], 7); |
|||
AssertHelpers.AlmostEqual(new Complex32(0.51639777f, 0.12909944f), result[3], 7); |
|||
AssertHelpers.AlmostEqual(new Complex32(0.64549722f, 0.12909944f), result[4], 7); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,397 @@ |
|||
// <copyright file="VectorTests.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-2010 Math.NET
|
|||
// Permission is hereby granted, free of charge, to any person
|
|||
// obtaining a copy of this software and associated documentation
|
|||
// files (the "Software"), to deal in the Software without
|
|||
// restriction, including without limitation the rights to use,
|
|||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
// copies of the Software, and to permit persons to whom the
|
|||
// Software is furnished to do so, subject to the following
|
|||
// conditions:
|
|||
// The above copyright notice and this permission notice shall be
|
|||
// included in all copies or substantial portions of the Software.
|
|||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|||
// OTHER DEALINGS IN THE SOFTWARE.
|
|||
// </copyright>
|
|||
|
|||
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 |
|||
{ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Globalization; |
|||
using System.Linq; |
|||
using Numerics; |
|||
using Distributions; |
|||
using LinearAlgebra.Generic; |
|||
using MbUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public abstract partial class VectorTests |
|||
{ |
|||
protected readonly Complex32[] Data = { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1) }; |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCloneVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var clone = vector.Clone(); |
|||
|
|||
Assert.AreNotSame(vector, clone); |
|||
Assert.AreEqual(vector.Count, clone.Count); |
|||
for (var index = 0; index < Data.Length; index++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[index], clone[index]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCloneVectorUsingICloneable() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var clone = (Vector<Complex32>)((ICloneable)vector).Clone(); |
|||
|
|||
Assert.AreNotSame(vector, clone); |
|||
Assert.AreEqual(vector.Count, clone.Count); |
|||
for (var index = 0; index < Data.Length; index++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[index], clone[index]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanConvertVectorToString() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var str = vector.ToString(); |
|||
var sep = CultureInfo.CurrentCulture.TextInfo.ListSeparator; |
|||
Assert.AreEqual(string.Format("1 + 1i{0}2 + 1i{0}3 + 1i{0}4 + 1i{0}5 + 1i", sep), str); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCopyPartialVectorToAnother() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = CreateVector(Data.Length); |
|||
|
|||
vector.CopyTo(other, 2, 2, 2); |
|||
|
|||
AssertHelpers.AreEqual(Complex32.Zero, other[0]); |
|||
AssertHelpers.AreEqual(Complex32.Zero, other[1]); |
|||
AssertHelpers.AreEqual(new Complex32(3, 1), other[2]); |
|||
AssertHelpers.AreEqual(new Complex32(4, 1), other[3]); |
|||
AssertHelpers.AreEqual(Complex32.Zero, other[4]); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCopyPartialVectorToSelf() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
vector.CopyTo(vector, 0, 2, 2); |
|||
|
|||
AssertHelpers.AreEqual(new Complex32(1, 1), vector[0]); |
|||
AssertHelpers.AreEqual(new Complex32(2, 1), vector[1]); |
|||
AssertHelpers.AreEqual(new Complex32(1, 1), vector[2]); |
|||
AssertHelpers.AreEqual(new Complex32(2, 1), vector[3]); |
|||
AssertHelpers.AreEqual(new Complex32(5, 1), vector[4]); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanCopyVectorToAnother() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var other = CreateVector(Data.Length); |
|||
|
|||
vector.CopyTo(other); |
|||
|
|||
for (var index = 0; index < Data.Length; index++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[index], other[index]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Ignore] |
|||
public void CanCreateMatrix() |
|||
{ |
|||
} |
|||
|
|||
[Test] |
|||
public void CanCreateVector() |
|||
{ |
|||
var expected = CreateVector(5); |
|||
var actual = expected.CreateVector(5); |
|||
Assert.AreEqual(expected.GetType(), actual.GetType(), "vectors are same type."); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanEnumerateOverVector() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
Assert.AreElementsEqual(Data, vector); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanEnumerateOverVectorUsingIEnumerable() |
|||
{ |
|||
var enumerable = (IEnumerable)CreateVector(Data); |
|||
var index = 0; |
|||
foreach (var element in enumerable) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[index++], (Complex32)element); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanEquateVectors() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = CreateVector(Data); |
|||
var vector3 = CreateVector(4); |
|||
Assert.IsTrue(vector1.Equals(vector1)); |
|||
Assert.IsTrue(vector1.Equals(vector2)); |
|||
Assert.IsFalse(vector1.Equals(vector3)); |
|||
Assert.IsFalse(vector1.Equals(null)); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void ThrowsArgumentExceptionIfSizeIsNotPositive() |
|||
{ |
|||
Assert.Throws<ArgumentException>(() => CreateVector(-1)); |
|||
Assert.Throws<ArgumentException>(() => CreateVector(0)); |
|||
} |
|||
|
|||
[Test] |
|||
public void TestingForEqualityWithNonVectorReturnsFalse() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
Assert.IsFalse(vector.Equals(2)); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanTestForEqualityUsingObjectEquals() |
|||
{ |
|||
var vector1 = CreateVector(Data); |
|||
var vector2 = CreateVector(Data); |
|||
Assert.IsTrue(vector1.Equals((object)vector2)); |
|||
} |
|||
|
|||
[Test] |
|||
public void VectorGetHashCode() |
|||
{ |
|||
var vector = CreateVector(new [] { new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1) }); |
|||
Assert.AreEqual(-1051736064, vector.GetHashCode()); |
|||
} |
|||
|
|||
[Test] |
|||
public void GetIndexedEnumerator() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
foreach (var pair in vector.GetIndexedEnumerator()) |
|||
{ |
|||
AssertHelpers.AreEqual(Data[pair.Key], pair.Value); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanConvertVectorToArray() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var array = vector.ToArray(); |
|||
Assert.AreElementsEqual(vector, array); |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanConvertVectorToColumnMatrix() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var matrix = vector.ToColumnMatrix(); |
|||
|
|||
Assert.AreEqual(vector.Count, matrix.RowCount); |
|||
Assert.AreEqual(1, matrix.ColumnCount); |
|||
|
|||
for (var i = 0; i < vector.Count; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], matrix[i, 0]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[MultipleAsserts] |
|||
public void CanConvertVectorToRowMatrix() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var matrix = vector.ToRowMatrix(); |
|||
|
|||
Assert.AreEqual(vector.Count, matrix.ColumnCount); |
|||
Assert.AreEqual(1, matrix.RowCount); |
|||
|
|||
for (var i = 0; i < vector.Count; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], matrix[0, i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanSetValues() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
vector.SetValues(Data); |
|||
for (var i = 0; i < Data.Length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i], Data[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[Row(0, 5)] |
|||
[Row(2, 2)] |
|||
[Row(1, 4)] |
|||
[Row(6, 10, ExpectedException = typeof(ArgumentOutOfRangeException))] |
|||
[Row(1, 10, ExpectedException = typeof(ArgumentOutOfRangeException))] |
|||
[Row(1, -10, ExpectedException = typeof(ArgumentOutOfRangeException))] |
|||
public void CanCalculateSubVector(int index, int length) |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var sub = vector.SubVector(index, length); |
|||
Assert.AreEqual(length, sub.Count); |
|||
for (var i = 0; i < length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i + index], sub[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanFindAbsoluteMinimumIndex() |
|||
{ |
|||
var source = CreateVector(Data); |
|||
const int Expected = 0; |
|||
var actual = source.AbsoluteMinimumIndex(); |
|||
Assert.AreEqual(Expected, actual); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanFindAbsoluteMinimum() |
|||
{ |
|||
var source = CreateVector(Data); |
|||
var expected = new Complex32(1, 1).Magnitude; |
|||
var actual = source.AbsoluteMinimum(); |
|||
AssertHelpers.AreEqual(expected, actual); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanFindAbsoluteMaximumIndex() |
|||
{ |
|||
var source = CreateVector(Data); |
|||
const int Expected = 4; |
|||
var actual = source.AbsoluteMaximumIndex(); |
|||
Assert.AreEqual(Expected, actual); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanFindAbsoluteMaximum() |
|||
{ |
|||
var source = CreateVector(Data); |
|||
var expected = new Complex32(5, 1).Magnitude; |
|||
var actual = source.AbsoluteMaximum(); |
|||
AssertHelpers.AreEqual(expected, actual); |
|||
} |
|||
|
|||
[Test] |
|||
[Row(0, 5)] |
|||
[Row(2, 2)] |
|||
[Row(1, 4)] |
|||
[Row(6, 10, ExpectedException = typeof(ArgumentOutOfRangeException))] |
|||
[Row(1, 10, ExpectedException = typeof(ArgumentOutOfRangeException))] |
|||
[Row(1, -10, ExpectedException = typeof(ArgumentOutOfRangeException))] |
|||
public void CanGetSubVector(int index, int length) |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
var sub = vector.SubVector(index, length); |
|||
Assert.AreEqual(length, sub.Count); |
|||
for (var i = 0; i < length; i++) |
|||
{ |
|||
AssertHelpers.AreEqual(vector[i + index], sub[i]); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void CanSum() |
|||
{ |
|||
Complex32[] testData = { new Complex32(-20, -1), new Complex32(-10, -1), new Complex32(10, 1), new Complex32(20, 1), new Complex32(30,1) }; |
|||
var vector = CreateVector(testData); |
|||
var actual = vector.Sum(); |
|||
var expected = new Complex32(30, 1); |
|||
AssertHelpers.AreEqual(expected, actual); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanSumMagnitudes() |
|||
{ |
|||
Complex32[] testData = { new Complex32(-20, -1), new Complex32(-10, -1), new Complex32(10, 1), new Complex32(20, 1), new Complex32(30, 1) }; |
|||
var vector = CreateVector(testData); |
|||
var actual = vector.SumMagnitudes(); |
|||
var expected = testData.Sum(complex => complex.Magnitude); |
|||
Assert.AreEqual(expected, actual); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentNullException] |
|||
public void CanSetValuesWithNullParameterShouldThrowException() |
|||
{ |
|||
var vector = CreateVector(Data); |
|||
vector.SetValues(null); |
|||
} |
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void CanSetValuesWithNonEqualDataLengthShouldThrowException() |
|||
{ |
|||
var vector = CreateVector(Data.Length + 2); |
|||
vector.SetValues(Data); |
|||
} |
|||
|
|||
|
|||
[Test] |
|||
[ExpectedArgumentException] |
|||
public void RandomWithNumberOfElementsLessThanZeroShouldThrowException() |
|||
{ |
|||
var vector = CreateVector(4); |
|||
vector.Random(-2, new ContinuousUniform()); |
|||
} |
|||
|
|||
[Test] |
|||
public void CanClearVector() |
|||
{ |
|||
Complex32[] testData = { new Complex32(-20, -1), new Complex32(-10, -1), new Complex32(10, 1), new Complex32(20, 1), new Complex32(30, 1) }; |
|||
var vector = CreateVector(testData); |
|||
vector.Clear(); |
|||
foreach (var element in vector) |
|||
{ |
|||
AssertHelpers.AreEqual(Complex32.Zero, element); |
|||
} |
|||
} |
|||
|
|||
protected abstract Vector<Complex32> CreateVector(int size); |
|||
protected abstract Vector<Complex32> CreateVector(IList<Complex32> data); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue