Browse Source

clean up: fixed bugs, made matrix arthimetic immutable, added intermediate, type specific abstract Matrix class. Need to finish cleaning up factorization classes and some tests still faile

la-knuth
Marcus Cuda 16 years ago
parent
commit
03fb79967d
  1. 4
      src/MathNet.Numerics.5.1.ReSharper
  2. 14
      src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs
  3. 149
      src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs
  4. 528
      src/Numerics/LinearAlgebra/Complex/DenseMatrix.cs
  5. 388
      src/Numerics/LinearAlgebra/Complex/DiagonalMatrix.cs
  6. 413
      src/Numerics/LinearAlgebra/Complex/Matrix.cs
  7. 709
      src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs
  8. 6
      src/Numerics/LinearAlgebra/Complex/Vector.cs
  9. 538
      src/Numerics/LinearAlgebra/Complex32/DenseMatrix.cs
  10. 431
      src/Numerics/LinearAlgebra/Complex32/DiagonalMatrix.cs
  11. 413
      src/Numerics/LinearAlgebra/Complex32/Matrix.cs
  12. 725
      src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs
  13. 6
      src/Numerics/LinearAlgebra/Complex32/Vector.cs
  14. 282
      src/Numerics/LinearAlgebra/Double/DenseMatrix.cs
  15. 384
      src/Numerics/LinearAlgebra/Double/DiagonalMatrix.cs
  16. 403
      src/Numerics/LinearAlgebra/Double/Matrix.cs
  17. 689
      src/Numerics/LinearAlgebra/Double/SparseMatrix.cs
  18. 6
      src/Numerics/LinearAlgebra/Double/Vector.cs
  19. 159
      src/Numerics/LinearAlgebra/Generic/Matrix.Arithmetic.cs
  20. 509
      src/Numerics/LinearAlgebra/Single/DenseMatrix.cs
  21. 408
      src/Numerics/LinearAlgebra/Single/DiagonalMatrix.cs
  22. 403
      src/Numerics/LinearAlgebra/Single/Matrix.cs
  23. 701
      src/Numerics/LinearAlgebra/Single/SparseMatrix.cs
  24. 6
      src/Numerics/LinearAlgebra/Single/Vector.cs
  25. 51
      src/Numerics/Numerics.csproj
  26. 12
      src/Silverlight/Silverlight.csproj
  27. 53
      src/UnitTests/LinearAlgebraTests/Complex/MatrixTests.Arithmetic.cs
  28. 110
      src/UnitTests/LinearAlgebraTests/Complex/UserDefinedMatrixTests.cs
  29. 8
      src/UnitTests/LinearAlgebraTests/Complex/VectorTests.Arithmetic.cs
  30. 10
      src/UnitTests/LinearAlgebraTests/Complex32/IO/MatlabReaderTests.cs
  31. 24
      src/UnitTests/LinearAlgebraTests/Complex32/MatrixTests.cs
  32. 112
      src/UnitTests/LinearAlgebraTests/Complex32/UserDefinedMatrixTests.cs
  33. 97
      src/UnitTests/LinearAlgebraTests/Double/UserDefinedMatrixTests.cs
  34. 97
      src/UnitTests/LinearAlgebraTests/Single/UserDefinedMatrixTests.cs

4
src/MathNet.Numerics.5.1.ReSharper

@ -23,7 +23,9 @@ indices
&lt &lt
&gt &gt
Frobenius Frobenius
Pointwise</UserWords> Pointwise
multipcation
kronecker</UserWords>
</CustomDictionary> </CustomDictionary>
</Dictionaries> </Dictionaries>
</CustomDictionaries> </CustomDictionaries>

14
src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs

@ -145,7 +145,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <summary> /// <summary>
/// Does a point wise multiplication of two arrays <c>z = x * y</c>. This can be used /// Does a point wise multiplication of two arrays <c>z = x * y</c>. This can be used
/// to multiple elements of vectors or matrices. /// to multiply elements of vectors or matrices.
/// </summary> /// </summary>
/// <param name="x">The array x.</param> /// <param name="x">The array x.</param>
/// <param name="y">The array y.</param> /// <param name="y">The array y.</param>
@ -155,6 +155,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// routine.</remarks> /// routine.</remarks>
void PointWiseMultiplyArrays(T[] x, T[] y, T[] result); void PointWiseMultiplyArrays(T[] x, T[] y, T[] result);
/// <summary>
/// Does a point wise division of two arrays <c>z = x / y</c>. This can be used
/// to divide elements of vectors or matrices.
/// </summary>
/// <param name="x">The array x.</param>
/// <param name="y">The array y.</param>
/// <param name="result">The result of the point wise division.</param>
/// <remarks>There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.</remarks>
void PointWiseDivideArrays(T[] x, T[] y, T[] result);
/// <summary> /// <summary>
/// Computes the requested <see cref="Norm"/> of the matrix. /// Computes the requested <see cref="Norm"/> of the matrix.
/// </summary> /// </summary>

149
src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs

@ -229,6 +229,42 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
CommonParallel.For(0, y.Length, index => { result[index] = x[index] * y[index]; }); CommonParallel.For(0, y.Length, index => { result[index] = x[index] * y[index]; });
} }
/// <summary>
/// Does a point wise division of two arrays <c>z = x / y</c>. This can be used
/// to divide elements of vectors or matrices.
/// </summary>
/// <param name="x">The array x.</param>
/// <param name="y">The array y.</param>
/// <param name="result">The result of the point wise division.</param>
/// <remarks>There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.</remarks>
public void PointWiseDivideArrays(double[] x, double[] y, double[] result)
{
if (y == null)
{
throw new ArgumentNullException("y");
}
if (x == null)
{
throw new ArgumentNullException("x");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (y.Length != x.Length || y.Length != result.Length)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
}
CommonParallel.For(0, y.Length, index => { result[index] = x[index] / y[index]; });
}
/// <summary> /// <summary>
/// Computes the requested <see cref="Norm"/> of the matrix. /// Computes the requested <see cref="Norm"/> of the matrix.
/// </summary> /// </summary>
@ -2982,6 +3018,41 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]); CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]);
} }
/// <summary>
/// Does a point wise division of two arrays <c>z = x / y</c>. This can be used
/// to divide elements of vectors or matrices.
/// </summary>
/// <param name="x">The array x.</param>
/// <param name="y">The array y.</param>
/// <param name="result">The result of the point wise division.</param>
/// <remarks>There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.</remarks>
public void PointWiseDivideArrays(float[] x, float[] y, float[] result)
{
if (y == null)
{
throw new ArgumentNullException("y");
}
if (x == null)
{
throw new ArgumentNullException("x");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (y.Length != x.Length || y.Length != result.Length)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
}
CommonParallel.For(0, y.Length, index => { result[index] = x[index] / y[index]; });
}
/// <summary> /// <summary>
/// Computes the requested <see cref="Norm"/> of the matrix. /// Computes the requested <see cref="Norm"/> of the matrix.
/// </summary> /// </summary>
@ -5581,7 +5652,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentNullException("x"); throw new ArgumentNullException("x");
} }
if (alpha == 1.0) if (alpha.IsOne())
{ {
return; return;
} }
@ -5721,6 +5792,41 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]); CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]);
} }
/// <summary>
/// Does a point wise division of two arrays <c>z = x / y</c>. This can be used
/// to divide elements of vectors or matrices.
/// </summary>
/// <param name="x">The array x.</param>
/// <param name="y">The array y.</param>
/// <param name="result">The result of the point wise division.</param>
/// <remarks>There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.</remarks>
public void PointWiseDivideArrays(Complex[] x, Complex[] y, Complex[] result)
{
if (y == null)
{
throw new ArgumentNullException("y");
}
if (x == null)
{
throw new ArgumentNullException("x");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (y.Length != x.Length || y.Length != result.Length)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
}
CommonParallel.For(0, y.Length, index => { result[index] = x[index] / y[index]; });
}
/// <summary> /// <summary>
/// Computes the requested <see cref="Norm"/> of the matrix. /// Computes the requested <see cref="Norm"/> of the matrix.
/// </summary> /// </summary>
@ -5921,7 +6027,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
rowsC = rowsA; rowsC = rowsA;
} }
if (alpha == 0.0 && beta == 0.0) if (alpha.IsZero() && beta.IsZero())
{ {
Array.Clear(c, 0, c.Length); Array.Clear(c, 0, c.Length);
return; return;
@ -5950,9 +6056,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
bdata = b; bdata = b;
} }
if (alpha == 1.0) if (alpha.IsOne())
{ {
if (beta == 0.0) if (beta.IsZero())
{ {
if ((int)transposeA > 111 && (int)transposeB > 111) if ((int)transposeA > 111 && (int)transposeB > 111)
{ {
@ -8422,6 +8528,41 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]); CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]);
} }
/// <summary>
/// Does a point wise division of two arrays <c>z = x / y</c>. This can be used
/// to divide elements of vectors or matrices.
/// </summary>
/// <param name="x">The array x.</param>
/// <param name="y">The array y.</param>
/// <param name="result">The result of the point wise division.</param>
/// <remarks>There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.</remarks>
public void PointWiseDivideArrays(Complex32[] x, Complex32[] y, Complex32[] result)
{
if (y == null)
{
throw new ArgumentNullException("y");
}
if (x == null)
{
throw new ArgumentNullException("x");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (y.Length != x.Length || y.Length != result.Length)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
}
CommonParallel.For(0, y.Length, index => { result[index] = x[index] / y[index]; });
}
/// <summary> /// <summary>
/// Computes the requested <see cref="Norm"/> of the matrix. /// Computes the requested <see cref="Norm"/> of the matrix.
/// </summary> /// </summary>

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

@ -28,7 +28,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
using System; using System;
using System.Numerics; using System.Numerics;
using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Threading; using Threading;
@ -36,7 +35,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <summary> /// <summary>
/// A Matrix class with dense storage. The underlying storage is a one dimensional array in column-major order. /// A Matrix class with dense storage. The underlying storage is a one dimensional array in column-major order.
/// </summary> /// </summary>
public class DenseMatrix : Matrix<Complex> public class DenseMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseMatrix"/> class. This matrix is square with a given size. /// Initializes a new instance of the <see cref="DenseMatrix"/> class. This matrix is square with a given size.
@ -219,28 +218,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
return ret; return ret;
} }
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<Complex> 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> /// <summary>Calculates the L1 norm.</summary>
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override double L1Norm() public override Complex L1Norm()
{ {
var norm = 0.0; var norm = 0.0;
for (var j = 0; j < ColumnCount; j++) for (var j = 0; j < ColumnCount; j++)
@ -259,10 +239,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override Complex FrobeniusNorm()
{ {
var transpose = (DenseMatrix)Transpose(); var transpose = (DenseMatrix)Transpose();
var aat = this * transpose; var aat = (DenseMatrix)(this * transpose);
var norm = 0.0; var norm = 0.0;
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
@ -276,7 +256,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override Complex InfinityNorm()
{ {
var norm = 0.0; var norm = 0.0;
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
@ -296,437 +276,303 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
#region Elementary operations #region Elementary operations
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of add</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override void Add(Matrix<Complex> other) protected override void DoAdd(Matrix<Complex> other, Matrix<Complex> result)
{ {
var m = other as DenseMatrix; var denseOther = other as DenseMatrix;
if (m == null) var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
base.Add(other); base.DoAdd(other, result);
} }
else else
{ {
Add(m); Control.LinearAlgebraProvider.AddArrays(Data, denseOther.Data, denseResult.Data);
} }
} }
/// <summary> /// <summary>
/// Adds another <see cref="DenseMatrix"/> to this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DenseMatrix"/> to add to this matrix.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the subtraction.</param>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> protected override void DoSubtract(Matrix<Complex> other, Matrix<Complex> result)
public void Add(DenseMatrix other)
{ {
if (other == null) var denseOther = other as DenseMatrix;
var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
throw new ArgumentNullException("other"); base.DoSubtract(other, result);
} }
else
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); Control.LinearAlgebraProvider.SubtractArrays(Data, denseOther.Data, denseResult.Data);
} }
Control.LinearAlgebraProvider.AddArrays(Data, other.Data, Data);
} }
#endregion
#region Static constructors for special matrices.
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Initializes a square <see cref="DenseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="order">the size of the square matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>A dense identity matrix.</returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// <exception cref="ArgumentException">
public override void Subtract(Matrix<Complex> other) /// If <paramref name="order"/> is less than one.
/// </exception>
public static DenseMatrix Identity(int order)
{ {
var m = other as DenseMatrix; var m = new DenseMatrix(order);
if (m == null) for (var i = 0; i < order; i++)
{
base.Subtract(other);
}
else
{ {
Subtract(m); m.Data[(i * order) + i] = 1.0;
} }
return m;
} }
#endregion
/// <summary> /// <summary>
/// Subtracts another <see cref="DenseMatrix"/> from this matrix. The result will be written into this matrix. /// Returns the conjugate transpose of this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DenseMatrix"/> to subtract.</param> /// <returns>The conjugate transpose of this matrix.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> public override Matrix<Complex> ConjugateTranspose()
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(DenseMatrix other)
{ {
if (other == null) var ret = new DenseMatrix(ColumnCount, RowCount);
{ for (var j = 0; j < ColumnCount; j++)
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); var index = j * RowCount;
for (var i = 0; i < RowCount; i++)
{
ret.Data[(i * ColumnCount) + j] = Data[index + i].Conjugate();
}
} }
Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); return ret;
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a complex. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="complex">The complex to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(Complex complex) /// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(Complex scalar, Matrix<Complex> result)
{ {
Control.LinearAlgebraProvider.ScaleArray(complex, Data); var denseResult = result as DenseMatrix;
if (denseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, denseResult.Data);
}
} }
/// <summary> /// <summary>
/// Multiplies this dense matrix with another dense matrix and places the results into the result dense matrix. /// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(Vector<Complex> rightSide, Vector<Complex> result)
/// <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<Complex> other, Matrix<Complex> result)
{ {
if (other == null) var denseRight = rightSide as DenseVector;
{ var denseResult = result as DenseVector;
throw new ArgumentNullException("other");
}
if (result == null) if (denseRight == null || denseResult == null)
{ {
throw new ArgumentNullException("result"); base.DoMultiply(rightSide, 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 else
{ {
Control.LinearAlgebraProvider.MatrixMultiply( Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Data, Algorithms.LinearAlgebra.Transpose.DontTranspose,
RowCount, Algorithms.LinearAlgebra.Transpose.DontTranspose,
ColumnCount, 1.0,
m.Data, Data,
m.RowCount, RowCount,
m.ColumnCount, ColumnCount,
r.Data); denseRight.Data,
denseRight.Count,
1,
0.0,
denseResult.Data);
} }
} }
/// <summary> /// <summary>
/// Multiplies this matrix with another matrix and returns the result. /// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="leftSide">The vector to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoLeftMultiply(Vector<Complex> leftSide, Vector<Complex> result)
/// <returns>The result of multiplication.</returns>
public override Matrix<Complex> Multiply(Matrix<Complex> other)
{ {
if (other == null) var denseLeft = leftSide as DenseVector;
{ var denseResult = result as DenseVector;
throw new ArgumentNullException("other");
}
if (ColumnCount != other.RowCount) if (denseLeft == null || denseResult == null)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); base.DoLeftMultiply(leftSide, result);
} }
else
var m = other as DenseMatrix;
if (m == null)
{ {
return base.Multiply(other); Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0,
denseLeft.Data,
1,
denseResult.Count,
Data,
RowCount,
ColumnCount,
0.0,
denseResult.Data);
} }
var result = (DenseMatrix)CreateMatrix(RowCount, other.ColumnCount);
Multiply(other, result);
return result;
} }
/// <summary> /// <summary>
/// Multiplies this dense matrix with transpose of another dense matrix and places the results into the result dense matrix. /// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(Matrix<Complex> other, Matrix<Complex> result)
/// <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<Complex> other, Matrix<Complex> result)
{ {
var otherDense = other as DenseMatrix; var denseOther = other as DenseMatrix;
var resultDense = result as DenseMatrix; var denseResult = result as DenseMatrix;
if (otherDense == null || resultDense == null) if (denseOther == null || denseResult == null)
{ {
base.TransposeAndMultiply(other, result); base.DoMultiply(other, result);
return;
} }
else
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.DontTranspose,
1.0,
Data,
RowCount,
ColumnCount,
denseOther.Data,
denseOther.RowCount,
denseOther.ColumnCount,
0.0,
denseResult.Data);
} }
Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose,
1.0,
Data,
RowCount,
ColumnCount,
otherDense.Data,
otherDense.RowCount,
otherDense.ColumnCount,
1.0,
resultDense.Data);
} }
/// <summary> /// <summary>
/// Multiplies this matrix with transpose of another matrix and returns the result. /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoTransposeAndMultiply(Matrix<Complex> other, Matrix<Complex> result)
/// <returns>The result of multiplication.</returns>
public override Matrix<Complex> TransposeAndMultiply(Matrix<Complex> other)
{ {
var otherDense = other as DenseMatrix; var denseOther = other as DenseMatrix;
if (otherDense == null) var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
return base.TransposeAndMultiply(other); base.DoTransposeAndMultiply(other, result);
} }
else
if (ColumnCount != otherDense.ColumnCount)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose,
1.0,
Data,
RowCount,
ColumnCount,
denseOther.Data,
denseOther.RowCount,
denseOther.ColumnCount,
0.0,
denseResult.Data);
} }
var result = (DenseMatrix)CreateMatrix(RowCount, other.RowCount);
TransposeAndMultiply(other, result);
return result;
} }
/// <summary> /// <summary>
/// Multiplies two dense matrices. /// Negate each element of this matrix and place the results into the result matrix.
/// </summary> /// </summary>
/// <param name="leftSide">The left matrix to multiply.</param> /// <param name="result">The result of the negation.</param>
/// <param name="rightSide">The right matrix to multiply.</param> protected override void DoNegate(Matrix<Complex> result)
/// <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) var denseResult = result as DenseMatrix;
{
throw new ArgumentNullException("leftSide");
}
if (rightSide == null) if (denseResult == null)
{ {
throw new ArgumentNullException("rightSide"); base.DoNegate(result);
} }
else
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] = Complex.One; Array.Copy(Data, denseResult.Data, Data.Length);
Control.LinearAlgebraProvider.ScaleArray(-1, denseResult.Data);
} }
return m;
} }
#endregion
/// <summary> /// <summary>
/// Negate each element of this matrix. /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception> /// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <exception cref="ArgumentException">if the result matrix's dimensions are not the same as this matrix.</exception> /// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
public override void Negate() protected override void DoPointwiseMultiply(Matrix<Complex> other, Matrix<Complex> result)
{ {
Multiply(-1); var denseOther = other as DenseMatrix;
} var denseResult = result as DenseMatrix;
/// <summary> if (denseOther == null || denseResult == null)
/// 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<Complex> Random(int numberOfRows, int numberOfColumns, IContinuousDistribution distribution)
{
if (numberOfRows < 1)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows"); base.DoPointwiseMultiply(other, result);
} }
else
if (numberOfColumns < 1)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, denseOther.Data, denseResult.Data);
} }
var matrix = CreateMatrix(numberOfRows, numberOfColumns);
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < matrix.RowCount; i++)
{
matrix[i, j] = new Complex(distribution.Sample(), distribution.Sample());
}
});
return matrix;
} }
/// <summary> /// <summary>
/// Generates matrix with random elements. /// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <param name="numberOfRows">Number of rows.</param> /// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="numberOfColumns">Number of columns.</param> /// <param name="result">The matrix to store the result of the pointwise division.</param>
/// <param name="distribution">Continuous Random Distribution or Source</param> protected override void DoPointwiseDivide(Matrix<Complex> other, Matrix<Complex> result)
/// <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<Complex> Random(int numberOfRows, int numberOfColumns, IDiscreteDistribution distribution)
{ {
if (numberOfRows < 1) var denseOther = other as DenseMatrix;
var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows"); base.DoPointwiseDivide(other, result);
} }
else
if (numberOfColumns < 1)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); Control.LinearAlgebraProvider.PointWiseDivideArrays(Data, denseOther.Data, denseResult.Data);
} }
var matrix = CreateMatrix(numberOfRows, numberOfColumns);
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < matrix.RowCount; i++)
{
matrix[i, j] = new Complex(distribution.Sample(), distribution.Sample());
}
});
return matrix;
} }
#region Simple arithmetic of type T
/// <summary> /// <summary>
/// Add two values T+T /// Computes the trace of this matrix.
/// </summary> /// </summary>
/// <param name="val1">Left operand value</param> /// <returns>The trace of this matrix</returns>
/// <param name="val2">Right operand value</param> /// <exception cref="ArgumentException">If the matrix is not square</exception>
/// <returns>Result of addition</returns> public override Complex Trace()
protected sealed override Complex AddT(Complex val1, Complex val2)
{ {
return val1 + val2; if (RowCount != ColumnCount)
} {
throw new ArgumentException(Resources.ArgumentMatrixSquare);
/// <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 Complex SubtractT(Complex val1, Complex 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 Complex MultiplyT(Complex val1, Complex 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 Complex DivideT(Complex val1, Complex val2)
{
return val1 / val2;
}
/// <summary> return CommonParallel.Aggregate(0, RowCount, i => Data[(i * RowCount) + i]);
/// Take absolute value
/// </summary>
/// <param name="val1">Source alue</param>
/// <returns>True if one; otherwise false</returns>
protected sealed override double AbsoluteT(Complex val1)
{
return val1.Magnitude;
} }
#endregion
} }
} }

388
src/Numerics/LinearAlgebra/Complex/DiagonalMatrix.cs

@ -29,7 +29,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
using System; using System;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Threading; using Threading;
@ -43,7 +42,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// entries are set. The exception to this is when the off diagonal elements are /// entries are set. The exception to this is when the off diagonal elements are
/// 0.0 or NaN; these settings will cause no change to the diagonal matrix. /// 0.0 or NaN; these settings will cause no change to the diagonal matrix.
/// </remarks> /// </remarks>
public class DiagonalMatrix : Matrix<Complex> public class DiagonalMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DiagonalMatrix"/> class. This matrix is square with a given size. /// Initializes a new instance of the <see cref="DiagonalMatrix"/> class. This matrix is square with a given size.
@ -279,92 +278,155 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
#region Elementary operations #region Elementary operations
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>The result of the addition.</returns>
/// <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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
/// <exception cref="ArgumentException">If <paramref name="other"/> is not <see cref="DiagonalMatrix"/>.</exception> public override Matrix<Complex> Add(Matrix<Complex> other)
public override void Add(Matrix<Complex> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
var m = other as DiagonalMatrix; if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
if (m == null) {
throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
Matrix<Complex> result;
if (other is DiagonalMatrix)
{
result = new DenseMatrix(RowCount, ColumnCount);
}
else
{ {
throw new ArgumentException(Resources.ArgumentTypeMismatch); result = new DiagonalMatrix(RowCount, ColumnCount);
} }
Add(m); Add(other, result);
return result;
} }
/// <summary> /// <summary>
/// Adds another <see cref="DiagonalMatrix"/> to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DiagonalMatrix"/> to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the addition.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Add(DiagonalMatrix other) public override void Add(Matrix<Complex> other, Matrix<Complex> result)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
if (result == null)
{
throw new ArgumentNullException("result");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException("result", Resources.ArgumentMatrixDimensions);
} }
Control.LinearAlgebraProvider.AddArrays(Data, other.Data, Data); var diagOther = other as DiagonalMatrix;
var diagResult = result as DiagonalMatrix;
if (diagOther == null || diagResult == null)
{
base.Add(other, result);
}
else
{
Control.LinearAlgebraProvider.AddArrays(Data, diagOther.Data, diagResult.Data);
}
} }
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>The result of the subtraction.</returns>
/// <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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
/// <exception cref="ArgumentException">If <paramref name="other"/> is not <see cref="DiagonalMatrix"/>.</exception> public override Matrix<Complex> Subtract(Matrix<Complex> other)
public override void Subtract(Matrix<Complex> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
var m = other as DiagonalMatrix; if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
if (m == null) {
throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
Matrix<Complex> result;
if (other is DiagonalMatrix)
{ {
throw new ArgumentException(Resources.ArgumentTypeMismatch); result = new DenseMatrix(RowCount, ColumnCount);
}
else
{
result = new DiagonalMatrix(RowCount, ColumnCount);
} }
Subtract(m); Subtract(other, result);
return result;
} }
/// <summary> /// <summary>
/// Subtracts another <see cref="DiagonalMatrix"/> from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DiagonalMatrix"/> to subtract.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the subtraction.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(DiagonalMatrix other) public override void Subtract(Matrix<Complex> other, Matrix<Complex> result)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
if (result == null)
{
throw new ArgumentNullException("result");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException("result", Resources.ArgumentMatrixDimensions);
} }
Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); var diagOther = other as DiagonalMatrix;
var diagResult = result as DiagonalMatrix;
if (diagOther == null || diagResult == null)
{
base.Subtract(other, result);
}
else
{
Control.LinearAlgebraProvider.SubtractArrays(Data, diagOther.Data, diagResult.Data);
}
} }
/// <summary> /// <summary>
@ -388,8 +450,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
throw new ArgumentException(Resources.ArgumentArraysSameLength, "source"); throw new ArgumentException(Resources.ArgumentArraysSameLength, "source");
} }
CommonParallel.For(0, source.Length, index => Data[index] = source[index]); Array.Copy(source, Data, source.Length);
} }
/// <summary> /// <summary>
@ -416,27 +478,45 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source");
} }
CommonParallel.For(0, denseSource.Data.Length, index => Data[index] = denseSource.Data[index]); Array.Copy(denseSource.Data, Data, denseSource.Data.Length);
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a scalar. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="scalar">The scalar to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(Complex scalar) /// <param name="result">The matrix to store the result of the multiplication.</param>
/// <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 Multiply(Complex scalar, Matrix<Complex> result)
{ {
if (result == null)
{
throw new ArgumentNullException("result");
}
if (scalar == 0.0) if (scalar == 0.0)
{ {
Clear(); result.Clear();
return; return;
} }
if (scalar == 1.0) if (scalar == 1.0)
{ {
CopyTo(result);
return; return;
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, Data); var diagResult = result as DiagonalMatrix;
if (diagResult == null)
{
base.Multiply(scalar, result);
}
else
{
CopyTo(diagResult);
Control.LinearAlgebraProvider.ScaleArray(scalar, diagResult.Data);
}
} }
/// <summary> /// <summary>
@ -481,9 +561,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
var thisDataCopy = new Complex[r.Data.Length]; var thisDataCopy = new Complex[r.Data.Length];
var otherDataCopy = new Complex[r.Data.Length]; var otherDataCopy = new Complex[r.Data.Length];
Array.Copy(Data, thisDataCopy, (r.Data.Length > Data.Length) ? Data.Length : r.Data.Length);
CommonParallel.For(0, (r.Data.Length > Data.Length) ? Data.Length : r.Data.Length, index => thisDataCopy[index] = Data[index]); Array.Copy(m.Data, otherDataCopy, (r.Data.Length > m.Data.Length) ? m.Data.Length : r.Data.Length);
CommonParallel.For(0, (r.Data.Length > m.Data.Length) ? m.Data.Length : r.Data.Length, index => otherDataCopy[index] = m.Data[index]);
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(thisDataCopy, otherDataCopy, r.Data); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(thisDataCopy, otherDataCopy, r.Data);
} }
@ -694,34 +773,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
return result; return result;
} }
/// <summary>
/// Multiplies two diagonal 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 DiagonalMatrix operator *(DiagonalMatrix leftSide, DiagonalMatrix 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 (DiagonalMatrix)leftSide.Multiply(rightSide);
}
#endregion #endregion
/// <summary> /// <summary>
@ -756,7 +807,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "target"); throw new ArgumentException(Resources.ArgumentMatrixDimensions, "target");
} }
CommonParallel.For(0, Data.Length, index => diagonalTarget.Data[index] = Data[index]); Array.Copy(Data, diagonalTarget.Data, Data.Length);
} }
/// <summary> /// <summary>
@ -766,18 +817,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
public override Matrix<Complex> Transpose() public override Matrix<Complex> Transpose()
{ {
var ret = new DiagonalMatrix(ColumnCount, RowCount); var ret = new DiagonalMatrix(ColumnCount, RowCount);
CommonParallel.For(0, Data.Length, index => ret.Data[index] = Data[index]); Array.Copy(Data, ret.Data, Data.Length);
return ret;
}
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<Complex> ConjugateTranspose()
{
var ret = new DiagonalMatrix(ColumnCount, RowCount);
CommonParallel.For(0, Data.Length, index => ret.Data[index] = Data[index].Conjugate());
return ret; return ret;
} }
@ -895,21 +935,21 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <summary>Calculates the L1 norm.</summary> /// <summary>Calculates the L1 norm.</summary>
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override double L1Norm() public override Complex L1Norm()
{ {
return Data.Aggregate(double.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude)); return Data.Aggregate(double.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude));
} }
/// <summary>Calculates the L2 norm.</summary> /// <summary>Calculates the L2 norm.</summary>
/// <returns>The L2 norm of the matrix.</returns> /// <returns>The L2 norm of the matrix.</returns>
public override double L2Norm() public override Complex L2Norm()
{ {
return Data.Aggregate(double.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude)); return Data.Aggregate(double.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude));
} }
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override Complex FrobeniusNorm()
{ {
var norm = Data.Sum(t => t.Magnitude * t.Magnitude); var norm = Data.Sum(t => t.Magnitude * t.Magnitude);
return Math.Sqrt(norm); return Math.Sqrt(norm);
@ -917,21 +957,21 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override Complex InfinityNorm()
{ {
return L1Norm(); return L1Norm();
} }
/// <summary>Calculates the condition number of this matrix.</summary> /// <summary>Calculates the condition number of this matrix.</summary>
/// <returns>The condition number of the matrix.</returns> /// <returns>The condition number of the matrix.</returns>
public override double ConditionNumber() public override Complex ConditionNumber()
{ {
var maxSv = double.NegativeInfinity; var maxSv = double.NegativeInfinity;
var minSv = double.PositiveInfinity; var minSv = double.PositiveInfinity;
for (var i = 0; i < Data.Length; i++) foreach (var t in Data)
{ {
maxSv = Math.Max(maxSv, Data[i].Magnitude); maxSv = Math.Max(maxSv, t.Magnitude);
minSv = Math.Min(minSv, Data[i].Magnitude); minSv = Math.Min(minSv, t.Magnitude);
} }
return maxSv / minSv; return maxSv / minSv;
@ -1476,50 +1516,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
CommonParallel.For(0, lower.RowCount, i => CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j)))); CommonParallel.For(0, lower.RowCount, i => CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j))));
} }
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise 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 this matrix and <paramref name="other"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public override void PointwiseMultiply(Matrix<Complex> other, Matrix<Complex> result)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
var m = other as DiagonalMatrix;
var r = result as DiagonalMatrix;
if (m == null || r == null)
{
base.PointwiseMultiply(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, m.Data, r.Data);
}
}
/// <summary> /// <summary>
/// Permute the columns of a matrix according to a permutation. /// Permute the columns of a matrix according to a permutation.
/// </summary> /// </summary>
@ -1564,129 +1560,5 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
#endregion #endregion
/// <summary>
/// Negates each element of this matrix.
/// </summary>
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<Complex> 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);
var mn = Math.Min(numberOfRows, numberOfColumns);
CommonParallel.For(0, mn, i => matrix[i, i] = new Complex(distribution.Sample(), 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<Complex> 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);
var mn = Math.Min(numberOfRows, numberOfColumns);
CommonParallel.For(0, mn, i => matrix[i, i] = new Complex(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 Complex AddT(Complex val1, Complex 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 Complex SubtractT(Complex val1, Complex 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 Complex MultiplyT(Complex val1, Complex 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 Complex DivideT(Complex val1, Complex 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(Complex val1)
{
return val1.Magnitude;
}
#endregion
} }
} }

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

@ -0,0 +1,413 @@
// <copyright file="Matrix.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.Complex
{
using System;
using System.Numerics;
using Distributions;
using Generic;
using Properties;
using Threading;
/// <summary>
/// <c>Complex</c> version of the <see cref="Matrix{T}"/> class.
/// </summary>
public abstract class Matrix : Matrix<Complex>
{
/// <summary>
/// Initializes a new instance of the Matrix class.
/// </summary>
/// <param name="rows">
/// The number of rows.
/// </param>
/// <param name="columns">
/// The number of columns.
/// </param>
protected Matrix(int rows, int columns) : base(rows, columns)
{
}
/// <summary>
/// Initializes a new instance of the Matrix class.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
protected Matrix(int order)
: base(order)
{
}
/// <summary>Calculates the L1 norm.</summary>
/// <returns>The L1 norm of the matrix.</returns>
public override Complex L1Norm()
{
var norm = 0.0;
for (var j = 0; j < ColumnCount; j++)
{
var s = 0.0;
for (var i = 0; i < RowCount; i++)
{
s += At(i, j).Magnitude;
}
norm = Math.Max(norm, s);
}
return norm;
}
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<Complex> 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;
}
/// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns>
public override Complex FrobeniusNorm()
{
var transpose = Transpose();
var aat = this * transpose;
var norm = 0.0;
for (var i = 0; i < RowCount; i++)
{
norm += aat.At(i, 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 Complex InfinityNorm()
{
var norm = 0.0;
for (var i = 0; i < RowCount; i++)
{
var s = 0.0;
for (var j = 0; j < ColumnCount; j++)
{
s += At(i, j).Magnitude;
}
norm = Math.Max(norm, s);
}
return norm;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of the addition.</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>
protected override void DoAdd(Matrix<Complex> other, Matrix<Complex> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) + other.At(i, j));
}
});
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract to this matrix.</param>
/// <param name="result">The matrix to store the result of subtraction.</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>
protected override void DoSubtract(Matrix<Complex> other, Matrix<Complex> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) - other.At(i, j));
}
});
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(Complex scalar, Matrix<Complex> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) * scalar);
}
});
}
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<Complex> rightSide, Vector<Complex> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
var s = new Complex();
for (var j = 0; j != ColumnCount; j++)
{
s += At(i, j) * rightSide[j];
}
result[i] = s;
});
}
/// <summary>
/// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector.
/// </summary>
/// <param name="leftSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoLeftMultiply(Vector<Complex> leftSide, Vector<Complex> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
var s = new Complex();
for (var i = 0; i != leftSide.Count; i++)
{
s += leftSide[i] * At(i, j);
}
result[j] = s;
});
}
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Matrix<Complex> other, Matrix<Complex> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
for (var i = 0; i != other.ColumnCount; i++)
{
var s = new Complex();
for (var l = 0; l < ColumnCount; l++)
{
s += At(j, l) * other.At(l, i);
}
result.At(j, i, s);
}
});
}
/// <summary>
/// Divides each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to divide the matrix with.</param>
/// <param name="result">The matrix to store the result of the division.</param>
protected override void DoDivide(Complex scalar, Matrix<Complex> result)
{
DoMultiply(1.0 / scalar, result);
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoTransposeAndMultiply(Matrix<Complex> other, Matrix<Complex> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
var s = new Complex();
for (var l = 0; l < ColumnCount; l++)
{
s += At(i, l) * other.At(j, l);
}
result.At(i, j, s);
}
});
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
protected override void DoNegate(Matrix<Complex> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j != ColumnCount; j++)
{
result[i, j] = -At(i, j);
}
});
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
protected override void DoPointwiseMultiply(Matrix<Complex> other, Matrix<Complex> result)
{
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
result.At(i, j, At(i, j) * other.At(i, j));
}
});
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
protected override void DoPointwiseDivide(Matrix<Complex> other, Matrix<Complex> result)
{
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
result.At(i, j, At(i, j) / other.At(i, j));
}
});
}
/// <summary>
/// Computes the trace of this matrix.
/// </summary>
/// <returns>The trace of this matrix</returns>
/// <exception cref="ArgumentException">If the matrix is not square</exception>
public override Complex Trace()
{
if (RowCount != ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
return CommonParallel.Aggregate(0, RowCount, i => At(i, i));
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<Complex> matrix, IContinuousDistribution distribution)
{
CommonParallel.For(
0,
matrix.RowCount,
i =>
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
matrix.At(i, j, distribution.Sample());
}
});
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<Complex> matrix, IDiscreteDistribution distribution)
{
CommonParallel.For(
0,
matrix.RowCount,
i =>
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
matrix.At(i, j, distribution.Sample());
}
});
}
}
}

709
src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs

@ -32,7 +32,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
{ {
using System; using System;
using System.Numerics; using System.Numerics;
using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Threading; using Threading;
@ -41,7 +40,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// A Matrix class with sparse storage. The underlying storage scheme is 3-array compressed-sparse-row (CSR) Format. /// A Matrix class with sparse storage. The underlying storage scheme is 3-array compressed-sparse-row (CSR) Format.
/// <a href="http://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR_or_CRS.29">Wikipedia - CSR</a>. /// <a href="http://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR_or_CRS.29">Wikipedia - CSR</a>.
/// </summary> /// </summary>
public class SparseMatrix : Matrix<Complex> public class SparseMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Object for use in "lock" /// Object for use in "lock"
@ -113,7 +112,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <param name="value">The value which we assign to each element of the matrix.</param> /// <param name="value">The value which we assign to each element of the matrix.</param>
public SparseMatrix(int rows, int columns, Complex value) : this(rows, columns) public SparseMatrix(int rows, int columns, Complex value) : this(rows, columns)
{ {
if (value == Complex.Zero) if (value == 0.0)
{ {
return; return;
} }
@ -613,7 +612,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
if (index >= 0) if (index >= 0)
{ {
// Non-zero item found in matrix // Non-zero item found in matrix
if (value == Complex.Zero) if (value == 0.0)
{ {
// Delete existing item // Delete existing item
DeleteItemByIndex(index, row); DeleteItemByIndex(index, row);
@ -627,7 +626,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
else else
{ {
// Item not found. Add new value // Item not found. Add new value
if (value == Complex.Zero) if (value == 0.0)
{ {
return; return;
} }
@ -790,56 +789,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
sparseTarget._columnIndices = new int[NonZerosCount]; sparseTarget._columnIndices = new int[NonZerosCount];
sparseTarget.NonZerosCount = NonZerosCount; sparseTarget.NonZerosCount = NonZerosCount;
if (NonZerosCount != 0) Array.Copy(_nonZeroValues, sparseTarget._nonZeroValues, NonZerosCount);
{ Array.Copy(_columnIndices, sparseTarget._columnIndices, NonZerosCount);
CommonParallel.For(0, NonZerosCount, index => sparseTarget._nonZeroValues[index] = _nonZeroValues[index]); Array.Copy(_rowIndex, sparseTarget._rowIndex, RowCount);
Buffer.BlockCopy(_columnIndices, 0, sparseTarget._columnIndices, 0, NonZerosCount * Constants.SizeOfInt);
Buffer.BlockCopy(_rowIndex, 0, sparseTarget._rowIndex, 0, RowCount * Constants.SizeOfInt);
}
} }
} }
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="obj">
/// An object to compare with this object.
/// </param>
/// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="obj"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object obj)
{
var sparseMatrix = obj as SparseMatrix;
if (sparseMatrix == null)
{
return base.Equals(obj);
}
// Accept if the argument is the same object as this
if (ReferenceEquals(this, sparseMatrix))
{
return true;
}
if (ColumnCount != sparseMatrix.ColumnCount || RowCount != sparseMatrix.RowCount || NonZerosCount != sparseMatrix.NonZerosCount)
{
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < NonZerosCount; index++)
{
if (!_nonZeroValues[index].AlmostEqual(sparseMatrix._nonZeroValues[index]) || _columnIndices[index] != sparseMatrix._columnIndices[index])
{
return false;
}
}
return true;
}
/// <summary> /// <summary>
/// Returns a hash code for this instance. /// Returns a hash code for this instance.
/// </summary> /// </summary>
@ -853,9 +808,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
for (var i = 0; i < hashNum; i++) for (var i = 0; i < hashNum; i++)
{ {
#if SILVERLIGHT #if SILVERLIGHT
hash ^= Precision.DoubleToInt64Bits(_nonZeroValues[i].GetHashCode()); hash ^= Precision.DoubleToInt64Bits(_nonZeroValues[i].Magnitude);
#else #else
hash ^= BitConverter.DoubleToInt64Bits(_nonZeroValues[i].GetHashCode()); hash ^= BitConverter.DoubleToInt64Bits(_nonZeroValues[i].Magnitude);
#endif #endif
} }
@ -897,47 +852,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
return ret; return ret;
} }
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<Complex> ConjugateTranspose()
{
var ret = new SparseMatrix(ColumnCount, RowCount)
{
_columnIndices = new int[NonZerosCount],
_nonZeroValues = new Complex[NonZerosCount]
};
// Do an 'inverse' CopyTo iterate over the rows
for (var i = 0; i < _rowIndex.Length; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
// Get the values for the current row
if (startIndex == endIndex)
{
// Begin and end are equal. There are no values in the row, Move to the next row
continue;
}
for (var j = startIndex; j < endIndex; j++)
{
ret.SetValueAt(_columnIndices[j], i, _nonZeroValues[j].Conjugate());
}
}
return ret;
}
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override Complex FrobeniusNorm()
{ {
var transpose = (SparseMatrix)Transpose(); var transpose = (SparseMatrix)Transpose();
var aat = this * transpose; var aat = (SparseMatrix)(this * transpose);
var norm = 0.0; var norm = 0.0;
@ -969,7 +889,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override Complex InfinityNorm()
{ {
var norm = 0.0; var norm = 0.0;
for (var i = 0; i < _rowIndex.Length; i++) for (var i = 0; i < _rowIndex.Length; i++)
@ -1112,200 +1032,231 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
} }
#region Elementary operations #region Static constructors for special matrices.
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Initializes a square <see cref="SparseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="order">the size of the square matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>Identity <c>SparseMatrix</c></returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// <exception cref="ArgumentException">
public override void Add(Matrix<Complex> other) /// If <paramref name="order"/> is less than one.
/// </exception>
public static SparseMatrix Identity(int order)
{ {
if (ReferenceEquals(this, other)) var m = new SparseMatrix(order)
{ {
Multiply(2); NonZerosCount = order,
return; _nonZeroValues = new Complex[order],
} _columnIndices = new int[order]
};
var m = other as SparseMatrix; for (var i = 0; i < order; i++)
if (m == null)
{
base.Add(other);
}
else
{ {
Add(m); m._nonZeroValues[i] = 1.0;
m._columnIndices[i] = i;
m._rowIndex[i] = i;
} }
return m;
} }
#endregion
/// <summary> /// <summary>
/// Adds another <see cref="SparseMatrix"/> to this matrix. The result will be written into this matrix. /// Indicates whether the current object is equal to another object of the same type.
/// </summary> /// </summary>
/// <param name="other">The <see cref="SparseMatrix"/> to add to this matrix.</param> /// <param name="other">
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// An object to compare with this object.
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// </param>
public void Add(SparseMatrix other) /// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="other"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(Matrix<Complex> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); return false;
} }
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); return false;
} }
for (var i = 0; i < other.RowCount; i++) // Accept if the argument is the same object as this.
if (ReferenceEquals(this, other))
{ {
// Get the begin / end index for the current row return true;
var startIndex = other._rowIndex[i]; }
var endIndex = i < other._rowIndex.Length - 1 ? other._rowIndex[i + 1] : other.NonZerosCount;
for (var j = startIndex; j < endIndex; j++) var sparseMatrix = other as SparseMatrix;
if (sparseMatrix == null)
{
return base.Equals(other);
}
if (NonZerosCount != sparseMatrix.NonZerosCount)
{
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < NonZerosCount; index++)
{
if (!_nonZeroValues[index].AlmostEqual(sparseMatrix._nonZeroValues[index]) || _columnIndices[index] != sparseMatrix._columnIndices[index])
{ {
var index = FindItem(i, other._columnIndices[j]); return false;
if (index >= 0)
{
if (_nonZeroValues[index] + other._nonZeroValues[j] == 0.0)
{
DeleteItemByIndex(index, i);
}
else
{
_nonZeroValues[index] += other._nonZeroValues[j];
}
}
else
{
SetValueAt(i, other._columnIndices[j], other._nonZeroValues[j]);
}
} }
} }
return true;
} }
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the addition.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override void Subtract(Matrix<Complex> other) protected override void DoAdd(Matrix<Complex> other, Matrix<Complex> result)
{ {
// We are substracting Matrix form itself result.Clear();
if (ReferenceEquals(this, other))
{
Clear();
return;
}
var m = other as SparseMatrix; var sparseResult = result as SparseMatrix;
if (m == null) if (sparseResult == null)
{ {
base.Subtract(other); for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{
var resVal = _nonZeroValues[j] + other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
result.At(i, _columnIndices[j], resVal);
}
}
}
} }
else else
{ {
Subtract(m); for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{
var resVal = _nonZeroValues[j] + other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
}
}
} }
} }
/// <summary> /// <summary>
/// Subtracts another <see cref="SparseMatrix"/> from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="SparseMatrix"/> to subtract.</param> /// <param name="other">The matrix to subtract to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of subtraction.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(SparseMatrix other) protected override void DoSubtract(Matrix<Complex> other, Matrix<Complex> result)
{ {
if (other == null) result.Clear();
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
for (var i = 0; i < other.RowCount; i++) var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{ {
// Get the begin / end index for the current row for (var i = 0; i < other.RowCount; i++)
var startIndex = other._rowIndex[i];
var endIndex = i < other._rowIndex.Length - 1 ? other._rowIndex[i + 1] : other.NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
var index = FindItem(i, other._columnIndices[j]); // Get the begin / end index for the current row
if (index >= 0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
if (_nonZeroValues[index] - other._nonZeroValues[j] == 0.0) var resVal = _nonZeroValues[j] - other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{ {
DeleteItemByIndex(index, i); result.At(i, _columnIndices[j], resVal);
}
else
{
_nonZeroValues[index] -= other._nonZeroValues[j];
} }
} }
else }
}
else
{
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
SetValueAt(i, other._columnIndices[j], -other._nonZeroValues[j]); var resVal = _nonZeroValues[j] - other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
} }
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a complex. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="complex">The complex to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(Complex complex) /// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(Complex scalar, Matrix<Complex> result)
{ {
if (Complex.One.AlmostEqual(complex)) if (scalar == 1.0)
{ {
CopyTo(result);
return; return;
} }
if (Complex.Zero.AlmostEqual(complex)) if (scalar == 0.0)
{ {
Clear(); result.Clear();
return; return;
} }
Control.LinearAlgebraProvider.ScaleArray(complex, _nonZeroValues); var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._nonZeroValues);
}
} }
/// <summary> /// <summary>
/// Multiplies this sparse matrix with another sparse matrix and places the results into the result sparse matrix. /// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(Matrix<Complex> other, Matrix<Complex> result)
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If <strong>Columns != other.Rows</strong>.</exception>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the Rows x other.Columns.</exception>
public override void Multiply(Matrix<Complex> other, Matrix<Complex> result)
{ {
var otherSparseMatrix = other as SparseMatrix; var otherSparseMatrix = other as SparseMatrix;
var resultSparseMatrix = result as SparseMatrix; var resultSparseMatrix = result as SparseMatrix;
if (otherSparseMatrix == null || resultSparseMatrix == null) if (otherSparseMatrix == null || resultSparseMatrix == null)
{ {
base.Multiply(other, result); base.DoMultiply(other, result);
return; return;
} }
if (ColumnCount != otherSparseMatrix.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
if (resultSparseMatrix.RowCount != RowCount || resultSparseMatrix.ColumnCount != otherSparseMatrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
resultSparseMatrix.Clear(); resultSparseMatrix.Clear();
var columnVector = new DenseVector(otherSparseMatrix.RowCount); var columnVector = new DenseVector(otherSparseMatrix.RowCount);
for (var row = 0; row < RowCount; row++) for (var row = 0; row < RowCount; row++)
@ -1332,60 +1283,21 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
/// <summary> /// <summary>
/// Multiplies this matrix with another matrix and returns the result. /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>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<Complex> Multiply(Matrix<Complex> other)
{
var matrix = other as SparseMatrix;
if (matrix == null)
{
return base.Multiply(other);
}
if (ColumnCount != matrix.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
var result = (SparseMatrix)CreateMatrix(RowCount, matrix.ColumnCount);
Multiply(matrix, result);
return result;
}
/// <summary>
/// Multiplies this dense matrix with transpose of another dense matrix and places the results into the result dense matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoTransposeAndMultiply(Matrix<Complex> other, Matrix<Complex> result)
/// <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<Complex> other, Matrix<Complex> result)
{ {
var otherSparse = other as SparseMatrix; var otherSparse = other as SparseMatrix;
var resultSparse = result as SparseMatrix; var resultSparse = result as SparseMatrix;
if (otherSparse == null || resultSparse == null) if (otherSparse == null || resultSparse == null)
{ {
base.TransposeAndMultiply(other, result); base.DoTransposeAndMultiply(other, result);
return; return;
} }
if (ColumnCount != otherSparse.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
if ((resultSparse.RowCount != RowCount) || (resultSparse.ColumnCount != otherSparse.RowCount))
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
resultSparse.Clear(); resultSparse.Clear();
for (var j = 0; j < RowCount; j++) for (var j = 0; j < RowCount; j++)
{ {
@ -1422,58 +1334,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
} }
} }
} }
/// <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<Complex> TransposeAndMultiply(Matrix<Complex> other)
{
var otherSparse = other as SparseMatrix;
if (otherSparse == null)
{
return base.TransposeAndMultiply(other);
}
if (ColumnCount != otherSparse.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
var result = (SparseMatrix)CreateMatrix(RowCount, other.RowCount);
TransposeAndMultiply(other, result);
return result;
}
/// <summary> /// <summary>
/// Multiplies two sparse matrices. /// Negate each element of this matrix and place the results into the result matrix.
/// </summary> /// </summary>
/// <param name="leftSide">The left matrix to multiply.</param> /// <param name="result">The result of the negation.</param>
/// <param name="rightSide">The right matrix to multiply.</param> protected override void DoNegate(Matrix<Complex> result)
/// <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 SparseMatrix operator *(SparseMatrix leftSide, SparseMatrix rightSide)
{ {
if (leftSide == null) CopyTo(result);
{ DoMultiply(-1, result);
throw new ArgumentNullException("leftSide");
}
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide.ColumnCount != rightSide.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
return (SparseMatrix)leftSide.Multiply(rightSide);
} }
/// <summary> /// <summary>
@ -1481,221 +1350,95 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// </summary> /// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param> /// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param> /// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoPointwiseMultiply(Matrix<Complex> other, Matrix<Complex> result)
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public override void PointwiseMultiply(Matrix<Complex> other, Matrix<Complex> result)
{ {
if (other == null)
{
throw new ArgumentNullException("other");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
result.Clear(); result.Clear();
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++) var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{
for (var i = 0; i < other.RowCount; i++)
{ {
var resVal = _nonZeroValues[j] * other[i, _columnIndices[j]]; // Get the begin / end index for the current row
if (resVal != 0.0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
result[i, _columnIndices[j]] = resVal; var resVal = _nonZeroValues[j] * other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
result.At(i, _columnIndices[j], resVal);
}
} }
} }
} }
} else
/// <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<Complex> 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 = (SparseMatrix)CreateMatrix(numberOfRows, numberOfColumns);
for (var i = 0; i < matrix.RowCount; i++)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var i = 0; i < other.RowCount; i++)
{ {
var value = new Complex(distribution.Sample(), distribution.Sample()); // Get the begin / end index for the current row
if (value != 0.0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
matrix.SetValueAt(i, j, value); var resVal = _nonZeroValues[j] * other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
} }
return matrix;
} }
/// <summary> /// <summary>
/// Generates matrix with random elements. /// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <param name="numberOfRows">Number of rows.</param> /// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="numberOfColumns">Number of columns.</param> /// <param name="result">The matrix to store the result of the pointwise division.</param>
/// <param name="distribution">Continuous Random Distribution or Source</param> protected override void DoPointwiseDivide(Matrix<Complex> other, Matrix<Complex> result)
/// <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<Complex> Random(int numberOfRows, int numberOfColumns, IDiscreteDistribution distribution)
{ {
if (numberOfRows < 1) result.Clear();
{
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows");
}
if (numberOfColumns < 1)
{
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns");
}
var matrix = (SparseMatrix)CreateMatrix(numberOfRows, numberOfColumns); var sparseResult = result as SparseMatrix;
for (var i = 0; i < matrix.RowCount; i++) if (sparseResult == null)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var i = 0; i < other.RowCount; i++)
{ {
var value = new Complex(distribution.Sample(), distribution.Sample()); // Get the begin / end index for the current row
if (value != 0.0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
matrix.SetValueAt(i, j, value); var resVal = _nonZeroValues[j] / other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
result.At(i, _columnIndices[j], resVal);
}
} }
} }
} }
else
{
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
return matrix; for (var j = startIndex; j < endIndex; j++)
}
#endregion
#region Static constructors for special matrices.
/// <summary>
/// Initializes a square <see cref="SparseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary>
/// <param name="order">the size of the square matrix.</param>
/// <returns>Identity <c>SparseMatrix</c></returns>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public static SparseMatrix Identity(int order)
{
var m = new SparseMatrix(order)
{ {
NonZerosCount = order, var resVal = _nonZeroValues[j] / other.At(i, _columnIndices[j]);
_nonZeroValues = new Complex[order], if (resVal != 0.0)
_columnIndices = new int[order] {
}; sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
for (var i = 0; i < order; i++) }
{ }
m._nonZeroValues[i] = Complex.One;
m._columnIndices[i] = i;
m._rowIndex[i] = i;
} }
return m;
}
#endregion
/// <summary>
/// Negates each element of this matrix.
/// </summary>
public override void Negate()
{
Multiply(-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 Complex AddT(Complex val1, Complex 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 Complex SubtractT(Complex val1, Complex 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 Complex MultiplyT(Complex val1, Complex 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 Complex DivideT(Complex val1, Complex 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(Complex val1)
{
return val1.Magnitude;
}
#endregion
} }
} }

6
src/Numerics/LinearAlgebra/Complex/Vector.cs

@ -66,7 +66,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] + scalar); index => result[index] = this[index] + scalar);
} }
/// <summary> /// <summary>
@ -132,7 +132,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] * scalar); index => result[index] = this[index] * scalar);
} }
/// <summary> /// <summary>
@ -149,7 +149,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] / scalar); index => result[index] = this[index] / scalar);
} }
/// <summary> /// <summary>

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

@ -27,7 +27,6 @@
namespace MathNet.Numerics.LinearAlgebra.Complex32 namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
using System; using System;
using Distributions;
using Generic; using Generic;
using Numerics; using Numerics;
using Properties; using Properties;
@ -36,7 +35,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <summary> /// <summary>
/// A Matrix class with dense storage. The underlying storage is a one dimensional array in column-major order. /// A Matrix class with dense storage. The underlying storage is a one dimensional array in column-major order.
/// </summary> /// </summary>
public class DenseMatrix : Matrix<Complex32> public class DenseMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseMatrix"/> class. This matrix is square with a given size. /// Initializes a new instance of the <see cref="DenseMatrix"/> class. This matrix is square with a given size.
@ -219,33 +218,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
return ret; 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> /// <summary>Calculates the L1 norm.</summary>
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override double L1Norm() public override Complex32 L1Norm()
{ {
var norm = 0.0; var norm = 0.0f;
for (var j = 0; j < ColumnCount; j++) for (var j = 0; j < ColumnCount; j++)
{ {
var s = 0.0; var s = 0.0f;
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
{ {
s += Data[(j * RowCount) + i].Magnitude; s += Data[(j * RowCount) + i].Magnitude;
@ -259,29 +239,29 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override Complex32 FrobeniusNorm()
{ {
var transpose = (DenseMatrix)Transpose(); var transpose = (DenseMatrix)Transpose();
var aat = this * transpose; var aat = (DenseMatrix)(this * transpose);
var norm = 0.0; var norm = 0.0f;
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
{ {
norm += aat.Data[(i * RowCount) + i].Magnitude; norm += aat.Data[(i * RowCount) + i].Magnitude;
} }
norm = Math.Sqrt(norm); norm = Convert.ToSingle(Math.Sqrt(norm));
return norm; return norm;
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override Complex32 InfinityNorm()
{ {
var norm = 0.0; var norm = 0.0f;
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
{ {
var s = 0.0; var s = 0.0f;
for (var j = 0; j < ColumnCount; j++) for (var j = 0; j < ColumnCount; j++)
{ {
s += Data[(j * RowCount) + i].Magnitude; s += Data[(j * RowCount) + i].Magnitude;
@ -296,437 +276,303 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
#region Elementary operations #region Elementary operations
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of add</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override void Add(Matrix<Complex32> other) protected override void DoAdd(Matrix<Complex32> other, Matrix<Complex32> result)
{ {
var m = other as DenseMatrix; var denseOther = other as DenseMatrix;
if (m == null) var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
base.Add(other); base.DoAdd(other, result);
} }
else else
{ {
Add(m); Control.LinearAlgebraProvider.AddArrays(Data, denseOther.Data, denseResult.Data);
} }
} }
/// <summary> /// <summary>
/// Adds another <see cref="DenseMatrix"/> to this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DenseMatrix"/> to add to this matrix.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the subtraction.</param>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> protected override void DoSubtract(Matrix<Complex32> other, Matrix<Complex32> result)
public void Add(DenseMatrix other)
{ {
if (other == null) var denseOther = other as DenseMatrix;
var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
throw new ArgumentNullException("other"); base.DoSubtract(other, result);
} }
else
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); Control.LinearAlgebraProvider.SubtractArrays(Data, denseOther.Data, denseResult.Data);
} }
Control.LinearAlgebraProvider.AddArrays(Data, other.Data, Data);
} }
#endregion
#region Static constructors for special matrices.
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Initializes a square <see cref="DenseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="order">the size of the square matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>A dense identity matrix.</returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// <exception cref="ArgumentException">
public override void Subtract(Matrix<Complex32> other) /// If <paramref name="order"/> is less than one.
/// </exception>
public static DenseMatrix Identity(int order)
{ {
var m = other as DenseMatrix; var m = new DenseMatrix(order);
if (m == null) for (var i = 0; i < order; i++)
{
base.Subtract(other);
}
else
{ {
Subtract(m); m.Data[(i * order) + i] = 1.0f;
} }
return m;
} }
#endregion
/// <summary> /// <summary>
/// Subtracts another <see cref="DenseMatrix"/> from this matrix. The result will be written into this matrix. /// Returns the conjugate transpose of this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DenseMatrix"/> to subtract.</param> /// <returns>The conjugate transpose of this matrix.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> public override Matrix<Complex32> ConjugateTranspose()
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(DenseMatrix other)
{ {
if (other == null) var ret = new DenseMatrix(ColumnCount, RowCount);
{ for (var j = 0; j < ColumnCount; j++)
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); var index = j * RowCount;
for (var i = 0; i < RowCount; i++)
{
ret.Data[(i * ColumnCount) + j] = Data[index + i].Conjugate();
}
} }
Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); return ret;
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a complex. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="complex">The complex to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(Complex32 complex) /// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(Complex32 scalar, Matrix<Complex32> result)
{ {
Control.LinearAlgebraProvider.ScaleArray(complex, Data); var denseResult = result as DenseMatrix;
if (denseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, denseResult.Data);
}
} }
/// <summary> /// <summary>
/// Multiplies this dense matrix with another dense matrix and places the results into the result dense matrix. /// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(Vector<Complex32> rightSide, Vector<Complex32> result)
/// <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) var denseRight = rightSide as DenseVector;
{ var denseResult = result as DenseVector;
throw new ArgumentNullException("other");
}
if (result == null) if (denseRight == null || denseResult == null)
{ {
throw new ArgumentNullException("result"); base.DoMultiply(rightSide, 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 else
{ {
Control.LinearAlgebraProvider.MatrixMultiply( Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Data, Algorithms.LinearAlgebra.Transpose.DontTranspose,
RowCount, Algorithms.LinearAlgebra.Transpose.DontTranspose,
ColumnCount, 1.0f,
m.Data, Data,
m.RowCount, RowCount,
m.ColumnCount, ColumnCount,
r.Data); denseRight.Data,
denseRight.Count,
1,
0.0f,
denseResult.Data);
} }
} }
/// <summary> /// <summary>
/// Multiplies this matrix with another matrix and returns the result. /// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="leftSide">The vector to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoLeftMultiply(Vector<Complex32> leftSide, Vector<Complex32> result)
/// <returns>The result of multiplication.</returns>
public override Matrix<Complex32> Multiply(Matrix<Complex32> other)
{ {
if (other == null) var denseLeft = leftSide as DenseVector;
{ var denseResult = result as DenseVector;
throw new ArgumentNullException("other");
}
if (ColumnCount != other.RowCount) if (denseLeft == null || denseResult == null)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); base.DoLeftMultiply(leftSide, result);
} }
else
var m = other as DenseMatrix;
if (m == null)
{ {
return base.Multiply(other); Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f,
denseLeft.Data,
1,
denseResult.Count,
Data,
RowCount,
ColumnCount,
0.0f,
denseResult.Data);
} }
var result = (DenseMatrix)CreateMatrix(RowCount, other.ColumnCount);
Multiply(other, result);
return result;
} }
/// <summary> /// <summary>
/// Multiplies this dense matrix with transpose of another dense matrix and places the results into the result dense matrix. /// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
/// <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 denseOther = other as DenseMatrix;
var resultDense = result as DenseMatrix; var denseResult = result as DenseMatrix;
if (otherDense == null || resultDense == null)
{
base.TransposeAndMultiply(other, result);
return;
}
if (ColumnCount != otherDense.ColumnCount) if (denseOther == null || denseResult == null)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); base.DoMultiply(other, result);
} }
else
if ((resultDense.RowCount != RowCount) || (resultDense.ColumnCount != otherDense.RowCount))
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f,
Data,
RowCount,
ColumnCount,
denseOther.Data,
denseOther.RowCount,
denseOther.ColumnCount,
0.0f,
denseResult.Data);
} }
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> /// <summary>
/// Multiplies this matrix with transpose of another matrix and returns the result. /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoTransposeAndMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
/// <returns>The result of multiplication.</returns>
public override Matrix<Complex32> TransposeAndMultiply(Matrix<Complex32> other)
{ {
var otherDense = other as DenseMatrix; var denseOther = other as DenseMatrix;
if (otherDense == null) var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
return base.TransposeAndMultiply(other); base.DoTransposeAndMultiply(other, result);
} }
else
if (ColumnCount != otherDense.ColumnCount)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose,
1.0f,
Data,
RowCount,
ColumnCount,
denseOther.Data,
denseOther.RowCount,
denseOther.ColumnCount,
0.0f,
denseResult.Data);
} }
var result = (DenseMatrix)CreateMatrix(RowCount, other.RowCount);
TransposeAndMultiply(other, result);
return result;
} }
/// <summary> /// <summary>
/// Multiplies two dense matrices. /// Negate each element of this matrix and place the results into the result matrix.
/// </summary> /// </summary>
/// <param name="leftSide">The left matrix to multiply.</param> /// <param name="result">The result of the negation.</param>
/// <param name="rightSide">The right matrix to multiply.</param> protected override void DoNegate(Matrix<Complex32> result)
/// <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) var denseResult = result as DenseMatrix;
{
throw new ArgumentNullException("leftSide");
}
if (rightSide == null) if (denseResult == null)
{ {
throw new ArgumentNullException("rightSide"); base.DoNegate(result);
} }
else
if (leftSide.ColumnCount != rightSide.RowCount)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); Array.Copy(Data, denseResult.Data, Data.Length);
Control.LinearAlgebraProvider.ScaleArray(-1, denseResult.Data);
} }
return (DenseMatrix)leftSide.Multiply(rightSide);
} }
#endregion
#region Static constructors for special matrices.
/// <summary> /// <summary>
/// Initializes a square <see cref="DenseMatrix"/> with all zero's except for ones on the diagonal. /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <param name="order">the size of the square matrix.</param> /// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <returns>A dense identity matrix.</returns> /// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
/// <exception cref="ArgumentException"> protected override void DoPointwiseMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
/// If <paramref name="order"/> is less than one.
/// </exception>
public static DenseMatrix Identity(int order)
{ {
var m = new DenseMatrix(order); var denseOther = other as DenseMatrix;
for (var i = 0; i < order; i++) var denseResult = result as DenseMatrix;
{
m[i, i] = Complex32.One;
}
return m;
}
#endregion if (denseOther == null || denseResult == null)
/// <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"); base.DoPointwiseMultiply(other, result);
} }
else
if (numberOfColumns < 1)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, denseOther.Data, denseResult.Data);
} }
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> /// <summary>
/// Generates matrix with random elements. /// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <param name="numberOfRows">Number of rows.</param> /// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="numberOfColumns">Number of columns.</param> /// <param name="result">The matrix to store the result of the pointwise division.</param>
/// <param name="distribution">Continuous Random Distribution or Source</param> protected override void DoPointwiseDivide(Matrix<Complex32> other, Matrix<Complex32> result)
/// <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) var denseOther = other as DenseMatrix;
var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows"); base.DoPointwiseDivide(other, result);
} }
else
if (numberOfColumns < 1)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); Control.LinearAlgebraProvider.PointWiseDivideArrays(Data, denseOther.Data, denseResult.Data);
} }
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> /// <summary>
/// Add two values T+T /// Computes the trace of this matrix.
/// </summary> /// </summary>
/// <param name="val1">Left operand value</param> /// <returns>The trace of this matrix</returns>
/// <param name="val2">Right operand value</param> /// <exception cref="ArgumentException">If the matrix is not square</exception>
/// <returns>Result of addition</returns> public override Complex32 Trace()
protected sealed override Complex32 AddT(Complex32 val1, Complex32 val2)
{ {
return val1 + val2; if (RowCount != ColumnCount)
} {
throw new ArgumentException(Resources.ArgumentMatrixSquare);
/// <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> return CommonParallel.Aggregate(0, RowCount, i => Data[(i * RowCount) + i]);
/// 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
} }
} }

431
src/Numerics/LinearAlgebra/Complex32/DiagonalMatrix.cs

@ -28,7 +28,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
using System; using System;
using System.Linq; using System.Linq;
using Distributions;
using Generic; using Generic;
using Numerics; using Numerics;
using Properties; using Properties;
@ -43,16 +42,17 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// entries are set. The exception to this is when the off diagonal elements are /// entries are set. The exception to this is when the off diagonal elements are
/// 0.0 or NaN; these settings will cause no change to the diagonal matrix. /// 0.0 or NaN; these settings will cause no change to the diagonal matrix.
/// </remarks> /// </remarks>
public class DiagonalMatrix : Matrix<Complex32> public class DiagonalMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DiagonalMatrix"/> class. This matrix is square with a given size. /// Initializes a new instance of the <see cref="DiagonalMatrix"/> class. This matrix is square with a given size.
/// </summary> /// </summary>
/// <param name="order">the size of the square matrix.</param> /// <param name="order">the size of the square matrix.</param>
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one. /// If <paramref name="order"/> is less than one.
/// </exception> /// </exception>
public DiagonalMatrix(int order) : base(order) public DiagonalMatrix(int order)
: base(order)
{ {
Data = new Complex32[order * order]; Data = new Complex32[order * order];
} }
@ -66,7 +66,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <param name="columns"> /// <param name="columns">
/// The number of columns. /// The number of columns.
/// </param> /// </param>
public DiagonalMatrix(int rows, int columns) : base(rows, columns) public DiagonalMatrix(int rows, int columns)
: base(rows, columns)
{ {
Data = new Complex32[Math.Min(rows, columns)]; Data = new Complex32[Math.Min(rows, columns)];
} }
@ -81,7 +82,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// The number of columns. /// The number of columns.
/// </param> /// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param> /// <param name="value">The value which we assign to each element of the matrix.</param>
public DiagonalMatrix(int rows, int columns, Complex32 value) : base(rows, columns) public DiagonalMatrix(int rows, int columns, Complex32 value)
: base(rows, columns)
{ {
Data = new Complex32[Math.Min(rows, columns)]; Data = new Complex32[Math.Min(rows, columns)];
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < Data.Length; i++)
@ -97,7 +99,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <param name="rows">The number of rows.</param> /// <param name="rows">The number of rows.</param>
/// <param name="columns">The number of columns.</param> /// <param name="columns">The number of columns.</param>
/// <param name="diagonalArray">The one dimensional array which contain diagonal elements.</param> /// <param name="diagonalArray">The one dimensional array which contain diagonal elements.</param>
public DiagonalMatrix(int rows, int columns, Complex32[] diagonalArray) : base(rows, columns) public DiagonalMatrix(int rows, int columns, Complex32[] diagonalArray)
: base(rows, columns)
{ {
Data = diagonalArray; Data = diagonalArray;
} }
@ -109,7 +112,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <exception cref="IndexOutOfRangeException">When <paramref name="array"/> contains an off-diagonal element.</exception> /// <exception cref="IndexOutOfRangeException">When <paramref name="array"/> contains an off-diagonal element.</exception>
/// <exception cref="IndexOutOfRangeException">Depending on the implementation, an <see cref="IndexOutOfRangeException"/> /// <exception cref="IndexOutOfRangeException">Depending on the implementation, an <see cref="IndexOutOfRangeException"/>
/// may be thrown if one of the indices is outside the dimensions of the matrix.</exception> /// may be thrown if one of the indices is outside the dimensions of the matrix.</exception>
public DiagonalMatrix(Complex32[,] array) : this(array.GetLength(0), array.GetLength(1)) public DiagonalMatrix(Complex32[,] array)
: this(array.GetLength(0), array.GetLength(1))
{ {
var rows = array.GetLength(0); var rows = array.GetLength(0);
var columns = array.GetLength(1); var columns = array.GetLength(1);
@ -122,7 +126,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
Data[i] = array[i, j]; Data[i] = array[i, j];
} }
else if (((array[i, j].Real != 0.0f) && !float.IsNaN(array[i, j].Real)) || ((array[i, j].Imaginary != 0.0f) && !float.IsNaN(array[i, j].Imaginary))) else if (((array[i, j].Real != 0.0) && !double.IsNaN(array[i, j].Real)) || ((array[i, j].Imaginary != 0.0) && !double.IsNaN(array[i, j].Imaginary)))
{ {
throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix."); throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix.");
} }
@ -156,7 +160,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// may be thrown if one of the indices is outside the dimensions of the matrix.</exception> /// may be thrown if one of the indices is outside the dimensions of the matrix.</exception>
public override Complex32 At(int row, int column) public override Complex32 At(int row, int column)
{ {
return row == column ? Data[row] : Complex32.Zero; return row == column ? Data[row] : 0.0f;
} }
/// <summary> /// <summary>
@ -180,7 +184,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
Data[row] = value; Data[row] = value;
} }
else if (((value.Real != 0.0f) && !float.IsNaN(value.Real)) || ((value.Imaginary != 0.0f) && !float.IsNaN(value.Imaginary))) else if (((value.Real != 0.0) && !double.IsNaN(value.Real)) || ((value.Imaginary != 0.0) && !double.IsNaN(value.Imaginary)))
{ {
throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix."); throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix.");
} }
@ -279,92 +283,155 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
#region Elementary operations #region Elementary operations
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>The result of the addition.</returns>
/// <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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
/// <exception cref="ArgumentException">If <paramref name="other"/> is not <see cref="DiagonalMatrix"/>.</exception> public override Matrix<Complex32> Add(Matrix<Complex32> other)
public override void Add(Matrix<Complex32> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
var m = other as DiagonalMatrix; if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
if (m == null)
{ {
throw new ArgumentException(Resources.ArgumentTypeMismatch); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
} }
Add(m); Matrix<Complex32> result;
if (other is DiagonalMatrix)
{
result = new DenseMatrix(RowCount, ColumnCount);
}
else
{
result = new DiagonalMatrix(RowCount, ColumnCount);
}
Add(other, result);
return result;
} }
/// <summary> /// <summary>
/// Adds another <see cref="DiagonalMatrix"/> to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DiagonalMatrix"/> to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the addition.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Add(DiagonalMatrix other) public override void Add(Matrix<Complex32> other, Matrix<Complex32> result)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
if (result == null)
{
throw new ArgumentNullException("result");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException("result", Resources.ArgumentMatrixDimensions);
} }
Control.LinearAlgebraProvider.AddArrays(Data, other.Data, Data); var diagOther = other as DiagonalMatrix;
var diagResult = result as DiagonalMatrix;
if (diagOther == null || diagResult == null)
{
base.Add(other, result);
}
else
{
Control.LinearAlgebraProvider.AddArrays(Data, diagOther.Data, diagResult.Data);
}
} }
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>The result of the subtraction.</returns>
/// <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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
/// <exception cref="ArgumentException">If <paramref name="other"/> is not <see cref="DiagonalMatrix"/>.</exception> public override Matrix<Complex32> Subtract(Matrix<Complex32> other)
public override void Subtract(Matrix<Complex32> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
var m = other as DiagonalMatrix; if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
if (m == null) {
throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
Matrix<Complex32> result;
if (other is DiagonalMatrix)
{ {
throw new ArgumentException(Resources.ArgumentTypeMismatch); result = new DenseMatrix(RowCount, ColumnCount);
}
else
{
result = new DiagonalMatrix(RowCount, ColumnCount);
} }
Subtract(m); Subtract(other, result);
return result;
} }
/// <summary> /// <summary>
/// Subtracts another <see cref="DiagonalMatrix"/> from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DiagonalMatrix"/> to subtract.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the subtraction.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(DiagonalMatrix other) public override void Subtract(Matrix<Complex32> other, Matrix<Complex32> result)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
if (result == null)
{
throw new ArgumentNullException("result");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
} }
Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException("result", Resources.ArgumentMatrixDimensions);
}
var diagOther = other as DiagonalMatrix;
var diagResult = result as DiagonalMatrix;
if (diagOther == null || diagResult == null)
{
base.Subtract(other, result);
}
else
{
Control.LinearAlgebraProvider.SubtractArrays(Data, diagOther.Data, diagResult.Data);
}
} }
/// <summary> /// <summary>
@ -389,7 +456,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
throw new ArgumentException(Resources.ArgumentArraysSameLength, "source"); throw new ArgumentException(Resources.ArgumentArraysSameLength, "source");
} }
CommonParallel.For(0, source.Length, index => Data[index] = source[index]); Array.Copy(source, Data, source.Length);
} }
/// <summary> /// <summary>
@ -416,27 +483,45 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source"); throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source");
} }
CommonParallel.For(0, denseSource.Data.Length, index => Data[index] = denseSource.Data[index]); Array.Copy(denseSource.Data, Data, denseSource.Data.Length);
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a scalar. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="scalar">The scalar to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(Complex32 scalar) /// <param name="result">The matrix to store the result of the multiplication.</param>
/// <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 Multiply(Complex32 scalar, Matrix<Complex32> result)
{ {
if (scalar == Complex32.Zero) if (result == null)
{ {
Clear(); throw new ArgumentNullException("result");
}
if (scalar.IsZero())
{
result.Clear();
return; return;
} }
if (scalar == Complex32.One) if (scalar.IsOne())
{ {
CopyTo(result);
return; return;
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, Data); var diagResult = result as DiagonalMatrix;
if (diagResult == null)
{
base.Multiply(scalar, result);
}
else
{
CopyTo(diagResult);
Control.LinearAlgebraProvider.ScaleArray(scalar, diagResult.Data);
}
} }
/// <summary> /// <summary>
@ -481,9 +566,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
var thisDataCopy = new Complex32[r.Data.Length]; var thisDataCopy = new Complex32[r.Data.Length];
var otherDataCopy = new Complex32[r.Data.Length]; var otherDataCopy = new Complex32[r.Data.Length];
Array.Copy(Data, thisDataCopy, (r.Data.Length > Data.Length) ? Data.Length : r.Data.Length);
CommonParallel.For(0, (r.Data.Length > Data.Length) ? Data.Length : r.Data.Length, index => thisDataCopy[index] = Data[index]); Array.Copy(m.Data, otherDataCopy, (r.Data.Length > m.Data.Length) ? m.Data.Length : r.Data.Length);
CommonParallel.For(0, (r.Data.Length > m.Data.Length) ? m.Data.Length : r.Data.Length, index => otherDataCopy[index] = m.Data[index]);
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(thisDataCopy, otherDataCopy, r.Data); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(thisDataCopy, otherDataCopy, r.Data);
} }
@ -694,34 +778,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
return result; return result;
} }
/// <summary>
/// Multiplies two diagonal 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 DiagonalMatrix operator *(DiagonalMatrix leftSide, DiagonalMatrix 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 (DiagonalMatrix)leftSide.Multiply(rightSide);
}
#endregion #endregion
/// <summary> /// <summary>
@ -756,7 +812,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "target"); throw new ArgumentException(Resources.ArgumentMatrixDimensions, "target");
} }
CommonParallel.For(0, Data.Length, index => diagonalTarget.Data[index] = Data[index]); Array.Copy(Data, diagonalTarget.Data, Data.Length);
} }
/// <summary> /// <summary>
@ -766,18 +822,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
public override Matrix<Complex32> Transpose() public override Matrix<Complex32> Transpose()
{ {
var ret = new DiagonalMatrix(ColumnCount, RowCount); var ret = new DiagonalMatrix(ColumnCount, RowCount);
CommonParallel.For(0, Data.Length, index => ret.Data[index] = Data[index]); Array.Copy(Data, ret.Data, Data.Length);
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 DiagonalMatrix(ColumnCount, RowCount);
CommonParallel.For(0, Data.Length, index => ret.Data[index] = Data[index].Conjugate());
return ret; return ret;
} }
@ -895,43 +940,43 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <summary>Calculates the L1 norm.</summary> /// <summary>Calculates the L1 norm.</summary>
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override double L1Norm() public override Complex32 L1Norm()
{ {
return Data.Aggregate(double.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude)); return Data.Aggregate(float.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude));
} }
/// <summary>Calculates the L2 norm.</summary> /// <summary>Calculates the L2 norm.</summary>
/// <returns>The L2 norm of the matrix.</returns> /// <returns>The L2 norm of the matrix.</returns>
public override double L2Norm() public override Complex32 L2Norm()
{ {
return Data.Aggregate(double.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude)); return Data.Aggregate(float.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude));
} }
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override Complex32 FrobeniusNorm()
{ {
var norm = Data.Sum(t => t.Magnitude * t.Magnitude); var norm = Data.Sum(t => t.Magnitude * t.Magnitude);
return Math.Sqrt(norm); return Convert.ToSingle(Math.Sqrt(norm));
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override Complex32 InfinityNorm()
{ {
return L1Norm(); return L1Norm();
} }
/// <summary>Calculates the condition number of this matrix.</summary> /// <summary>Calculates the condition number of this matrix.</summary>
/// <returns>The condition number of the matrix.</returns> /// <returns>The condition number of the matrix.</returns>
public override double ConditionNumber() public override Complex32 ConditionNumber()
{ {
var maxSv = double.NegativeInfinity; var maxSv = float.NegativeInfinity;
var minSv = double.PositiveInfinity; var minSv = float.PositiveInfinity;
for (var i = 0; i < Data.Length; i++) foreach (var t in Data)
{ {
maxSv = Math.Max(maxSv, Data[i].Magnitude); maxSv = Math.Max(maxSv, t.Magnitude);
minSv = Math.Min(minSv, Data[i].Magnitude); minSv = Math.Min(minSv, t.Magnitude);
} }
return maxSv / minSv; return maxSv / minSv;
@ -945,15 +990,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
if (RowCount != ColumnCount) if (RowCount != ColumnCount)
{ {
throw new ArgumentException(Resources.ArgumentMatrixSquare); throw new ArgumentException(Resources.ArgumentMatrixSquare);
} }
var inverse = (DiagonalMatrix)Clone(); var inverse = (DiagonalMatrix)Clone();
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < Data.Length; i++)
{ {
if (Data[i] != Complex32.Zero) if (Data[i] != 0.0f)
{ {
inverse.Data[i] = Complex32.One / Data[i]; inverse.Data[i] = 1.0f / Data[i];
} }
else else
{ {
@ -1476,50 +1521,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
CommonParallel.For(0, lower.RowCount, i => CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j)))); CommonParallel.For(0, lower.RowCount, i => CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j))));
} }
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise 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 this matrix and <paramref name="other"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public override void PointwiseMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
var m = other as DiagonalMatrix;
var r = result as DiagonalMatrix;
if (m == null || r == null)
{
base.PointwiseMultiply(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, m.Data, r.Data);
}
}
/// <summary> /// <summary>
/// Permute the columns of a matrix according to a permutation. /// Permute the columns of a matrix according to a permutation.
/// </summary> /// </summary>
@ -1557,136 +1558,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
var m = new DiagonalMatrix(order); var m = new DiagonalMatrix(order);
for (var i = 0; i < order; i++) for (var i = 0; i < order; i++)
{ {
m.Data[i] = Complex32.One; m.Data[i] = 1.0f;
} }
return m; return m;
} }
#endregion #endregion
/// <summary>
/// Negates each element of this matrix.
/// </summary>
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);
var mn = Math.Min(numberOfRows, numberOfColumns);
CommonParallel.For(0, mn, i => matrix[i, i] = 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);
var mn = Math.Min(numberOfRows, numberOfColumns);
CommonParallel.For(0, mn, i => matrix[i, i] = 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
} }
} }

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

@ -0,0 +1,413 @@
// <copyright file="Matrix.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>
/// <c>Complex32</c> version of the <see cref="Matrix{T}"/> class.
/// </summary>
public abstract class Matrix : Matrix<Complex32>
{
/// <summary>
/// Initializes a new instance of the Matrix class.
/// </summary>
/// <param name="rows">
/// The number of rows.
/// </param>
/// <param name="columns">
/// The number of columns.
/// </param>
protected Matrix(int rows, int columns) : base(rows, columns)
{
}
/// <summary>
/// Initializes a new instance of the Matrix class.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
protected Matrix(int order)
: base(order)
{
}
/// <summary>Calculates the L1 norm.</summary>
/// <returns>The L1 norm of the matrix.</returns>
public override Complex32 L1Norm()
{
var norm = 0.0f;
for (var j = 0; j < ColumnCount; j++)
{
var s = 0.0f;
for (var i = 0; i < RowCount; i++)
{
s += At(i, j).Magnitude;
}
norm = Math.Max(norm, s);
}
return norm;
}
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
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;
}
/// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns>
public override Complex32 FrobeniusNorm()
{
var transpose = Transpose();
var aat = this * transpose;
var norm = 0.0f;
for (var i = 0; i < RowCount; i++)
{
norm += aat.At(i, i).Magnitude;
}
norm = Convert.ToSingle(Math.Sqrt(norm));
return norm;
}
/// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns>
public override Complex32 InfinityNorm()
{
var norm = 0.0f;
for (var i = 0; i < RowCount; i++)
{
var s = 0.0f;
for (var j = 0; j < ColumnCount; j++)
{
s += At(i, j).Magnitude;
}
norm = Math.Max(norm, s);
}
return norm;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of the addition.</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>
protected override void DoAdd(Matrix<Complex32> other, Matrix<Complex32> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) + other.At(i, j));
}
});
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract to this matrix.</param>
/// <param name="result">The matrix to store the result of subtraction.</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>
protected override void DoSubtract(Matrix<Complex32> other, Matrix<Complex32> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) - other.At(i, j));
}
});
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(Complex32 scalar, Matrix<Complex32> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) * scalar);
}
});
}
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<Complex32> rightSide, Vector<Complex32> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
var s = new Complex32();
for (var j = 0; j != ColumnCount; j++)
{
s += At(i, j) * rightSide[j];
}
result[i] = s;
});
}
/// <summary>
/// Divides each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to divide the matrix with.</param>
/// <param name="result">The matrix to store the result of the division.</param>
protected override void DoDivide(Complex32 scalar, Matrix<Complex32> result)
{
DoMultiply(1.0f / scalar, result);
}
/// <summary>
/// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector.
/// </summary>
/// <param name="leftSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoLeftMultiply(Vector<Complex32> leftSide, Vector<Complex32> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
var s = new Complex32();
for (var i = 0; i != leftSide.Count; i++)
{
s += leftSide[i] * At(i, j);
}
result[j] = s;
});
}
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
for (var i = 0; i != other.ColumnCount; i++)
{
var s = new Complex32();
for (var l = 0; l < ColumnCount; l++)
{
s += At(j, l) * other.At(l, i);
}
result.At(j, i, s);
}
});
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoTransposeAndMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
var s = new Complex32();
for (var l = 0; l < ColumnCount; l++)
{
s += At(i, l) * other.At(j, l);
}
result.At(i, j, s);
}
});
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
protected override void DoNegate(Matrix<Complex32> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j != ColumnCount; j++)
{
result[i, j] = -At(i, j);
}
});
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
protected override void DoPointwiseMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
result.At(i, j, At(i, j) * other.At(i, j));
}
});
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
protected override void DoPointwiseDivide(Matrix<Complex32> other, Matrix<Complex32> result)
{
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
result.At(i, j, At(i, j) / other.At(i, j));
}
});
}
/// <summary>
/// Computes the trace of this matrix.
/// </summary>
/// <returns>The trace of this matrix</returns>
/// <exception cref="ArgumentException">If the matrix is not square</exception>
public override Complex32 Trace()
{
if (RowCount != ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
return CommonParallel.Aggregate(0, RowCount, i => At(i, i));
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<Complex32> matrix, IContinuousDistribution distribution)
{
CommonParallel.For(
0,
matrix.RowCount,
i =>
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
matrix.At(i, j, Convert.ToSingle(distribution.Sample()));
}
});
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<Complex32> matrix, IDiscreteDistribution distribution)
{
CommonParallel.For(
0,
matrix.RowCount,
i =>
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
matrix.At(i, j, distribution.Sample());
}
});
}
}
}

725
src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs

@ -31,7 +31,6 @@
namespace MathNet.Numerics.LinearAlgebra.Complex32 namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
using System; using System;
using Distributions;
using Generic; using Generic;
using Numerics; using Numerics;
using Properties; using Properties;
@ -41,7 +40,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// A Matrix class with sparse storage. The underlying storage scheme is 3-array compressed-sparse-row (CSR) Format. /// A Matrix class with sparse storage. The underlying storage scheme is 3-array compressed-sparse-row (CSR) Format.
/// <a href="http://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR_or_CRS.29">Wikipedia - CSR</a>. /// <a href="http://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR_or_CRS.29">Wikipedia - CSR</a>.
/// </summary> /// </summary>
public class SparseMatrix : Matrix<Complex32> public class SparseMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Object for use in "lock" /// Object for use in "lock"
@ -113,7 +112,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// <param name="value">The value which we assign to each element of the matrix.</param> /// <param name="value">The value which we assign to each element of the matrix.</param>
public SparseMatrix(int rows, int columns, Complex32 value) : this(rows, columns) public SparseMatrix(int rows, int columns, Complex32 value) : this(rows, columns)
{ {
if (value == Complex32.Zero) if (value == 0.0f)
{ {
return; return;
} }
@ -551,7 +550,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
{ {
var index = FindItem(i, j); var index = FindItem(i, j);
ret[(j * RowCount) + i] = index >= 0 ? _nonZeroValues[index] : Complex32.Zero; ret[(j * RowCount) + i] = index >= 0 ? _nonZeroValues[index] : 0.0f;
} }
} }
@ -575,7 +574,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
lock (_lockObject) lock (_lockObject)
{ {
var index = FindItem(row, column); var index = FindItem(row, column);
return index >= 0 ? _nonZeroValues[index] : Complex32.Zero; return index >= 0 ? _nonZeroValues[index] : 0.0f;
} }
} }
@ -613,7 +612,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
if (index >= 0) if (index >= 0)
{ {
// Non-zero item found in matrix // Non-zero item found in matrix
if (value == Complex32.Zero) if (value == 0.0f)
{ {
// Delete existing item // Delete existing item
DeleteItemByIndex(index, row); DeleteItemByIndex(index, row);
@ -627,7 +626,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
else else
{ {
// Item not found. Add new value // Item not found. Add new value
if (value == Complex32.Zero) if (value == 0.0f)
{ {
return; return;
} }
@ -790,56 +789,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
sparseTarget._columnIndices = new int[NonZerosCount]; sparseTarget._columnIndices = new int[NonZerosCount];
sparseTarget.NonZerosCount = NonZerosCount; sparseTarget.NonZerosCount = NonZerosCount;
if (NonZerosCount != 0) Array.Copy(_nonZeroValues, sparseTarget._nonZeroValues, NonZerosCount);
{ Array.Copy(_columnIndices, sparseTarget._columnIndices, NonZerosCount);
CommonParallel.For(0, NonZerosCount, index => sparseTarget._nonZeroValues[index] = _nonZeroValues[index]); Array.Copy(_rowIndex, sparseTarget._rowIndex, RowCount);
Buffer.BlockCopy(_columnIndices, 0, sparseTarget._columnIndices, 0, NonZerosCount * Constants.SizeOfInt);
Buffer.BlockCopy(_rowIndex, 0, sparseTarget._rowIndex, 0, RowCount * Constants.SizeOfInt);
}
} }
} }
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="obj">
/// An object to compare with this object.
/// </param>
/// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="obj"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object obj)
{
var sparseMatrix = obj as SparseMatrix;
if (sparseMatrix == null)
{
return base.Equals(obj);
}
// Accept if the argument is the same object as this
if (ReferenceEquals(this, sparseMatrix))
{
return true;
}
if (ColumnCount != sparseMatrix.ColumnCount || RowCount != sparseMatrix.RowCount || NonZerosCount != sparseMatrix.NonZerosCount)
{
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < NonZerosCount; index++)
{
if (!_nonZeroValues[index].AlmostEqual(sparseMatrix._nonZeroValues[index]) || _columnIndices[index] != sparseMatrix._columnIndices[index])
{
return false;
}
}
return true;
}
/// <summary> /// <summary>
/// Returns a hash code for this instance. /// Returns a hash code for this instance.
/// </summary> /// </summary>
@ -853,9 +808,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
for (var i = 0; i < hashNum; i++) for (var i = 0; i < hashNum; i++)
{ {
#if SILVERLIGHT #if SILVERLIGHT
hash ^= Precision.DoubleToInt64Bits(_nonZeroValues[i].GetHashCode()); hash ^= Precision.DoubleToInt64Bits(_nonZeroValues[i].Magnitude);
#else #else
hash ^= BitConverter.DoubleToInt64Bits(_nonZeroValues[i].GetHashCode()); hash ^= BitConverter.DoubleToInt64Bits(_nonZeroValues[i].Magnitude);
#endif #endif
} }
@ -897,49 +852,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
return ret; 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 SparseMatrix(ColumnCount, RowCount)
{
_columnIndices = new int[NonZerosCount],
_nonZeroValues = new Complex32[NonZerosCount]
};
// Do an 'inverse' CopyTo iterate over the rows
for (var i = 0; i < _rowIndex.Length; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
// Get the values for the current row
if (startIndex == endIndex)
{
// Begin and end are equal. There are no values in the row, Move to the next row
continue;
}
for (var j = startIndex; j < endIndex; j++)
{
ret.SetValueAt(_columnIndices[j], i, _nonZeroValues[j].Conjugate());
}
}
return ret;
}
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override Complex32 FrobeniusNorm()
{ {
var transpose = (SparseMatrix)Transpose(); var transpose = (SparseMatrix)Transpose();
var aat = this * transpose; var aat = (SparseMatrix)(this * transpose);
var norm = 0.0; var norm = 0.0f;
for (var i = 0; i < aat._rowIndex.Length; i++) for (var i = 0; i < aat._rowIndex.Length; i++)
{ {
@ -963,15 +883,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
} }
norm = Math.Sqrt(norm); norm = Convert.ToSingle(Math.Sqrt(norm));
return norm; return norm;
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override Complex32 InfinityNorm()
{ {
var norm = 0.0; var norm = 0.0f;
for (var i = 0; i < _rowIndex.Length; i++) for (var i = 0; i < _rowIndex.Length; i++)
{ {
// Get the begin / end index for the current row // Get the begin / end index for the current row
@ -985,7 +905,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
continue; continue;
} }
var s = 0.0; var s = 0.0f;
for (var j = startIndex; j < endIndex; j++) for (var j = startIndex; j < endIndex; j++)
{ {
s += _nonZeroValues[j].Magnitude; s += _nonZeroValues[j].Magnitude;
@ -1060,7 +980,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
{ {
// Copy code from At(row, column) to avoid unnecessary lock // Copy code from At(row, column) to avoid unnecessary lock
var index = FindItem(rowIndex, i); var index = FindItem(rowIndex, i);
result[j] = index >= 0 ? _nonZeroValues[index] : Complex32.Zero; result[j] = index >= 0 ? _nonZeroValues[index] : 0.0f;
} }
} }
} }
@ -1112,200 +1032,231 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
} }
#region Elementary operations #region Static constructors for special matrices.
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Initializes a square <see cref="SparseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="order">the size of the square matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>Identity <c>SparseMatrix</c></returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// <exception cref="ArgumentException">
public override void Add(Matrix<Complex32> other) /// If <paramref name="order"/> is less than one.
/// </exception>
public static SparseMatrix Identity(int order)
{ {
if (ReferenceEquals(this, other)) var m = new SparseMatrix(order)
{ {
Multiply(2); NonZerosCount = order,
return; _nonZeroValues = new Complex32[order],
} _columnIndices = new int[order]
};
var m = other as SparseMatrix; for (var i = 0; i < order; i++)
if (m == null)
{
base.Add(other);
}
else
{ {
Add(m); m._nonZeroValues[i] = 1.0f;
m._columnIndices[i] = i;
m._rowIndex[i] = i;
} }
return m;
} }
#endregion
/// <summary> /// <summary>
/// Adds another <see cref="SparseMatrix"/> to this matrix. The result will be written into this matrix. /// Indicates whether the current object is equal to another object of the same type.
/// </summary> /// </summary>
/// <param name="other">The <see cref="SparseMatrix"/> to add to this matrix.</param> /// <param name="other">
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// An object to compare with this object.
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// </param>
public void Add(SparseMatrix other) /// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="other"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(Matrix<Complex32> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); return false;
} }
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); return false;
} }
for (var i = 0; i < other.RowCount; i++) // Accept if the argument is the same object as this.
if (ReferenceEquals(this, other))
{ {
// Get the begin / end index for the current row return true;
var startIndex = other._rowIndex[i]; }
var endIndex = i < other._rowIndex.Length - 1 ? other._rowIndex[i + 1] : other.NonZerosCount;
for (var j = startIndex; j < endIndex; j++) var sparseMatrix = other as SparseMatrix;
if (sparseMatrix == null)
{
return base.Equals(other);
}
if (NonZerosCount != sparseMatrix.NonZerosCount)
{
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < NonZerosCount; index++)
{
if (!_nonZeroValues[index].AlmostEqual(sparseMatrix._nonZeroValues[index]) || _columnIndices[index] != sparseMatrix._columnIndices[index])
{ {
var index = FindItem(i, other._columnIndices[j]); return false;
if (index >= 0)
{
if (_nonZeroValues[index] + other._nonZeroValues[j] == Complex32.Zero)
{
DeleteItemByIndex(index, i);
}
else
{
_nonZeroValues[index] += other._nonZeroValues[j];
}
}
else
{
SetValueAt(i, other._columnIndices[j], other._nonZeroValues[j]);
}
} }
} }
return true;
} }
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the addition.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override void Subtract(Matrix<Complex32> other) protected override void DoAdd(Matrix<Complex32> other, Matrix<Complex32> result)
{ {
// We are substracting Matrix form itself result.Clear();
if (ReferenceEquals(this, other))
{
Clear();
return;
}
var m = other as SparseMatrix; var sparseResult = result as SparseMatrix;
if (m == null) if (sparseResult == null)
{ {
base.Subtract(other); for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{
var resVal = _nonZeroValues[j] + other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{
result.At(i, _columnIndices[j], resVal);
}
}
}
} }
else else
{ {
Subtract(m); for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{
var resVal = _nonZeroValues[j] + other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
}
}
} }
} }
/// <summary> /// <summary>
/// Subtracts another <see cref="SparseMatrix"/> from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="SparseMatrix"/> to subtract.</param> /// <param name="other">The matrix to subtract to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of subtraction.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(SparseMatrix other) protected override void DoSubtract(Matrix<Complex32> other, Matrix<Complex32> result)
{ {
if (other == null) result.Clear();
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
for (var i = 0; i < other.RowCount; i++) var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{ {
// Get the begin / end index for the current row for (var i = 0; i < other.RowCount; i++)
var startIndex = other._rowIndex[i];
var endIndex = i < other._rowIndex.Length - 1 ? other._rowIndex[i + 1] : other.NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
var index = FindItem(i, other._columnIndices[j]); // Get the begin / end index for the current row
if (index >= 0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
if (_nonZeroValues[index] - other._nonZeroValues[j] == Complex32.Zero) var resVal = _nonZeroValues[j] - other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{ {
DeleteItemByIndex(index, i); result.At(i, _columnIndices[j], resVal);
}
else
{
_nonZeroValues[index] -= other._nonZeroValues[j];
} }
} }
else }
}
else
{
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
SetValueAt(i, other._columnIndices[j], -other._nonZeroValues[j]); var resVal = _nonZeroValues[j] - other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
} }
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a complex. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="complex">The complex to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(Complex32 complex) /// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(Complex32 scalar, Matrix<Complex32> result)
{ {
if (Complex32.One.AlmostEqual(complex)) if (scalar == 1.0f)
{ {
CopyTo(result);
return; return;
} }
if (Complex32.Zero.AlmostEqual(complex)) if (scalar == 0.0f)
{ {
Clear(); result.Clear();
return; return;
} }
Control.LinearAlgebraProvider.ScaleArray(complex, _nonZeroValues); var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._nonZeroValues);
}
} }
/// <summary> /// <summary>
/// Multiplies this sparse matrix with another sparse matrix and places the results into the result sparse matrix. /// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If <strong>Columns != other.Rows</strong>.</exception>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the Rows x other.Columns.</exception>
public override void Multiply(Matrix<Complex32> other, Matrix<Complex32> result)
{ {
var otherSparseMatrix = other as SparseMatrix; var otherSparseMatrix = other as SparseMatrix;
var resultSparseMatrix = result as SparseMatrix; var resultSparseMatrix = result as SparseMatrix;
if (otherSparseMatrix == null || resultSparseMatrix == null) if (otherSparseMatrix == null || resultSparseMatrix == null)
{ {
base.Multiply(other, result); base.DoMultiply(other, result);
return; return;
} }
if (ColumnCount != otherSparseMatrix.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
if (resultSparseMatrix.RowCount != RowCount || resultSparseMatrix.ColumnCount != otherSparseMatrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
resultSparseMatrix.Clear(); resultSparseMatrix.Clear();
var columnVector = new DenseVector(otherSparseMatrix.RowCount); var columnVector = new DenseVector(otherSparseMatrix.RowCount);
for (var row = 0; row < RowCount; row++) for (var row = 0; row < RowCount; row++)
@ -1332,60 +1283,21 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
} }
/// <summary> /// <summary>
/// Multiplies this matrix with another matrix and returns the result. /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>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)
{
var matrix = other as SparseMatrix;
if (matrix == null)
{
return base.Multiply(other);
}
if (ColumnCount != matrix.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
var result = (SparseMatrix)CreateMatrix(RowCount, matrix.ColumnCount);
Multiply(matrix, result);
return result;
}
/// <summary>
/// Multiplies this dense matrix with transpose of another dense matrix and places the results into the result dense matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoTransposeAndMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
/// <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 otherSparse = other as SparseMatrix; var otherSparse = other as SparseMatrix;
var resultSparse = result as SparseMatrix; var resultSparse = result as SparseMatrix;
if (otherSparse == null || resultSparse == null) if (otherSparse == null || resultSparse == null)
{ {
base.TransposeAndMultiply(other, result); base.DoTransposeAndMultiply(other, result);
return; return;
} }
if (ColumnCount != otherSparse.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
if ((resultSparse.RowCount != RowCount) || (resultSparse.ColumnCount != otherSparse.RowCount))
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
resultSparse.Clear(); resultSparse.Clear();
for (var j = 0; j < RowCount; j++) for (var j = 0; j < RowCount; j++)
{ {
@ -1415,65 +1327,22 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
index => index =>
{ {
var ind = FindItem(i1, otherSparse._columnIndices[index]); var ind = FindItem(i1, otherSparse._columnIndices[index]);
return ind >= 0 ? otherSparse._nonZeroValues[index] * _nonZeroValues[ind] : Complex32.Zero; return ind >= 0 ? otherSparse._nonZeroValues[index] * _nonZeroValues[ind] : 0.0f;
}); });
resultSparse.SetValueAt(i, j, sum + result.At(i, j)); resultSparse.SetValueAt(i, j, sum + result.At(i, j));
} }
} }
} }
/// <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 otherSparse = other as SparseMatrix;
if (otherSparse == null)
{
return base.TransposeAndMultiply(other);
}
if (ColumnCount != otherSparse.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
var result = (SparseMatrix)CreateMatrix(RowCount, other.RowCount);
TransposeAndMultiply(other, result);
return result;
}
/// <summary> /// <summary>
/// Multiplies two sparse matrices. /// Negate each element of this matrix and place the results into the result matrix.
/// </summary> /// </summary>
/// <param name="leftSide">The left matrix to multiply.</param> /// <param name="result">The result of the negation.</param>
/// <param name="rightSide">The right matrix to multiply.</param> protected override void DoNegate(Matrix<Complex32> result)
/// <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 SparseMatrix operator *(SparseMatrix leftSide, SparseMatrix rightSide)
{ {
if (leftSide == null) CopyTo(result);
{ DoMultiply(-1, result);
throw new ArgumentNullException("leftSide");
}
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide.ColumnCount != rightSide.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
return (SparseMatrix)leftSide.Multiply(rightSide);
} }
/// <summary> /// <summary>
@ -1481,221 +1350,95 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// </summary> /// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param> /// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param> /// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoPointwiseMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public override void PointwiseMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{ {
if (other == null)
{
throw new ArgumentNullException("other");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
result.Clear(); result.Clear();
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++) var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{
for (var i = 0; i < other.RowCount; i++)
{ {
var resVal = _nonZeroValues[j] * other[i, _columnIndices[j]]; // Get the begin / end index for the current row
if (resVal != Complex32.Zero) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
result[i, _columnIndices[j]] = resVal; var resVal = _nonZeroValues[j] * other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{
result.At(i, _columnIndices[j], resVal);
}
} }
} }
} }
} else
/// <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 = (SparseMatrix)CreateMatrix(numberOfRows, numberOfColumns);
for (var i = 0; i < matrix.RowCount; i++)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var i = 0; i < other.RowCount; i++)
{ {
var value = new Complex32((float)distribution.Sample(), (float)distribution.Sample()); // Get the begin / end index for the current row
if (value != Complex32.Zero) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
matrix.SetValueAt(i, j, value); var resVal = _nonZeroValues[j] * other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
} }
return matrix;
} }
/// <summary> /// <summary>
/// Generates matrix with random elements. /// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <param name="numberOfRows">Number of rows.</param> /// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="numberOfColumns">Number of columns.</param> /// <param name="result">The matrix to store the result of the pointwise division.</param>
/// <param name="distribution">Continuous Random Distribution or Source</param> protected override void DoPointwiseDivide(Matrix<Complex32> other, Matrix<Complex32> result)
/// <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) result.Clear();
{
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows");
}
if (numberOfColumns < 1)
{
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns");
}
var matrix = (SparseMatrix)CreateMatrix(numberOfRows, numberOfColumns); var sparseResult = result as SparseMatrix;
for (var i = 0; i < matrix.RowCount; i++) if (sparseResult == null)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var i = 0; i < other.RowCount; i++)
{ {
var value = new Complex32(distribution.Sample(), distribution.Sample()); // Get the begin / end index for the current row
if (value != Complex32.Zero) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
matrix.SetValueAt(i, j, value); var resVal = _nonZeroValues[j] / other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{
result.At(i, _columnIndices[j], resVal);
}
} }
} }
} }
else
{
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
return matrix; for (var j = startIndex; j < endIndex; j++)
}
#endregion
#region Static constructors for special matrices.
/// <summary>
/// Initializes a square <see cref="SparseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary>
/// <param name="order">the size of the square matrix.</param>
/// <returns>Identity <c>SparseMatrix</c></returns>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public static SparseMatrix Identity(int order)
{
var m = new SparseMatrix(order)
{ {
NonZerosCount = order, var resVal = _nonZeroValues[j] / other.At(i, _columnIndices[j]);
_nonZeroValues = new Complex32[order], if (resVal != 0.0f)
_columnIndices = new int[order] {
}; sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
for (var i = 0; i < order; i++) }
{ }
m._nonZeroValues[i] = Complex32.One;
m._columnIndices[i] = i;
m._rowIndex[i] = i;
} }
return m;
}
#endregion
/// <summary>
/// Negates each element of this matrix.
/// </summary>
public override void Negate()
{
Multiply(-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>
/// 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
} }
} }

6
src/Numerics/LinearAlgebra/Complex32/Vector.cs

@ -66,7 +66,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] + scalar); index => result[index] = this[index] + scalar);
} }
/// <summary> /// <summary>
@ -132,7 +132,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] * scalar); index => result[index] = this[index] * scalar);
} }
/// <summary> /// <summary>
@ -149,7 +149,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] / scalar); index => result[index] = this[index] / scalar);
} }
/// <summary> /// <summary>

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

@ -27,7 +27,6 @@
namespace MathNet.Numerics.LinearAlgebra.Double namespace MathNet.Numerics.LinearAlgebra.Double
{ {
using System; using System;
using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Threading; using Threading;
@ -242,7 +241,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override double FrobeniusNorm() public override double FrobeniusNorm()
{ {
var transpose = (DenseMatrix)Transpose(); var transpose = (DenseMatrix)Transpose();
var aat = (DenseMatrix) (this * transpose); var aat = (DenseMatrix)(this * transpose);
var norm = 0.0; var norm = 0.0;
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
@ -332,7 +331,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
var m = new DenseMatrix(order); var m = new DenseMatrix(order);
for (var i = 0; i < order; i++) for (var i = 0; i < order; i++)
{ {
m[i, i] = 1.0; m.Data[(i * order) + i] = 1.0;
} }
return m; return m;
@ -340,82 +339,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double
#endregion #endregion
/// <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<double> 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] = 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<double> 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] = distribution.Sample();
}
});
return matrix;
}
/// <summary> /// <summary>
/// Returns the conjugate transpose of this matrix. /// Returns the conjugate transpose of this matrix.
/// </summary> /// </summary>
@ -425,20 +348,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double
return Transpose(); return Transpose();
} }
/* Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose,
1.0,
Data,
RowCount,
ColumnCount,
otherDense.Data,
otherDense.RowCount,
otherDense.ColumnCount,
1.0,
resultDense.Data);
*/
/// <summary> /// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
@ -453,10 +362,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, Data); Control.LinearAlgebraProvider.ScaleArray(scalar, denseResult.Data);
} }
} }
/// <summary> /// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector. /// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary> /// </summary>
@ -464,19 +373,28 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<double> rightSide, Vector<double> result) protected override void DoMultiply(Vector<double> rightSide, Vector<double> result)
{ {
CommonParallel.For( var denseRight = rightSide as DenseVector;
0, var denseResult = result as DenseVector;
RowCount,
i => if (denseRight == null || denseResult == null)
{ {
var s = 0.0; base.DoMultiply(rightSide, result);
for (var j = 0; j != ColumnCount; j++) }
{ else
s += At(i, j) * rightSide[j]; {
} Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
result[i] = s; Algorithms.LinearAlgebra.Transpose.DontTranspose,
}); 1.0,
Data,
RowCount,
ColumnCount,
denseRight.Data,
denseRight.Count,
1,
0.0,
denseResult.Data);
}
} }
/// <summary> /// <summary>
@ -486,19 +404,28 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
protected override void DoLeftMultiply(Vector<double> leftSide, Vector<double> result) protected override void DoLeftMultiply(Vector<double> leftSide, Vector<double> result)
{ {
CommonParallel.For( var denseLeft = leftSide as DenseVector;
0, var denseResult = result as DenseVector;
RowCount,
j => if (denseLeft == null || denseResult == null)
{ {
var s = 0.0; base.DoLeftMultiply(leftSide, result);
for (var i = 0; i != leftSide.Count; i++) }
{ else
s += leftSide[i] * At(i, j); {
} Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
result[j] = s; Algorithms.LinearAlgebra.Transpose.DontTranspose,
}); 1.0,
denseLeft.Data,
1,
denseResult.Count,
Data,
RowCount,
ColumnCount,
0.0,
denseResult.Data);
}
} }
/// <summary> /// <summary>
@ -517,41 +444,20 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
CommonParallel.For( Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
0, Algorithms.LinearAlgebra.Transpose.DontTranspose,
RowCount, Algorithms.LinearAlgebra.Transpose.DontTranspose,
j => 1.0,
{ Data,
for (var i = 0; i != other.ColumnCount; i++) RowCount,
{ ColumnCount,
var s = 0.0; denseOther.Data,
for (var l = 0; l < ColumnCount; l++) denseOther.RowCount,
{ denseOther.ColumnCount,
s += Data[(j * RowCount) + l] * denseOther.Data[(i * RowCount) + l]; 0.0,
} denseResult.Data);
result.At(j, i, s);
}
});
CommonParallel.For(
0,
RowCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
var s = 0.0;
for (var l = 0; l < ColumnCount; l++)
{
s += Data[(j * RowCount) + l] * denseOther.Data[(l * RowCount) + j];
}
denseResult.Data[(j * RowCount) + i] *= s;
}
});
}
} }
}
/// <summary> /// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix. /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
@ -569,22 +475,18 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
CommonParallel.For( Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
0, Algorithms.LinearAlgebra.Transpose.DontTranspose,
RowCount, Algorithms.LinearAlgebra.Transpose.Transpose,
j => 1.0,
{ Data,
for (var i = 0; i < RowCount; i++) RowCount,
{ ColumnCount,
var s = 0.0; denseOther.Data,
for (var l = 0; l < ColumnCount; l++) denseOther.RowCount,
{ denseOther.ColumnCount,
s += Data[(j * RowCount) + l] * denseOther.Data[(l * RowCount) + j]; 0.0,
} denseResult.Data);
denseResult.Data[(j * RowCount) + i] *= s;
}
});
} }
} }
@ -602,17 +504,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
CommonParallel.For( Buffer.BlockCopy(Data, 0, denseResult.Data, 0, Data.Length * Constants.SizeOfDouble);
0, Control.LinearAlgebraProvider.ScaleArray(-1, denseResult.Data);
RowCount,
i =>
{
for (var j = 0; j != ColumnCount; j++)
{
var index = (j * RowCount) + i;
denseResult.Data[index] =- Data[index];
}
});
} }
} }
@ -632,18 +525,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
CommonParallel.For( Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, denseOther.Data, denseResult.Data);
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
var index = (j * RowCount) + i;
denseResult.Data[index] = Data[index] * denseOther.Data[index];
}
});
} }
} }
@ -663,17 +545,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
else else
{ {
CommonParallel.For( Control.LinearAlgebraProvider.PointWiseDivideArrays(Data, denseOther.Data, denseResult.Data);
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
var index = (j * RowCount) + i;
denseResult.Data[index] = Data[index] / denseOther.Data[index];
}
});
} }
} }

384
src/Numerics/LinearAlgebra/Double/DiagonalMatrix.cs

@ -28,8 +28,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
using System; using System;
using System.Linq; using System.Linq;
using System.Text;
using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Threading; using Threading;
@ -43,7 +41,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// entries are set. The exception to this is when the off diagonal elements are /// entries are set. The exception to this is when the off diagonal elements are
/// 0.0 or NaN; these settings will cause no change to the diagonal matrix. /// 0.0 or NaN; these settings will cause no change to the diagonal matrix.
/// </remarks> /// </remarks>
public class DiagonalMatrix : Matrix<double> public class DiagonalMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DiagonalMatrix"/> class. This matrix is square with a given size. /// Initializes a new instance of the <see cref="DiagonalMatrix"/> class. This matrix is square with a given size.
@ -279,92 +277,155 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
#region Elementary operations #region Elementary operations
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>The result of the addition.</returns>
/// <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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
/// <exception cref="ArgumentException">If <paramref name="other"/> is not <see cref="DiagonalMatrix"/>.</exception> public override Matrix<double> Add(Matrix<double> other)
public override void Add(Matrix<double> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
var m = other as DiagonalMatrix; if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
if (m == null)
{ {
throw new ArgumentException(Resources.ArgumentTypeMismatch); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
} }
Add(m); Matrix<double> result;
if (other is DiagonalMatrix)
{
result = new DenseMatrix(RowCount, ColumnCount);
}
else
{
result = new DiagonalMatrix(RowCount, ColumnCount);
}
Add(other, result);
return result;
} }
/// <summary> /// <summary>
/// Adds another <see cref="DiagonalMatrix"/> to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DiagonalMatrix"/> to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the addition.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Add(DiagonalMatrix other) public override void Add(Matrix<double> other, Matrix<double> result)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
if (result == null)
{
throw new ArgumentNullException("result");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
} }
Control.LinearAlgebraProvider.AddArrays(Data, other.Data, Data); if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException("result", Resources.ArgumentMatrixDimensions);
}
var diagOther = other as DiagonalMatrix;
var diagResult = result as DiagonalMatrix;
if (diagOther == null || diagResult == null)
{
base.Add(other, result);
}
else
{
Control.LinearAlgebraProvider.AddArrays(Data, diagOther.Data, diagResult.Data);
}
} }
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>The result of the subtraction.</returns>
/// <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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
/// <exception cref="ArgumentException">If <paramref name="other"/> is not <see cref="DiagonalMatrix"/>.</exception> public override Matrix<double> Subtract(Matrix<double> other)
public override void Subtract(Matrix<double> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
var m = other as DiagonalMatrix; if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
if (m == null) {
throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
Matrix<double> result;
if (other is DiagonalMatrix)
{
result = new DenseMatrix(RowCount, ColumnCount);
}
else
{ {
throw new ArgumentException(Resources.ArgumentTypeMismatch); result = new DiagonalMatrix(RowCount, ColumnCount);
} }
Subtract(m); Subtract(other, result);
return result;
} }
/// <summary> /// <summary>
/// Subtracts another <see cref="DiagonalMatrix"/> from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DiagonalMatrix"/> to subtract.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the subtraction.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(DiagonalMatrix other) public override void Subtract(Matrix<double> other, Matrix<double> result)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
if (result == null)
{
throw new ArgumentNullException("result");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException("result", Resources.ArgumentMatrixDimensions);
} }
Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); var diagOther = other as DiagonalMatrix;
var diagResult = result as DiagonalMatrix;
if (diagOther == null || diagResult == null)
{
base.Subtract(other, result);
}
else
{
Control.LinearAlgebraProvider.SubtractArrays(Data, diagOther.Data, diagResult.Data);
}
} }
/// <summary> /// <summary>
@ -420,23 +481,41 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a scalar. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="scalar">The scalar to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(double scalar) /// <param name="result">The matrix to store the result of the multiplication.</param>
/// <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 Multiply(double scalar, Matrix<double> result)
{ {
if (result == null)
{
throw new ArgumentNullException("result");
}
if (scalar == 0.0) if (scalar == 0.0)
{ {
Clear(); result.Clear();
return; return;
} }
if (scalar == 1.0) if (scalar == 1.0)
{ {
CopyTo(result);
return; return;
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, Data); var diagResult = result as DiagonalMatrix;
if (diagResult == null)
{
base.Multiply(scalar, result);
}
else
{
CopyTo(diagResult);
Control.LinearAlgebraProvider.ScaleArray(scalar, diagResult.Data);
}
} }
/// <summary> /// <summary>
@ -693,34 +772,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double
return result; return result;
} }
/// <summary>
/// Multiplies two diagonal 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 DiagonalMatrix operator *(DiagonalMatrix leftSide, DiagonalMatrix 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 (DiagonalMatrix)leftSide.Multiply(rightSide);
}
#endregion #endregion
/// <summary> /// <summary>
@ -1464,50 +1515,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double
CommonParallel.For(0, lower.RowCount, i => CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j)))); CommonParallel.For(0, lower.RowCount, i => CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j))));
} }
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise 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 this matrix and <paramref name="other"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public override void PointwiseMultiply(Matrix<double> other, Matrix<double> result)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
var m = other as DiagonalMatrix;
var r = result as DiagonalMatrix;
if (m == null || r == null)
{
base.PointwiseMultiply(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, m.Data, r.Data);
}
}
/// <summary> /// <summary>
/// Permute the columns of a matrix according to a permutation. /// Permute the columns of a matrix according to a permutation.
/// </summary> /// </summary>
@ -1529,6 +1536,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
{ {
throw new InvalidOperationException("Permutations in diagonal matrix are not allowed"); throw new InvalidOperationException("Permutations in diagonal matrix are not allowed");
} }
#region Static constructors for special matrices. #region Static constructors for special matrices.
/// <summary> /// <summary>
@ -1551,165 +1559,5 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
#endregion #endregion
/// <summary>
/// Negates each element of this matrix.
/// </summary>
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<double> 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);
var mn = Math.Min(numberOfRows, numberOfColumns);
CommonParallel.For(0, mn, i => matrix[i, i] = 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<double> 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);
var mn = Math.Min(numberOfRows, numberOfColumns);
CommonParallel.For(0, mn, i => matrix[i, i] = distribution.Sample());
return matrix;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <param name="format">
/// The format to use.
/// </param>
/// <param name="formatProvider">
/// The format provider to use.
/// </param>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString(string format, IFormatProvider formatProvider)
{
var stringBuilder = new StringBuilder();
for (var row = 0; row < RowCount; row++)
{
for (var column = 0; column < ColumnCount; column++)
{
stringBuilder.Append(At(row, column).ToString(format, formatProvider));
if (column != ColumnCount - 1)
{
stringBuilder.Append(formatProvider.GetTextInfo().ListSeparator);
}
}
if (row != RowCount - 1)
{
stringBuilder.Append(Environment.NewLine);
}
}
return stringBuilder.ToString();
}
#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 double AddT(double val1, double 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 double SubtractT(double val1, double 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 double MultiplyT(double val1, double 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 double DivideT(double val1, double 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(double val1)
{
return Math.Abs(val1);
}
#endregion
} }
} }

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

@ -0,0 +1,403 @@
// <copyright file="Matrix.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.Double
{
using System;
using Distributions;
using Generic;
using Properties;
using Threading;
/// <summary>
/// <c>double</c> version of the <see cref="Matrix{T}"/> class.
/// </summary>
public abstract class Matrix : Matrix<double>
{
/// <summary>
/// Initializes a new instance of the Matrix class.
/// </summary>
/// <param name="rows">
/// The number of rows.
/// </param>
/// <param name="columns">
/// The number of columns.
/// </param>
protected Matrix(int rows, int columns) : base(rows, columns)
{
}
/// <summary>
/// Initializes a new instance of the Matrix class.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
protected Matrix(int order)
: base(order)
{
}
/// <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 += Math.Abs(At(i, j));
}
norm = Math.Max(norm, s);
}
return norm;
}
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<double> ConjugateTranspose()
{
return Transpose();
}
/// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm()
{
var transpose = Transpose();
var aat = this * transpose;
var norm = 0.0;
for (var i = 0; i < RowCount; i++)
{
norm += Math.Abs(aat.At(i, i));
}
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 += Math.Abs(At(i, j));
}
norm = Math.Max(norm, s);
}
return norm;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of the addition.</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>
protected override void DoAdd(Matrix<double> other, Matrix<double> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) + other.At(i, j));
}
});
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract to this matrix.</param>
/// <param name="result">The matrix to store the result of subtraction.</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>
protected override void DoSubtract(Matrix<double> other, Matrix<double> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) - other.At(i, j));
}
});
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(double scalar, Matrix<double> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) * scalar);
}
});
}
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<double> rightSide, Vector<double> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
var s = 0.0;
for (var j = 0; j != ColumnCount; j++)
{
s += At(i, j) * rightSide[j];
}
result[i] = s;
});
}
/// <summary>
/// Divides each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to divide the matrix with.</param>
/// <param name="result">The matrix to store the result of the division.</param>
protected override void DoDivide(double scalar, Matrix<double> result)
{
DoMultiply(1.0 / scalar, result);
}
/// <summary>
/// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector.
/// </summary>
/// <param name="leftSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoLeftMultiply(Vector<double> leftSide, Vector<double> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
var s = 0.0;
for (var i = 0; i != leftSide.Count; i++)
{
s += leftSide[i] * At(i, j);
}
result[j] = s;
});
}
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Matrix<double> other, Matrix<double> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
for (var i = 0; i != other.ColumnCount; i++)
{
var s = 0.0;
for (var l = 0; l < ColumnCount; l++)
{
s += At(j, l) * other.At(l, i);
}
result.At(j, i, s);
}
});
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoTransposeAndMultiply(Matrix<double> other, Matrix<double> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
var s = 0.0;
for (var l = 0; l < ColumnCount; l++)
{
s += At(i, l) * other.At(j, l);
}
result.At(i, j, s);
}
});
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
protected override void DoNegate(Matrix<double> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j != ColumnCount; j++)
{
result[i, j] = -At(i, j);
}
});
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
protected override void DoPointwiseMultiply(Matrix<double> other, Matrix<double> result)
{
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
result.At(i, j, At(i, j) * other.At(i, j));
}
});
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
protected override void DoPointwiseDivide(Matrix<double> other, Matrix<double> result)
{
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
result.At(i, j, At(i, j) / other.At(i, j));
}
});
}
/// <summary>
/// Computes the trace of this matrix.
/// </summary>
/// <returns>The trace of this matrix</returns>
/// <exception cref="ArgumentException">If the matrix is not square</exception>
public override double Trace()
{
if (RowCount != ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
return CommonParallel.Aggregate(0, RowCount, i => At(i, i));
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<double> matrix, IContinuousDistribution distribution)
{
CommonParallel.For(
0,
matrix.RowCount,
i =>
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
matrix.At(i, j, distribution.Sample());
}
});
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<double> matrix, IDiscreteDistribution distribution)
{
CommonParallel.For(
0,
matrix.RowCount,
i =>
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
matrix.At(i, j, distribution.Sample());
}
});
}
}
}

689
src/Numerics/LinearAlgebra/Double/SparseMatrix.cs

@ -31,8 +31,6 @@
namespace MathNet.Numerics.LinearAlgebra.Double namespace MathNet.Numerics.LinearAlgebra.Double
{ {
using System; using System;
using System.Text;
using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Threading; using Threading;
@ -41,7 +39,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// A Matrix class with sparse storage. The underlying storage scheme is 3-array compressed-sparse-row (CSR) Format. /// A Matrix class with sparse storage. The underlying storage scheme is 3-array compressed-sparse-row (CSR) Format.
/// <a href="http://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR_or_CRS.29">Wikipedia - CSR</a>. /// <a href="http://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR_or_CRS.29">Wikipedia - CSR</a>.
/// </summary> /// </summary>
public class SparseMatrix : Matrix<double> public class SparseMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Object for use in "lock" /// Object for use in "lock"
@ -858,7 +856,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
public override double FrobeniusNorm() public override double FrobeniusNorm()
{ {
var transpose = (SparseMatrix)Transpose(); var transpose = (SparseMatrix)Transpose();
var aat = this * transpose; var aat = (SparseMatrix)(this * transpose);
var norm = 0.0; var norm = 0.0;
@ -1033,200 +1031,231 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
} }
#region Elementary operations #region Static constructors for special matrices.
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Initializes a square <see cref="SparseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="order">the size of the square matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>Identity <c>SparseMatrix</c></returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// <exception cref="ArgumentException">
public override void Add(Matrix<double> other) /// If <paramref name="order"/> is less than one.
/// </exception>
public static SparseMatrix Identity(int order)
{ {
if (ReferenceEquals(this, other)) var m = new SparseMatrix(order)
{ {
Multiply(2); NonZerosCount = order,
return; _nonZeroValues = new double[order],
} _columnIndices = new int[order]
};
var m = other as SparseMatrix; for (var i = 0; i < order; i++)
if (m == null)
{
base.Add(other);
}
else
{ {
Add(m); m._nonZeroValues[i] = 1.0;
m._columnIndices[i] = i;
m._rowIndex[i] = i;
} }
return m;
} }
#endregion
/// <summary> /// <summary>
/// Adds another <see cref="SparseMatrix"/> to this matrix. The result will be written into this matrix. /// Indicates whether the current object is equal to another object of the same type.
/// </summary> /// </summary>
/// <param name="other">The <see cref="SparseMatrix"/> to add to this matrix.</param> /// <param name="other">
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// An object to compare with this object.
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// </param>
public void Add(SparseMatrix other) /// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="other"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(Matrix<double> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); return false;
} }
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); return false;
}
// Accept if the argument is the same object as this.
if (ReferenceEquals(this, other))
{
return true;
} }
for (var i = 0; i < other.RowCount; i++) var sparseMatrix = other as SparseMatrix;
if (sparseMatrix == null)
{ {
// Get the begin / end index for the current row return base.Equals(other);
var startIndex = other._rowIndex[i]; }
var endIndex = i < other._rowIndex.Length - 1 ? other._rowIndex[i + 1] : other.NonZerosCount;
for (var j = startIndex; j < endIndex; j++) if (NonZerosCount != sparseMatrix.NonZerosCount)
{
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < NonZerosCount; index++)
{
if (!_nonZeroValues[index].AlmostEqual(sparseMatrix._nonZeroValues[index]) || _columnIndices[index] != sparseMatrix._columnIndices[index])
{ {
var index = FindItem(i, other._columnIndices[j]); return false;
if (index >= 0)
{
if (_nonZeroValues[index] + other._nonZeroValues[j] == 0.0)
{
DeleteItemByIndex(index, i);
}
else
{
_nonZeroValues[index] += other._nonZeroValues[j];
}
}
else
{
SetValueAt(i, other._columnIndices[j], other._nonZeroValues[j]);
}
} }
} }
return true;
} }
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the addition.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override void Subtract(Matrix<double> other) protected override void DoAdd(Matrix<double> other, Matrix<double> result)
{ {
// We are substracting Matrix form itself result.Clear();
if (ReferenceEquals(this, other))
{
Clear();
return;
}
var m = other as SparseMatrix; var sparseResult = result as SparseMatrix;
if (m == null) if (sparseResult == null)
{ {
base.Subtract(other); for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{
var resVal = _nonZeroValues[j] + other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
result.At(i, _columnIndices[j], resVal);
}
}
}
} }
else else
{ {
Subtract(m); for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{
var resVal = _nonZeroValues[j] + other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
}
}
} }
} }
/// <summary> /// <summary>
/// Subtracts another <see cref="SparseMatrix"/> from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="SparseMatrix"/> to subtract.</param> /// <param name="other">The matrix to subtract to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of subtraction.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(SparseMatrix other) protected override void DoSubtract(Matrix<double> other, Matrix<double> result)
{ {
if (other == null) result.Clear();
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
for (var i = 0; i < other.RowCount; i++) var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{ {
// Get the begin / end index for the current row for (var i = 0; i < other.RowCount; i++)
var startIndex = other._rowIndex[i];
var endIndex = i < other._rowIndex.Length - 1 ? other._rowIndex[i + 1] : other.NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
var index = FindItem(i, other._columnIndices[j]); // Get the begin / end index for the current row
if (index >= 0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
if (_nonZeroValues[index] - other._nonZeroValues[j] == 0.0) var resVal = _nonZeroValues[j] - other.At(i, _columnIndices[j]);
{ if (resVal != 0.0)
DeleteItemByIndex(index, i);
}
else
{ {
_nonZeroValues[index] -= other._nonZeroValues[j]; result.At(i, _columnIndices[j], resVal);
} }
} }
else }
}
else
{
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
SetValueAt(i, other._columnIndices[j], -other._nonZeroValues[j]); var resVal = _nonZeroValues[j] - other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
} }
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a scalar. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="scalar">The scalar to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(double scalar) /// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(double scalar, Matrix<double> result)
{ {
if (1.0.AlmostEqualInDecimalPlaces(scalar, 15)) if (scalar == 1.0)
{ {
CopyTo(result);
return; return;
} }
if (0.0.AlmostEqualInDecimalPlaces(scalar, 15)) if (scalar == 0.0)
{ {
Clear(); result.Clear();
return; return;
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, _nonZeroValues); var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._nonZeroValues);
}
} }
/// <summary> /// <summary>
/// Multiplies this sparse matrix with another sparse matrix and places the results into the result sparse matrix. /// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(Matrix<double> other, Matrix<double> result)
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If <strong>Columns != other.Rows</strong>.</exception>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the Rows x other.Columns.</exception>
public override void Multiply(Matrix<double> other, Matrix<double> result)
{ {
var otherSparseMatrix = other as SparseMatrix; var otherSparseMatrix = other as SparseMatrix;
var resultSparseMatrix = result as SparseMatrix; var resultSparseMatrix = result as SparseMatrix;
if (otherSparseMatrix == null || resultSparseMatrix == null) if (otherSparseMatrix == null || resultSparseMatrix == null)
{ {
base.Multiply(other, result); base.DoMultiply(other, result);
return; return;
} }
if (ColumnCount != otherSparseMatrix.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
if (resultSparseMatrix.RowCount != RowCount || resultSparseMatrix.ColumnCount != otherSparseMatrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
resultSparseMatrix.Clear(); resultSparseMatrix.Clear();
var columnVector = new DenseVector(otherSparseMatrix.RowCount); var columnVector = new DenseVector(otherSparseMatrix.RowCount);
for (var row = 0; row < RowCount; row++) for (var row = 0; row < RowCount; row++)
@ -1253,60 +1282,21 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
/// <summary> /// <summary>
/// Multiplies this matrix with another matrix and returns the result. /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>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<double> Multiply(Matrix<double> other)
{
var matrix = other as SparseMatrix;
if (matrix == null)
{
return base.Multiply(other);
}
if (ColumnCount != matrix.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
var result = (SparseMatrix)CreateMatrix(RowCount, matrix.ColumnCount);
Multiply(matrix, result);
return result;
}
/// <summary>
/// Multiplies this dense matrix with transpose of another dense matrix and places the results into the result dense matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoTransposeAndMultiply(Matrix<double> other, Matrix<double> result)
/// <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<double> other, Matrix<double> result)
{ {
var otherSparse = other as SparseMatrix; var otherSparse = other as SparseMatrix;
var resultSparse = result as SparseMatrix; var resultSparse = result as SparseMatrix;
if (otherSparse == null || resultSparse == null) if (otherSparse == null || resultSparse == null)
{ {
base.TransposeAndMultiply(other, result); base.DoTransposeAndMultiply(other, result);
return; return;
} }
if (ColumnCount != otherSparse.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
if ((resultSparse.RowCount != RowCount) || (resultSparse.ColumnCount != otherSparse.RowCount))
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
resultSparse.Clear(); resultSparse.Clear();
for (var j = 0; j < RowCount; j++) for (var j = 0; j < RowCount; j++)
{ {
@ -1343,58 +1333,15 @@ namespace MathNet.Numerics.LinearAlgebra.Double
} }
} }
} }
/// <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<double> TransposeAndMultiply(Matrix<double> other)
{
var otherSparse = other as SparseMatrix;
if (otherSparse == null)
{
return base.TransposeAndMultiply(other);
}
if (ColumnCount != otherSparse.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
var result = (SparseMatrix)CreateMatrix(RowCount, other.RowCount);
TransposeAndMultiply(other, result);
return result;
}
/// <summary> /// <summary>
/// Multiplies two sparse matrices. /// Negate each element of this matrix and place the results into the result matrix.
/// </summary> /// </summary>
/// <param name="leftSide">The left matrix to multiply.</param> /// <param name="result">The result of the negation.</param>
/// <param name="rightSide">The right matrix to multiply.</param> protected override void DoNegate(Matrix<double> result)
/// <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 SparseMatrix operator *(SparseMatrix leftSide, SparseMatrix rightSide)
{ {
if (leftSide == null) CopyTo(result);
{ DoMultiply(-1, result);
throw new ArgumentNullException("leftSide");
}
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide.ColumnCount != rightSide.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
return (SparseMatrix)leftSide.Multiply(rightSide);
} }
/// <summary> /// <summary>
@ -1402,307 +1349,95 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// </summary> /// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param> /// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param> /// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoPointwiseMultiply(Matrix<double> other, Matrix<double> result)
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public override void PointwiseMultiply(Matrix<double> other, Matrix<double> result)
{ {
if (other == null)
{
throw new ArgumentNullException("other");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
result.Clear(); result.Clear();
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++) var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{
for (var i = 0; i < other.RowCount; i++)
{ {
var resVal = _nonZeroValues[j] * other[i, _columnIndices[j]]; // Get the begin / end index for the current row
if (resVal != 0.0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
result[i, _columnIndices[j]] = resVal; var resVal = _nonZeroValues[j] * other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
result.At(i, _columnIndices[j], resVal);
}
} }
} }
} }
} else
/// <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<double> 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 = (SparseMatrix)CreateMatrix(numberOfRows, numberOfColumns);
for (var i = 0; i < matrix.RowCount; i++)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var i = 0; i < other.RowCount; i++)
{ {
var value = distribution.Sample(); // Get the begin / end index for the current row
if (value != 0.0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
matrix.SetValueAt(i, j, value); var resVal = _nonZeroValues[j] * other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
} }
return matrix;
} }
/// <summary> /// <summary>
/// Generates matrix with random elements. /// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <param name="numberOfRows">Number of rows.</param> /// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="numberOfColumns">Number of columns.</param> /// <param name="result">The matrix to store the result of the pointwise division.</param>
/// <param name="distribution">Continuous Random Distribution or Source</param> protected override void DoPointwiseDivide(Matrix<double> other, Matrix<double> result)
/// <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<double> Random(int numberOfRows, int numberOfColumns, IDiscreteDistribution distribution)
{ {
if (numberOfRows < 1) result.Clear();
{
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows");
}
if (numberOfColumns < 1)
{
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns");
}
var matrix = (SparseMatrix)CreateMatrix(numberOfRows, numberOfColumns); var sparseResult = result as SparseMatrix;
for (var i = 0; i < matrix.RowCount; i++) if (sparseResult == null)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var i = 0; i < other.RowCount; i++)
{ {
var value = distribution.Sample(); // Get the begin / end index for the current row
if (value != 0.0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
matrix.SetValueAt(i, j, value); var resVal = _nonZeroValues[j] / other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
result.At(i, _columnIndices[j], resVal);
}
} }
} }
} }
else
return matrix;
}
#endregion
#region Static constructors for special matrices.
/// <summary>
/// Initializes a square <see cref="SparseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary>
/// <param name="order">the size of the square matrix.</param>
/// <returns>Identity <c>SparseMatrix</c></returns>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public static SparseMatrix Identity(int order)
{
var m = new SparseMatrix(order)
{
NonZerosCount = order,
_nonZeroValues = new double[order],
_columnIndices = new int[order]
};
for (var i = 0; i < order; i++)
{
m._nonZeroValues[i] = 1.0;
m._columnIndices[i] = i;
m._rowIndex[i] = i;
}
return m;
}
#endregion
/// <summary>
/// Negates each element of this matrix.
/// </summary>
public override void Negate()
{
Multiply(-1);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">
/// An object to compare with this object.
/// </param>
/// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="other"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(Matrix<double> other)
{
if (other == null)
{
return false;
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
return false;
}
// Accept if the argument is the same object as this.
if (ReferenceEquals(this, other))
{
return true;
}
var sparseMatrix = other as SparseMatrix;
if (sparseMatrix == null)
{
return base.Equals(other);
}
if (NonZerosCount != sparseMatrix.NonZerosCount)
{
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < NonZerosCount; index++)
{ {
if (!_nonZeroValues[index].AlmostEqual(sparseMatrix._nonZeroValues[index]) || _columnIndices[index] != sparseMatrix._columnIndices[index]) for (var i = 0; i < other.RowCount; i++)
{ {
return false; // Get the begin / end index for the current row
} var startIndex = _rowIndex[i];
} var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
return true;
}
/// <summary> for (var j = startIndex; j < endIndex; j++)
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <param name="format">
/// The format to use.
/// </param>
/// <param name="formatProvider">
/// The format provider to use.
/// </param>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString(string format, IFormatProvider formatProvider)
{
var stringBuilder = new StringBuilder();
for (var row = 0; row < RowCount; row++)
{
for (var column = 0; column < ColumnCount; column++)
{
stringBuilder.Append(At(row, column).ToString(format, formatProvider));
if (column != ColumnCount - 1)
{ {
stringBuilder.Append(formatProvider.GetTextInfo().ListSeparator); var resVal = _nonZeroValues[j] / other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
if (row != RowCount - 1)
{
stringBuilder.Append(Environment.NewLine);
}
} }
return stringBuilder.ToString();
}
#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 double AddT(double val1, double 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 double SubtractT(double val1, double 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 double MultiplyT(double val1, double 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 double DivideT(double val1, double 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(double val1)
{
return Math.Abs(val1);
} }
#endregion
} }
} }

6
src/Numerics/LinearAlgebra/Double/Vector.cs

@ -65,7 +65,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] + scalar); index => result[index] = this[index] + scalar);
} }
/// <summary> /// <summary>
@ -131,7 +131,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] * scalar); index => result[index] = this[index] * scalar);
} }
/// <summary> /// <summary>
@ -148,7 +148,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] / scalar); index => result[index] = this[index] / scalar);
} }
/// <summary> /// <summary>

159
src/Numerics/LinearAlgebra/Generic/Matrix.Arithmetic.cs

@ -207,10 +207,90 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
{ {
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension, "result"); throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension, "result");
} }
if (scalar.Equals(One))
{
CopyTo(result);
return;
}
if (scalar.Equals(Zero))
{
result.Clear();
return;
}
CopyTo(result);
DoMultiply(scalar, result); DoMultiply(scalar, result);
} }
/// <summary>
/// Divides each element of this matrix with a scalar.
/// </summary>
/// <param name="scalar">The scalar to divide with.</param>
/// <returns>The result of the division.</returns>
public virtual Matrix<T> Divide(T scalar)
{
if (scalar.Equals(One))
{
return Clone();
}
if (scalar.Equals(0.0))
{
throw new DivideByZeroException();
}
var result = CreateMatrix(RowCount, ColumnCount);
Divide(scalar, result);
return result;
}
/// <summary>
/// Divides each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to divide the matrix with.</param>
/// <param name="result">The matrix to store the result of the division.</param>
/// <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 virtual void Divide(T scalar, Matrix<T> result)
{
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.RowCount != RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "result");
}
if (result.ColumnCount != ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension, "result");
}
if (scalar.Equals(One))
{
CopyTo(result);
return;
}
if (scalar.Equals(0.0))
{
throw new DivideByZeroException();
}
DoDivide(scalar, result);
}
/// <summary>
/// Divides each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to divide the matrix with.</param>
/// <param name="result">The matrix to store the result of the division.</param>
protected abstract void DoDivide(T scalar, Matrix<T> result);
/// <summary> /// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
@ -560,9 +640,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
} }
var ret = leftSide.Clone(); return leftSide.Add(rightSide);
ret.Add(rightSide);
return ret;
} }
/// <summary> /// <summary>
@ -609,9 +687,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
} }
var ret = leftSide.Clone(); return leftSide.Subtract(rightSide);
ret.Subtract(rightSide);
return ret;
} }
/// <summary> /// <summary>
@ -627,9 +703,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
throw new ArgumentNullException("rightSide"); throw new ArgumentNullException("rightSide");
} }
var ret = rightSide.Clone(); return rightSide.Negate();
ret.Negate();
return ret;
} }
/// <summary> /// <summary>
@ -646,9 +720,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
throw new ArgumentNullException("leftSide"); throw new ArgumentNullException("leftSide");
} }
var ret = leftSide.Clone(); return leftSide.Multiply(rightSide);
ret.Multiply(rightSide);
return ret;
} }
/// <summary> /// <summary>
@ -665,9 +737,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
throw new ArgumentNullException("rightSide"); throw new ArgumentNullException("rightSide");
} }
var ret = rightSide.Clone(); return rightSide.Multiply(leftSide);
ret.Multiply(leftSide);
return ret;
} }
/// <summary> /// <summary>
@ -866,20 +936,42 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
protected abstract void DoPointwiseDivide(Matrix<T> other, Matrix<T> result); protected abstract void DoPointwiseDivide(Matrix<T> other, Matrix<T> result);
/// <summary> /// <summary>
/// Generates matrix with random elements. /// Generates a matrix with random elements.
/// </summary> /// </summary>
/// <param name="numberOfRows">Number of rows.</param> /// <param name="numberOfRows">Number of rows.</param>
/// <param name="numberOfColumns">Number of columns.</param> /// <param name="numberOfColumns">Number of columns.</param>
/// <param name="distribution">Continuous Random Distribution or Source</param> /// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
/// <returns> /// <returns>
/// An <c>numberOfRows</c>-by-<c>numberOfColumns</c> matrix with elements distributed according to the provided distribution. /// An <c>numberOfRows</c>-by-<c>numberOfColumns</c> matrix with elements distributed according to the provided distribution.
/// </returns> /// </returns>
/// <exception cref="ArgumentException">If the parameter <paramref name="numberOfRows"/> is not positive.</exception> /// <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> /// <exception cref="ArgumentException">If the parameter <paramref name="numberOfColumns"/> is not positive.</exception>
public abstract Matrix<T> Random(int numberOfRows, int numberOfColumns, IContinuousDistribution distribution); public virtual Matrix<T> 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);
DoRandom(matrix, distribution);
return matrix;
}
/// <summary> /// <summary>
/// Generates matrix with random elements. /// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected abstract void DoRandom(Matrix<T> matrix, IContinuousDistribution distribution);
/// <summary>
/// Generates a matrix with random elements.
/// </summary> /// </summary>
/// <param name="numberOfRows">Number of rows.</param> /// <param name="numberOfRows">Number of rows.</param>
/// <param name="numberOfColumns">Number of columns.</param> /// <param name="numberOfColumns">Number of columns.</param>
@ -889,7 +981,29 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
/// </returns> /// </returns>
/// <exception cref="ArgumentException">If the parameter <paramref name="numberOfRows"/> is not positive.</exception> /// <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> /// <exception cref="ArgumentException">If the parameter <paramref name="numberOfColumns"/> is not positive.</exception>
public abstract Matrix<T> Random(int numberOfRows, int numberOfColumns, IDiscreteDistribution distribution); public virtual Matrix<T> 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);
DoRandom(matrix, distribution);
return matrix;
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected abstract void DoRandom(Matrix<T> matrix, IDiscreteDistribution distribution);
/// <summary> /// <summary>
/// Computes the trace of this matrix. /// Computes the trace of this matrix.
@ -910,9 +1024,10 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
/// <summary>Calculates the condition number of this matrix.</summary> /// <summary>Calculates the condition number of this matrix.</summary>
/// <returns>The condition number of the matrix.</returns> /// <returns>The condition number of the matrix.</returns>
/// <remarks>The condition number is calculated using singular value decomposition.</remarks> /// <remarks>The condition number is calculated using singular value decomposition.</remarks>
public virtual double ConditionNumber() public virtual T ConditionNumber()
{ {
return Svd<T>.Create(this, false).ConditionNumber; throw new NotImplementedException();
//return Svd<T>.Create(this, false).ConditionNumber;
} }
/// <summary>Computes the determinant of this matrix.</summary> /// <summary>Computes the determinant of this matrix.</summary>

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

@ -27,7 +27,6 @@
namespace MathNet.Numerics.LinearAlgebra.Single namespace MathNet.Numerics.LinearAlgebra.Single
{ {
using System; using System;
using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Threading; using Threading;
@ -35,7 +34,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <summary> /// <summary>
/// A Matrix class with dense storage. The underlying storage is a one dimensional array in column-major order. /// A Matrix class with dense storage. The underlying storage is a one dimensional array in column-major order.
/// </summary> /// </summary>
public class DenseMatrix : Matrix<float> public class DenseMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DenseMatrix"/> class. This matrix is square with a given size. /// Initializes a new instance of the <see cref="DenseMatrix"/> class. This matrix is square with a given size.
@ -220,12 +219,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <summary>Calculates the L1 norm.</summary> /// <summary>Calculates the L1 norm.</summary>
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override double L1Norm() public override float L1Norm()
{ {
var norm = 0.0; var norm = 0.0f;
for (var j = 0; j < ColumnCount; j++) for (var j = 0; j < ColumnCount; j++)
{ {
var s = 0.0; var s = 0.0f;
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
{ {
s += Math.Abs(Data[(j * RowCount) + i]); s += Math.Abs(Data[(j * RowCount) + i]);
@ -239,29 +238,29 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override float FrobeniusNorm()
{ {
var transpose = (DenseMatrix)Transpose(); var transpose = (DenseMatrix)Transpose();
var aat = this * transpose; var aat = (DenseMatrix)(this * transpose);
var norm = 0.0; var norm = 0.0f;
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
{ {
norm += Math.Abs(aat.Data[(i * RowCount) + i]); norm += Math.Abs(aat.Data[(i * RowCount) + i]);
} }
norm = Math.Sqrt(norm); norm = Convert.ToSingle(Math.Sqrt(norm));
return norm; return norm;
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override float InfinityNorm()
{ {
var norm = 0.0; var norm = 0.0f;
for (var i = 0; i < RowCount; i++) for (var i = 0; i < RowCount; i++)
{ {
var s = 0.0; var s = 0.0f;
for (var j = 0; j < ColumnCount; j++) for (var j = 0; j < ColumnCount; j++)
{ {
s += Math.Abs(Data[(j * RowCount) + i]); s += Math.Abs(Data[(j * RowCount) + i]);
@ -276,435 +275,293 @@ namespace MathNet.Numerics.LinearAlgebra.Single
#region Elementary operations #region Elementary operations
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of add</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override void Add(Matrix<float> other) protected override void DoAdd(Matrix<float> other, Matrix<float> result)
{ {
var m = other as DenseMatrix; var denseOther = other as DenseMatrix;
if (m == null) var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
base.Add(other); base.DoAdd(other, result);
} }
else else
{ {
Add(m); Control.LinearAlgebraProvider.AddArrays(Data, denseOther.Data, denseResult.Data);
} }
} }
/// <summary> /// <summary>
/// Adds another <see cref="DenseMatrix"/> to this matrix. The result will be written into this matrix. /// Subtracts another matrix from 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> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the subtraction.</param>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> protected override void DoSubtract(Matrix<float> other, Matrix<float> result)
public override void Subtract(Matrix<float> other)
{ {
var m = other as DenseMatrix; var denseOther = other as DenseMatrix;
if (m == null) var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
base.Subtract(other); base.DoSubtract(other, result);
} }
else else
{ {
Subtract(m); Control.LinearAlgebraProvider.SubtractArrays(Data, denseOther.Data, denseResult.Data);
} }
} }
#endregion
#region Static constructors for special matrices.
/// <summary> /// <summary>
/// Subtracts another <see cref="DenseMatrix"/> from this matrix. The result will be written into this matrix. /// Initializes a square <see cref="DenseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DenseMatrix"/> to subtract.</param> /// <param name="order">the size of the square matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>A dense identity matrix.</returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// <exception cref="ArgumentException">
public void Subtract(DenseMatrix other) /// If <paramref name="order"/> is less than one.
/// </exception>
public static DenseMatrix Identity(int order)
{ {
if (other == null) var m = new DenseMatrix(order);
{ for (var i = 0; i < order; i++)
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); m.Data[(i * order) + i] = 1.0f;
} }
Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); return m;
} }
#endregion
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a scalar. /// Returns the conjugate transpose of this matrix.
/// </summary> /// </summary>
/// <param name="scalar">The scalar to multiply with.</param> /// <returns>The conjugate transpose of this matrix.</returns>
public override void Multiply(float scalar) public override Matrix<float> ConjugateTranspose()
{ {
Control.LinearAlgebraProvider.ScaleArray(scalar, Data); return Transpose();
} }
/// <summary> /// <summary>
/// Multiplies this dense matrix with another dense matrix and places the results into the result dense matrix. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The matrix to store the result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(float scalar, Matrix<float> result)
/// <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<float> other, Matrix<float> result)
{ {
if (other == null) var denseResult = result as DenseMatrix;
{ if (denseResult == null)
throw new ArgumentNullException("other");
}
if (result == null)
{ {
throw new ArgumentNullException("result"); base.DoMultiply(scalar, result);
} }
else
if (ColumnCount != other.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
if (result.RowCount != RowCount || result.ColumnCount != other.ColumnCount)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); Control.LinearAlgebraProvider.ScaleArray(scalar, denseResult.Data);
} }
}
var m = other as DenseMatrix; /// <summary>
var r = result as DenseMatrix; /// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<float> rightSide, Vector<float> result)
{
var denseRight = rightSide as DenseVector;
var denseResult = result as DenseVector;
if (m == null || r == null) if (denseRight == null || denseResult == null)
{ {
base.Multiply(other, result); base.DoMultiply(rightSide, result);
} }
else else
{ {
Control.LinearAlgebraProvider.MatrixMultiply( Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Data, Algorithms.LinearAlgebra.Transpose.DontTranspose,
RowCount, Algorithms.LinearAlgebra.Transpose.DontTranspose,
ColumnCount, 1.0f,
m.Data, Data,
m.RowCount, RowCount,
m.ColumnCount, ColumnCount,
r.Data); denseRight.Data,
denseRight.Count,
1,
0.0f,
denseResult.Data);
} }
} }
/// <summary> /// <summary>
/// Multiplies this matrix with another matrix and returns the result. /// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="leftSide">The vector to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoLeftMultiply(Vector<float> leftSide, Vector<float> result)
/// <returns>The result of multiplication.</returns>
public override Matrix<float> Multiply(Matrix<float> other)
{ {
if (other == null) var denseLeft = leftSide as DenseVector;
{ var denseResult = result as DenseVector;
throw new ArgumentNullException("other");
}
if (ColumnCount != other.RowCount) if (denseLeft == null || denseResult == null)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); base.DoLeftMultiply(leftSide, result);
} }
else
var m = other as DenseMatrix;
if (m == null)
{ {
return base.Multiply(other); Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.DontTranspose,
1.0f,
denseLeft.Data,
1,
denseResult.Count,
Data,
RowCount,
ColumnCount,
0.0f,
denseResult.Data);
} }
var result = (DenseMatrix)CreateMatrix(RowCount, other.ColumnCount);
Multiply(other, result);
return result;
} }
/// <summary> /// <summary>
/// Multiplies this dense matrix with transpose of another dense matrix and places the results into the result dense matrix. /// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(Matrix<float> other, Matrix<float> result)
/// <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<float> other, Matrix<float> result)
{ {
var otherDense = other as DenseMatrix; var denseOther = other as DenseMatrix;
var resultDense = result as DenseMatrix; var denseResult = result as DenseMatrix;
if (otherDense == null || resultDense == null) if (denseOther == null || denseResult == null)
{ {
base.TransposeAndMultiply(other, result); base.DoMultiply(other, result);
return;
} }
else
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.DontTranspose,
1.0f,
Data,
RowCount,
ColumnCount,
denseOther.Data,
denseOther.RowCount,
denseOther.ColumnCount,
0.0f,
denseResult.Data);
} }
Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose,
1.0f,
Data,
RowCount,
ColumnCount,
otherDense.Data,
otherDense.RowCount,
otherDense.ColumnCount,
1.0f,
resultDense.Data);
} }
/// <summary> /// <summary>
/// Multiplies this matrix with transpose of another matrix and returns the result. /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoTransposeAndMultiply(Matrix<float> other, Matrix<float> result)
/// <returns>The result of multiplication.</returns>
public override Matrix<float> TransposeAndMultiply(Matrix<float> other)
{ {
var otherDense = other as DenseMatrix; var denseOther = other as DenseMatrix;
if (otherDense == null) var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
return base.TransposeAndMultiply(other); base.DoTransposeAndMultiply(other, result);
} }
else
if (ColumnCount != otherDense.ColumnCount)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate(
Algorithms.LinearAlgebra.Transpose.DontTranspose,
Algorithms.LinearAlgebra.Transpose.Transpose,
1.0f,
Data,
RowCount,
ColumnCount,
denseOther.Data,
denseOther.RowCount,
denseOther.ColumnCount,
0.0f,
denseResult.Data);
} }
var result = (DenseMatrix)CreateMatrix(RowCount, other.RowCount);
TransposeAndMultiply(other, result);
return result;
} }
/// <summary> /// <summary>
/// Multiplies two dense matrices. /// Negate each element of this matrix and place the results into the result matrix.
/// </summary> /// </summary>
/// <param name="leftSide">The left matrix to multiply.</param> /// <param name="result">The result of the negation.</param>
/// <param name="rightSide">The right matrix to multiply.</param> protected override void DoNegate(Matrix<float> result)
/// <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) var denseResult = result as DenseMatrix;
{
throw new ArgumentNullException("leftSide");
}
if (rightSide == null) if (denseResult == null)
{ {
throw new ArgumentNullException("rightSide"); base.DoNegate(result);
} }
else
if (leftSide.ColumnCount != rightSide.RowCount)
{ {
throw new ArgumentException(Resources.ArgumentMatrixDimensions); Buffer.BlockCopy(Data, 0, denseResult.Data, 0, Data.Length * Constants.SizeOfFloat);
Control.LinearAlgebraProvider.ScaleArray(-1, denseResult.Data);
} }
return (DenseMatrix)leftSide.Multiply(rightSide);
} }
#endregion
#region Static constructors for special matrices.
/// <summary> /// <summary>
/// Initializes a square <see cref="DenseMatrix"/> with all zero's except for ones on the diagonal. /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <param name="order">the size of the square matrix.</param> /// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <returns>A dense identity matrix.</returns> /// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
/// <exception cref="ArgumentException"> protected override void DoPointwiseMultiply(Matrix<float> other, Matrix<float> result)
/// 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] = 1.0f;
}
return m;
}
#endregion
/// <summary>
/// Negates each element of this matrix.
/// </summary>
public override void Negate()
{ {
Multiply(-1); var denseOther = other as DenseMatrix;
} var denseResult = result as DenseMatrix;
/// <summary> if (denseOther == null || denseResult == null)
/// 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<float> Random(int numberOfRows, int numberOfColumns, IContinuousDistribution distribution)
{
if (numberOfRows < 1)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows"); base.DoPointwiseMultiply(other, result);
} }
else
if (numberOfColumns < 1)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, denseOther.Data, denseResult.Data);
} }
var matrix = CreateMatrix(numberOfRows, numberOfColumns);
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < matrix.RowCount; i++)
{
matrix[i, j] = (float)distribution.Sample();
}
});
return matrix;
} }
/// <summary> /// <summary>
/// Generates matrix with random elements. /// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <param name="numberOfRows">Number of rows.</param> /// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="numberOfColumns">Number of columns.</param> /// <param name="result">The matrix to store the result of the pointwise division.</param>
/// <param name="distribution">Continuous Random Distribution or Source</param> protected override void DoPointwiseDivide(Matrix<float> other, Matrix<float> result)
/// <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<float> Random(int numberOfRows, int numberOfColumns, IDiscreteDistribution distribution)
{ {
if (numberOfRows < 1) var denseOther = other as DenseMatrix;
var denseResult = result as DenseMatrix;
if (denseOther == null || denseResult == null)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows"); base.DoPointwiseDivide(other, result);
} }
else
if (numberOfColumns < 1)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); Control.LinearAlgebraProvider.PointWiseDivideArrays(Data, denseOther.Data, denseResult.Data);
} }
var matrix = CreateMatrix(numberOfRows, numberOfColumns);
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < matrix.RowCount; i++)
{
matrix[i, j] = 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 float AddT(float val1, float val2)
{
return val1 + val2;
} }
/// <summary> /// <summary>
/// Subtract two values T-T /// Computes the trace of this matrix.
/// </summary> /// </summary>
/// <param name="val1">Left operand value</param> /// <returns>The trace of this matrix</returns>
/// <param name="val2">Right operand value</param> /// <exception cref="ArgumentException">If the matrix is not square</exception>
/// <returns>Result of subtract</returns> public override float Trace()
protected sealed override float SubtractT(float val1, float val2)
{ {
return val1 - val2; if (RowCount != ColumnCount)
} {
throw new ArgumentException(Resources.ArgumentMatrixSquare);
/// <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 float MultiplyT(float val1, float 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 float DivideT(float val1, float val2)
{
return val1 / val2;
}
/// <summary> return CommonParallel.Aggregate(0, RowCount, i => Data[(i * RowCount) + i]);
/// Take absolute value
/// </summary>
/// <param name="val1">Source alue</param>
/// <returns>True if one; otherwise false</returns>
protected sealed override double AbsoluteT(float val1)
{
return Math.Abs(val1);
} }
#endregion
} }
} }

408
src/Numerics/LinearAlgebra/Single/DiagonalMatrix.cs

@ -28,8 +28,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
using System; using System;
using System.Linq; using System.Linq;
using System.Text;
using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Threading; using Threading;
@ -43,7 +41,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// entries are set. The exception to this is when the off diagonal elements are /// entries are set. The exception to this is when the off diagonal elements are
/// 0.0 or NaN; these settings will cause no change to the diagonal matrix. /// 0.0 or NaN; these settings will cause no change to the diagonal matrix.
/// </remarks> /// </remarks>
public class DiagonalMatrix : Matrix<float> public class DiagonalMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DiagonalMatrix"/> class. This matrix is square with a given size. /// Initializes a new instance of the <see cref="DiagonalMatrix"/> class. This matrix is square with a given size.
@ -122,7 +120,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
Data[i] = array[i, j]; Data[i] = array[i, j];
} }
else if (array[i, j] != 0.0f && !float.IsNaN(array[i, j])) else if (array[i, j] != 0.0 && !float.IsNaN(array[i, j]))
{ {
throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix."); throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix.");
} }
@ -180,7 +178,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
Data[row] = value; Data[row] = value;
} }
else if (value != 0.0f && !float.IsNaN(value)) else if (value != 0.0 && !float.IsNaN(value))
{ {
throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix."); throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix.");
} }
@ -279,92 +277,155 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
#region Elementary operations #region Elementary operations
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>The result of the addition.</returns>
/// <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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
/// <exception cref="ArgumentException">If <paramref name="other"/> is not <see cref="DiagonalMatrix"/>.</exception> public override Matrix<float> Add(Matrix<float> other)
public override void Add(Matrix<float> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
var m = other as DiagonalMatrix; if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
if (m == null)
{ {
throw new ArgumentException(Resources.ArgumentTypeMismatch); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
} }
Add(m); Matrix<float> result;
if (other is DiagonalMatrix)
{
result = new DenseMatrix(RowCount, ColumnCount);
}
else
{
result = new DiagonalMatrix(RowCount, ColumnCount);
}
Add(other, result);
return result;
} }
/// <summary> /// <summary>
/// Adds another <see cref="DiagonalMatrix"/> to this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DiagonalMatrix"/> to add to this matrix.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the addition.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Add(DiagonalMatrix other) public override void Add(Matrix<float> other, Matrix<float> result)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
if (result == null)
{
throw new ArgumentNullException("result");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
} }
Control.LinearAlgebraProvider.AddArrays(Data, other.Data, Data); if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException("result", Resources.ArgumentMatrixDimensions);
}
var diagOther = other as DiagonalMatrix;
var diagResult = result as DiagonalMatrix;
if (diagOther == null || diagResult == null)
{
base.Add(other, result);
}
else
{
Control.LinearAlgebraProvider.AddArrays(Data, diagOther.Data, diagResult.Data);
}
} }
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>The result of the subtraction.</returns>
/// <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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
/// <exception cref="ArgumentException">If <paramref name="other"/> is not <see cref="DiagonalMatrix"/>.</exception> public override Matrix<float> Subtract(Matrix<float> other)
public override void Subtract(Matrix<float> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
var m = other as DiagonalMatrix; if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
if (m == null) {
throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
Matrix<float> result;
if (other is DiagonalMatrix)
{
result = new DenseMatrix(RowCount, ColumnCount);
}
else
{ {
throw new ArgumentException(Resources.ArgumentTypeMismatch); result = new DiagonalMatrix(RowCount, ColumnCount);
} }
Subtract(m); Subtract(other, result);
return result;
} }
/// <summary> /// <summary>
/// Subtracts another <see cref="DiagonalMatrix"/> from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="DiagonalMatrix"/> to subtract.</param> /// <param name="other">The matrix to subtract.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the subtraction.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(DiagonalMatrix other) public override void Subtract(Matrix<float> other, Matrix<float> result)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); throw new ArgumentNullException("other");
} }
if (result == null)
{
throw new ArgumentNullException("result");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); throw new ArgumentOutOfRangeException("other", Resources.ArgumentMatrixDimensions);
}
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException("result", Resources.ArgumentMatrixDimensions);
} }
Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); var diagOther = other as DiagonalMatrix;
var diagResult = result as DiagonalMatrix;
if (diagOther == null || diagResult == null)
{
base.Subtract(other, result);
}
else
{
Control.LinearAlgebraProvider.SubtractArrays(Data, diagOther.Data, diagResult.Data);
}
} }
/// <summary> /// <summary>
@ -420,23 +481,41 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a scalar. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="scalar">The scalar to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(float scalar) /// <param name="result">The matrix to store the result of the multiplication.</param>
/// <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 Multiply(float scalar, Matrix<float> result)
{ {
if (result == null)
{
throw new ArgumentNullException("result");
}
if (scalar == 0.0) if (scalar == 0.0)
{ {
Clear(); result.Clear();
return; return;
} }
if (scalar == 1.0) if (scalar == 1.0)
{ {
CopyTo(result);
return; return;
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, Data); var diagResult = result as DiagonalMatrix;
if (diagResult == null)
{
base.Multiply(scalar, result);
}
else
{
CopyTo(diagResult);
Control.LinearAlgebraProvider.ScaleArray(scalar, diagResult.Data);
}
} }
/// <summary> /// <summary>
@ -693,34 +772,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single
return result; return result;
} }
/// <summary>
/// Multiplies two diagonal 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 DiagonalMatrix operator *(DiagonalMatrix leftSide, DiagonalMatrix 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 (DiagonalMatrix)leftSide.Multiply(rightSide);
}
#endregion #endregion
/// <summary> /// <summary>
@ -883,36 +934,36 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <summary>Calculates the L1 norm.</summary> /// <summary>Calculates the L1 norm.</summary>
/// <returns>The L1 norm of the matrix.</returns> /// <returns>The L1 norm of the matrix.</returns>
public override double L1Norm() public override float L1Norm()
{ {
return Data.Aggregate(float.NegativeInfinity, (current, t) => Math.Max(current, Math.Abs(t))); return Data.Aggregate(float.NegativeInfinity, (current, t) => Math.Max(current, Math.Abs(t)));
} }
/// <summary>Calculates the L2 norm.</summary> /// <summary>Calculates the L2 norm.</summary>
/// <returns>The L2 norm of the matrix.</returns> /// <returns>The L2 norm of the matrix.</returns>
public override double L2Norm() public override float L2Norm()
{ {
return Data.Aggregate(float.NegativeInfinity, (current, t) => Math.Max(current, Math.Abs(t))); return Data.Aggregate(float.NegativeInfinity, (current, t) => Math.Max(current, Math.Abs(t)));
} }
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override float FrobeniusNorm()
{ {
var norm = Data.Sum(t => t * t); var norm = Data.Sum(t => t * t);
return Math.Sqrt(norm); return Convert.ToSingle(Math.Sqrt(norm));
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override float InfinityNorm()
{ {
return L1Norm(); return L1Norm();
} }
/// <summary>Calculates the condition number of this matrix.</summary> /// <summary>Calculates the condition number of this matrix.</summary>
/// <returns>The condition number of the matrix.</returns> /// <returns>The condition number of the matrix.</returns>
public override double ConditionNumber() public override float ConditionNumber()
{ {
var maxSv = float.NegativeInfinity; var maxSv = float.NegativeInfinity;
var minSv = float.PositiveInfinity; var minSv = float.PositiveInfinity;
@ -1464,50 +1515,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single
CommonParallel.For(0, lower.RowCount, i => CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j)))); CommonParallel.For(0, lower.RowCount, i => CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j))));
} }
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise 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 this matrix and <paramref name="other"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public override void PointwiseMultiply(Matrix<float> other, Matrix<float> result)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
var m = other as DiagonalMatrix;
var r = result as DiagonalMatrix;
if (m == null || r == null)
{
base.PointwiseMultiply(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, m.Data, r.Data);
}
}
/// <summary> /// <summary>
/// Permute the columns of a matrix according to a permutation. /// Permute the columns of a matrix according to a permutation.
/// </summary> /// </summary>
@ -1529,6 +1536,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
{ {
throw new InvalidOperationException("Permutations in diagonal matrix are not allowed"); throw new InvalidOperationException("Permutations in diagonal matrix are not allowed");
} }
#region Static constructors for special matrices. #region Static constructors for special matrices.
/// <summary> /// <summary>
@ -1551,173 +1559,5 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
#endregion #endregion
/// <summary>
/// Negates each element of this matrix.
/// </summary>
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<float> 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);
var mn = Math.Min(numberOfRows, numberOfColumns);
CommonParallel.For(0, mn, i => matrix[i, i] = (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<float> 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] = distribution.Sample();
}
});
return matrix;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <param name="format">
/// The format to use.
/// </param>
/// <param name="formatProvider">
/// The format provider to use.
/// </param>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString(string format, IFormatProvider formatProvider)
{
var stringBuilder = new StringBuilder();
for (var row = 0; row < RowCount; row++)
{
for (var column = 0; column < ColumnCount; column++)
{
stringBuilder.Append(At(row, column).ToString(format, formatProvider));
if (column != ColumnCount - 1)
{
stringBuilder.Append(formatProvider.GetTextInfo().ListSeparator);
}
}
if (row != RowCount - 1)
{
stringBuilder.Append(Environment.NewLine);
}
}
return stringBuilder.ToString();
}
#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 float AddT(float val1, float 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 float SubtractT(float val1, float 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 float MultiplyT(float val1, float 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 float DivideT(float val1, float 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(float val1)
{
return Math.Abs(val1);
}
#endregion
} }
} }

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

@ -0,0 +1,403 @@
// <copyright file="Matrix.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.Single
{
using System;
using Distributions;
using Generic;
using Properties;
using Threading;
/// <summary>
/// <c>float</c> version of the <see cref="Matrix{T}"/> class.
/// </summary>
public abstract class Matrix : Matrix<float>
{
/// <summary>
/// Initializes a new instance of the Matrix class.
/// </summary>
/// <param name="rows">
/// The number of rows.
/// </param>
/// <param name="columns">
/// The number of columns.
/// </param>
protected Matrix(int rows, int columns) : base(rows, columns)
{
}
/// <summary>
/// Initializes a new instance of the Matrix class.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
protected Matrix(int order)
: base(order)
{
}
/// <summary>Calculates the L1 norm.</summary>
/// <returns>The L1 norm of the matrix.</returns>
public override float L1Norm()
{
var norm = 0.0f;
for (var j = 0; j < ColumnCount; j++)
{
var s = 0.0f;
for (var i = 0; i < RowCount; i++)
{
s += Math.Abs(At(i, j));
}
norm = Math.Max(norm, s);
}
return norm;
}
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<float> ConjugateTranspose()
{
return Transpose();
}
/// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns>
public override float FrobeniusNorm()
{
var transpose = Transpose();
var aat = this * transpose;
var norm = 0.0f;
for (var i = 0; i < RowCount; i++)
{
norm += Math.Abs(aat.At(i, i));
}
norm = Convert.ToSingle(Math.Sqrt(norm));
return norm;
}
/// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns>
public override float InfinityNorm()
{
var norm = 0.0f;
for (var i = 0; i < RowCount; i++)
{
var s = 0.0f;
for (var j = 0; j < ColumnCount; j++)
{
s += Math.Abs(At(i, j));
}
norm = Math.Max(norm, s);
}
return norm;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of the addition.</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>
protected override void DoAdd(Matrix<float> other, Matrix<float> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) + other.At(i, j));
}
});
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract to this matrix.</param>
/// <param name="result">The matrix to store the result of subtraction.</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>
protected override void DoSubtract(Matrix<float> other, Matrix<float> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) - other.At(i, j));
}
});
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(float scalar, Matrix<float> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j < ColumnCount; j++)
{
result.At(i, j, At(i, j) * scalar);
}
});
}
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<float> rightSide, Vector<float> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
var s = 0.0f;
for (var j = 0; j != ColumnCount; j++)
{
s += At(i, j) * rightSide[j];
}
result[i] = s;
});
}
/// <summary>
/// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector.
/// </summary>
/// <param name="leftSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoLeftMultiply(Vector<float> leftSide, Vector<float> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
var s = 0.0f;
for (var i = 0; i != leftSide.Count; i++)
{
s += leftSide[i] * At(i, j);
}
result[j] = s;
});
}
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Matrix<float> other, Matrix<float> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
for (var i = 0; i != other.ColumnCount; i++)
{
var s = 0.0f;
for (var l = 0; l < ColumnCount; l++)
{
s += At(j, l) * other.At(l, i);
}
result.At(j, i, s);
}
});
}
/// <summary>
/// Divides each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to divide the matrix with.</param>
/// <param name="result">The matrix to store the result of the division.</param>
protected override void DoDivide(float scalar, Matrix<float> result)
{
DoMultiply(1.0f / scalar, result);
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoTransposeAndMultiply(Matrix<float> other, Matrix<float> result)
{
CommonParallel.For(
0,
RowCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
var s = 0.0f;
for (var l = 0; l < ColumnCount; l++)
{
s += At(i, l) * other.At(j, l);
}
result.At(i, j, s);
}
});
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
protected override void DoNegate(Matrix<float> result)
{
CommonParallel.For(
0,
RowCount,
i =>
{
for (var j = 0; j != ColumnCount; j++)
{
result[i, j] = -At(i, j);
}
});
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
protected override void DoPointwiseMultiply(Matrix<float> other, Matrix<float> result)
{
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
result.At(i, j, At(i, j) * other.At(i, j));
}
});
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
protected override void DoPointwiseDivide(Matrix<float> other, Matrix<float> result)
{
CommonParallel.For(
0,
ColumnCount,
j =>
{
for (var i = 0; i < RowCount; i++)
{
result.At(i, j, At(i, j) / other.At(i, j));
}
});
}
/// <summary>
/// Computes the trace of this matrix.
/// </summary>
/// <returns>The trace of this matrix</returns>
/// <exception cref="ArgumentException">If the matrix is not square</exception>
public override float Trace()
{
if (RowCount != ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
return CommonParallel.Aggregate(0, RowCount, i => At(i, i));
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<float> matrix, IContinuousDistribution distribution)
{
CommonParallel.For(
0,
matrix.RowCount,
i =>
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
matrix.At(i, j, Convert.ToSingle(distribution.Sample()));
}
});
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">The matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<float> matrix, IDiscreteDistribution distribution)
{
CommonParallel.For(
0,
matrix.RowCount,
i =>
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
matrix.At(i, j, distribution.Sample());
}
});
}
}
}

701
src/Numerics/LinearAlgebra/Single/SparseMatrix.cs

@ -31,8 +31,6 @@
namespace MathNet.Numerics.LinearAlgebra.Single namespace MathNet.Numerics.LinearAlgebra.Single
{ {
using System; using System;
using System.Text;
using Distributions;
using Generic; using Generic;
using Properties; using Properties;
using Threading; using Threading;
@ -41,7 +39,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// A Matrix class with sparse storage. The underlying storage scheme is 3-array compressed-sparse-row (CSR) Format. /// A Matrix class with sparse storage. The underlying storage scheme is 3-array compressed-sparse-row (CSR) Format.
/// <a href="http://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR_or_CRS.29">Wikipedia - CSR</a>. /// <a href="http://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR_or_CRS.29">Wikipedia - CSR</a>.
/// </summary> /// </summary>
public class SparseMatrix : Matrix<float> public class SparseMatrix : Matrix
{ {
/// <summary> /// <summary>
/// Object for use in "lock" /// Object for use in "lock"
@ -855,12 +853,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// <summary>Calculates the Frobenius norm of this matrix.</summary> /// <summary>Calculates the Frobenius norm of this matrix.</summary>
/// <returns>The Frobenius norm of this matrix.</returns> /// <returns>The Frobenius norm of this matrix.</returns>
public override double FrobeniusNorm() public override float FrobeniusNorm()
{ {
var transpose = (SparseMatrix)Transpose(); var transpose = (SparseMatrix)Transpose();
var aat = this * transpose; var aat = (SparseMatrix)(this * transpose);
var norm = 0.0; var norm = 0.0f;
for (var i = 0; i < aat._rowIndex.Length; i++) for (var i = 0; i < aat._rowIndex.Length; i++)
{ {
@ -884,15 +882,15 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
} }
norm = Math.Sqrt(norm); norm = Convert.ToSingle(Math.Sqrt(norm));
return norm; return norm;
} }
/// <summary>Calculates the infinity norm of this matrix.</summary> /// <summary>Calculates the infinity norm of this matrix.</summary>
/// <returns>The infinity norm of this matrix.</returns> /// <returns>The infinity norm of this matrix.</returns>
public override double InfinityNorm() public override float InfinityNorm()
{ {
var norm = 0.0; var norm = 0.0f;
for (var i = 0; i < _rowIndex.Length; i++) for (var i = 0; i < _rowIndex.Length; i++)
{ {
// Get the begin / end index for the current row // Get the begin / end index for the current row
@ -906,7 +904,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
continue; continue;
} }
var s = 0.0; var s = 0.0f;
for (var j = startIndex; j < endIndex; j++) for (var j = startIndex; j < endIndex; j++)
{ {
s += Math.Abs(_nonZeroValues[j]); s += Math.Abs(_nonZeroValues[j]);
@ -1033,200 +1031,231 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
} }
#region Elementary operations #region Static constructors for special matrices.
/// <summary> /// <summary>
/// Adds another matrix to this matrix. The result will be written into this matrix. /// Initializes a square <see cref="SparseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary> /// </summary>
/// <param name="other">The matrix to add to this matrix.</param> /// <param name="order">the size of the square matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <returns>Identity <c>SparseMatrix</c></returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// <exception cref="ArgumentException">
public override void Add(Matrix<float> other) /// If <paramref name="order"/> is less than one.
/// </exception>
public static SparseMatrix Identity(int order)
{ {
if (ReferenceEquals(this, other)) var m = new SparseMatrix(order)
{ {
Multiply(2); NonZerosCount = order,
return; _nonZeroValues = new float[order],
} _columnIndices = new int[order]
};
var m = other as SparseMatrix; for (var i = 0; i < order; i++)
if (m == null)
{
base.Add(other);
}
else
{ {
Add(m); m._nonZeroValues[i] = 1.0f;
m._columnIndices[i] = i;
m._rowIndex[i] = i;
} }
return m;
} }
#endregion
/// <summary> /// <summary>
/// Adds another <see cref="SparseMatrix"/> to this matrix. The result will be written into this matrix. /// Indicates whether the current object is equal to another object of the same type.
/// </summary> /// </summary>
/// <param name="other">The <see cref="SparseMatrix"/> to add to this matrix.</param> /// <param name="other">
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// An object to compare with this object.
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception> /// </param>
public void Add(SparseMatrix other) /// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="other"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(Matrix<float> other)
{ {
if (other == null) if (other == null)
{ {
throw new ArgumentNullException("other"); return false;
} }
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{ {
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); return false;
}
// Accept if the argument is the same object as this.
if (ReferenceEquals(this, other))
{
return true;
} }
for (var i = 0; i < other.RowCount; i++) var sparseMatrix = other as SparseMatrix;
if (sparseMatrix == null)
{ {
// Get the begin / end index for the current row return base.Equals(other);
var startIndex = other._rowIndex[i]; }
var endIndex = i < other._rowIndex.Length - 1 ? other._rowIndex[i + 1] : other.NonZerosCount;
for (var j = startIndex; j < endIndex; j++) if (NonZerosCount != sparseMatrix.NonZerosCount)
{
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < NonZerosCount; index++)
{
if (!_nonZeroValues[index].AlmostEqual(sparseMatrix._nonZeroValues[index]) || _columnIndices[index] != sparseMatrix._columnIndices[index])
{ {
var index = FindItem(i, other._columnIndices[j]); return false;
if (index >= 0)
{
if (_nonZeroValues[index] + other._nonZeroValues[j] == 0.0)
{
DeleteItemByIndex(index, i);
}
else
{
_nonZeroValues[index] += other._nonZeroValues[j];
}
}
else
{
SetValueAt(i, other._columnIndices[j], other._nonZeroValues[j]);
}
} }
} }
return true;
} }
/// <summary> /// <summary>
/// Subtracts another matrix from this matrix. The result will be written into this matrix. /// Adds another matrix to this matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to subtract.</param> /// <param name="other">The matrix to add to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of the addition.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override void Subtract(Matrix<float> other) protected override void DoAdd(Matrix<float> other, Matrix<float> result)
{ {
// We are substracting Matrix form itself result.Clear();
if (ReferenceEquals(this, other))
{
Clear();
return;
}
var m = other as SparseMatrix; var sparseResult = result as SparseMatrix;
if (m == null) if (sparseResult == null)
{ {
base.Subtract(other); for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{
var resVal = _nonZeroValues[j] + other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{
result.At(i, _columnIndices[j], resVal);
}
}
}
} }
else else
{ {
Subtract(m); for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{
var resVal = _nonZeroValues[j] + other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
}
}
} }
} }
/// <summary> /// <summary>
/// Subtracts another <see cref="SparseMatrix"/> from this matrix. The result will be written into this matrix. /// Subtracts another matrix from this matrix.
/// </summary> /// </summary>
/// <param name="other">The <see cref="SparseMatrix"/> to subtract.</param> /// <param name="other">The matrix to subtract to this matrix.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> /// <param name="result">The matrix to store the result of subtraction.</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> /// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(SparseMatrix other) protected override void DoSubtract(Matrix<float> other, Matrix<float> result)
{ {
if (other == null) result.Clear();
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
for (var i = 0; i < other.RowCount; i++) var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{ {
// Get the begin / end index for the current row for (var i = 0; i < other.RowCount; i++)
var startIndex = other._rowIndex[i];
var endIndex = i < other._rowIndex.Length - 1 ? other._rowIndex[i + 1] : other.NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
var index = FindItem(i, other._columnIndices[j]); // Get the begin / end index for the current row
if (index >= 0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
if (_nonZeroValues[index] - other._nonZeroValues[j] == 0.0) var resVal = _nonZeroValues[j] - other.At(i, _columnIndices[j]);
{ if (resVal != 0.0f)
DeleteItemByIndex(index, i);
}
else
{ {
_nonZeroValues[index] -= other._nonZeroValues[j]; result.At(i, _columnIndices[j], resVal);
} }
} }
else }
}
else
{
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
SetValueAt(i, other._columnIndices[j], -other._nonZeroValues[j]); var resVal = _nonZeroValues[j] - other.At(i, _columnIndices[j]);
if (resVal != 0.0f)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
} }
} }
/// <summary> /// <summary>
/// Multiplies each element of this matrix with a scalar. /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary> /// </summary>
/// <param name="scalar">The scalar to multiply with.</param> /// <param name="scalar">The scalar to multiply the matrix with.</param>
public override void Multiply(float scalar) /// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(float scalar, Matrix<float> result)
{ {
if (1.0f.AlmostEqualInDecimalPlaces(scalar, 7)) if (scalar == 1.0)
{ {
CopyTo(result);
return; return;
} }
if (0.0f.AlmostEqualInDecimalPlaces(scalar, 7)) if (scalar == 0.0)
{ {
Clear(); result.Clear();
return; return;
} }
Control.LinearAlgebraProvider.ScaleArray(scalar, _nonZeroValues); var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._nonZeroValues);
}
} }
/// <summary> /// <summary>
/// Multiplies this sparse matrix with another sparse matrix and places the results into the result sparse matrix. /// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoMultiply(Matrix<float> other, Matrix<float> result)
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If <strong>Columns != other.Rows</strong>.</exception>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the Rows x other.Columns.</exception>
public override void Multiply(Matrix<float> other, Matrix<float> result)
{ {
var otherSparseMatrix = other as SparseMatrix; var otherSparseMatrix = other as SparseMatrix;
var resultSparseMatrix = result as SparseMatrix; var resultSparseMatrix = result as SparseMatrix;
if (otherSparseMatrix == null || resultSparseMatrix == null) if (otherSparseMatrix == null || resultSparseMatrix == null)
{ {
base.Multiply(other, result); base.DoMultiply(other, result);
return; return;
} }
if (ColumnCount != otherSparseMatrix.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
if (resultSparseMatrix.RowCount != RowCount || resultSparseMatrix.ColumnCount != otherSparseMatrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
resultSparseMatrix.Clear(); resultSparseMatrix.Clear();
var columnVector = new DenseVector(otherSparseMatrix.RowCount); var columnVector = new DenseVector(otherSparseMatrix.RowCount);
for (var row = 0; row < RowCount; row++) for (var row = 0; row < RowCount; row++)
@ -1253,60 +1282,21 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
/// <summary> /// <summary>
/// Multiplies this matrix with another matrix and returns the result. /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>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<float> Multiply(Matrix<float> other)
{
var matrix = other as SparseMatrix;
if (matrix == null)
{
return base.Multiply(other);
}
if (ColumnCount != matrix.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
var result = (SparseMatrix)CreateMatrix(RowCount, matrix.ColumnCount);
Multiply(matrix, result);
return result;
}
/// <summary>
/// Multiplies this dense matrix with transpose of another dense matrix and places the results into the result dense matrix.
/// </summary> /// </summary>
/// <param name="other">The matrix to multiply with.</param> /// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param> /// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoTransposeAndMultiply(Matrix<float> other, Matrix<float> result)
/// <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<float> other, Matrix<float> result)
{ {
var otherSparse = other as SparseMatrix; var otherSparse = other as SparseMatrix;
var resultSparse = result as SparseMatrix; var resultSparse = result as SparseMatrix;
if (otherSparse == null || resultSparse == null) if (otherSparse == null || resultSparse == null)
{ {
base.TransposeAndMultiply(other, result); base.DoTransposeAndMultiply(other, result);
return; return;
} }
if (ColumnCount != otherSparse.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
if ((resultSparse.RowCount != RowCount) || (resultSparse.ColumnCount != otherSparse.RowCount))
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
resultSparse.Clear(); resultSparse.Clear();
for (var j = 0; j < RowCount; j++) for (var j = 0; j < RowCount; j++)
{ {
@ -1343,58 +1333,15 @@ namespace MathNet.Numerics.LinearAlgebra.Single
} }
} }
} }
/// <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<float> TransposeAndMultiply(Matrix<float> other)
{
var otherSparse = other as SparseMatrix;
if (otherSparse == null)
{
return base.TransposeAndMultiply(other);
}
if (ColumnCount != otherSparse.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
var result = (SparseMatrix)CreateMatrix(RowCount, other.RowCount);
TransposeAndMultiply(other, result);
return result;
}
/// <summary> /// <summary>
/// Multiplies two sparse matrices. /// Negate each element of this matrix and place the results into the result matrix.
/// </summary> /// </summary>
/// <param name="leftSide">The left matrix to multiply.</param> /// <param name="result">The result of the negation.</param>
/// <param name="rightSide">The right matrix to multiply.</param> protected override void DoNegate(Matrix<float> result)
/// <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 SparseMatrix operator *(SparseMatrix leftSide, SparseMatrix rightSide)
{ {
if (leftSide == null) CopyTo(result);
{ DoMultiply(-1, result);
throw new ArgumentNullException("leftSide");
}
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide.ColumnCount != rightSide.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
return (SparseMatrix)leftSide.Multiply(rightSide);
} }
/// <summary> /// <summary>
@ -1402,307 +1349,95 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// </summary> /// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param> /// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param> /// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception> protected override void DoPointwiseMultiply(Matrix<float> other, Matrix<float> result)
/// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public override void PointwiseMultiply(Matrix<float> other, Matrix<float> result)
{ {
if (other == null)
{
throw new ArgumentNullException("other");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result");
}
result.Clear(); result.Clear();
for (var i = 0; i < other.RowCount; i++)
{
// Get the begin / end index for the current row
var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++) var sparseResult = result as SparseMatrix;
if (sparseResult == null)
{
for (var i = 0; i < other.RowCount; i++)
{ {
var resVal = _nonZeroValues[j] * other[i, _columnIndices[j]]; // Get the begin / end index for the current row
if (resVal != 0.0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
result[i, _columnIndices[j]] = resVal; var resVal = _nonZeroValues[j] * other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
result.At(i, _columnIndices[j], resVal);
}
} }
} }
} }
} else
/// <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<float> 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 = (SparseMatrix)CreateMatrix(numberOfRows, numberOfColumns);
for (var i = 0; i < matrix.RowCount; i++)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var i = 0; i < other.RowCount; i++)
{ {
var value = (float)distribution.Sample(); // Get the begin / end index for the current row
if (value != 0.0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
matrix.SetValueAt(i, j, value); var resVal = _nonZeroValues[j] * other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
} }
return matrix;
} }
/// <summary> /// <summary>
/// Generates matrix with random elements. /// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary> /// </summary>
/// <param name="numberOfRows">Number of rows.</param> /// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="numberOfColumns">Number of columns.</param> /// <param name="result">The matrix to store the result of the pointwise division.</param>
/// <param name="distribution">Continuous Random Distribution or Source</param> protected override void DoPointwiseDivide(Matrix<float> other, Matrix<float> result)
/// <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<float> Random(int numberOfRows, int numberOfColumns, IDiscreteDistribution distribution)
{ {
if (numberOfRows < 1) result.Clear();
{
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows");
}
if (numberOfColumns < 1)
{
throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns");
}
var matrix = (SparseMatrix)CreateMatrix(numberOfRows, numberOfColumns); var sparseResult = result as SparseMatrix;
for (var i = 0; i < matrix.RowCount; i++) if (sparseResult == null)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var i = 0; i < other.RowCount; i++)
{ {
var value = distribution.Sample(); // Get the begin / end index for the current row
if (value != 0.0) var startIndex = _rowIndex[i];
var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
for (var j = startIndex; j < endIndex; j++)
{ {
matrix.SetValueAt(i, j, value); var resVal = _nonZeroValues[j] / other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
result.At(i, _columnIndices[j], resVal);
}
} }
} }
} }
else
return matrix;
}
#endregion
#region Static constructors for special matrices.
/// <summary>
/// Initializes a square <see cref="SparseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary>
/// <param name="order">the size of the square matrix.</param>
/// <returns>Identity <c>SparseMatrix</c></returns>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public static SparseMatrix Identity(int order)
{
var m = new SparseMatrix(order)
{
NonZerosCount = order,
_nonZeroValues = new float[order],
_columnIndices = new int[order]
};
for (var i = 0; i < order; i++)
{
m._nonZeroValues[i] = 1.0f;
m._columnIndices[i] = i;
m._rowIndex[i] = i;
}
return m;
}
#endregion
/// <summary>
/// Negates each element of this matrix.
/// </summary>
public override void Negate()
{
Multiply(-1);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">
/// An object to compare with this object.
/// </param>
/// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="other"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(Matrix<float> other)
{
if (other == null)
{
return false;
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
return false;
}
// Accept if the argument is the same object as this.
if (ReferenceEquals(this, other))
{
return true;
}
var sparseMatrix = other as SparseMatrix;
if (sparseMatrix == null)
{
return base.Equals(other);
}
if (NonZerosCount != sparseMatrix.NonZerosCount)
{
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < NonZerosCount; index++)
{ {
if (!_nonZeroValues[index].AlmostEqual(sparseMatrix._nonZeroValues[index]) || _columnIndices[index] != sparseMatrix._columnIndices[index]) for (var i = 0; i < other.RowCount; i++)
{ {
return false; // Get the begin / end index for the current row
} var startIndex = _rowIndex[i];
} var endIndex = i < _rowIndex.Length - 1 ? _rowIndex[i + 1] : NonZerosCount;
return true;
}
/// <summary> for (var j = startIndex; j < endIndex; j++)
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <param name="format">
/// The format to use.
/// </param>
/// <param name="formatProvider">
/// The format provider to use.
/// </param>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString(string format, IFormatProvider formatProvider)
{
var stringBuilder = new StringBuilder();
for (var row = 0; row < RowCount; row++)
{
for (var column = 0; column < ColumnCount; column++)
{
stringBuilder.Append(At(row, column).ToString(format, formatProvider));
if (column != ColumnCount - 1)
{ {
stringBuilder.Append(formatProvider.GetTextInfo().ListSeparator); var resVal = _nonZeroValues[j] / other.At(i, _columnIndices[j]);
if (resVal != 0.0)
{
sparseResult.SetValueAt(i, _columnIndices[j], resVal);
}
} }
} }
if (row != RowCount - 1)
{
stringBuilder.Append(Environment.NewLine);
}
} }
return stringBuilder.ToString();
}
#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 float AddT(float val1, float 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 float SubtractT(float val1, float 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 float MultiplyT(float val1, float 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 float DivideT(float val1, float 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(float val1)
{
return Math.Abs(val1);
} }
#endregion
} }
} }

6
src/Numerics/LinearAlgebra/Single/Vector.cs

@ -66,7 +66,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] + scalar); index => result[index] = this[index] + scalar);
} }
/// <summary> /// <summary>
@ -132,7 +132,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] * scalar); index => result[index] = this[index] * scalar);
} }
/// <summary> /// <summary>
@ -149,7 +149,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
CommonParallel.For( CommonParallel.For(
0, 0,
Count, Count,
index => result[index] = result[index] / scalar); index => result[index] = this[index] / scalar);
} }
/// <summary> /// <summary>

51
src/Numerics/Numerics.csproj

@ -70,35 +70,10 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Algorithms\LinearAlgebra\Atlas\AtlasLinearAlgebraProvider.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AtlasLinearAlgebraProvider.tt</DependentUpon>
</Compile>
<Compile Include="Algorithms\LinearAlgebra\Atlas\SafeNativeMethods.cs">
<DependentUpon>SafeNativeMethods.tt</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
<None Include="Algorithms\LinearAlgebra\Mkl\MklLinearAlgebraProvider.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>MklLinearAlgebraProvider.cs</LastGenOutput>
</None>
<None Include="Algorithms\LinearAlgebra\NativeAlgebraProvider.include" /> <None Include="Algorithms\LinearAlgebra\NativeAlgebraProvider.include" />
<Compile Include="Algorithms\LinearAlgebra\ILinearAlgebraProvider.cs" /> <Compile Include="Algorithms\LinearAlgebra\ILinearAlgebraProvider.cs" />
<Compile Include="Algorithms\LinearAlgebra\ILinearAlgebraProviderOfT.cs" /> <Compile Include="Algorithms\LinearAlgebra\ILinearAlgebraProviderOfT.cs" />
<Compile Include="Algorithms\LinearAlgebra\ManagedLinearAlgebraProvider.cs" /> <Compile Include="Algorithms\LinearAlgebra\ManagedLinearAlgebraProvider.cs" />
<Compile Include="Algorithms\LinearAlgebra\Mkl\MklLinearAlgebraProvider.cs">
<DependentUpon>MklLinearAlgebraProvider.tt</DependentUpon>
<SubType>Code</SubType>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Include="Algorithms\LinearAlgebra\Mkl\SafeNativeMethods.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>SafeNativeMethods.tt</DependentUpon>
</Compile>
<Compile Include="Combinatorics.cs" /> <Compile Include="Combinatorics.cs" />
<Compile Include="ComplexExtensions.cs" /> <Compile Include="ComplexExtensions.cs" />
<Compile Include="Constants.cs" /> <Compile Include="Constants.cs" />
@ -124,18 +99,28 @@
<Compile Include="Distributions\Multivariate\InverseWishart.cs" /> <Compile Include="Distributions\Multivariate\InverseWishart.cs" />
<Compile Include="Distributions\Multivariate\MatrixNormal.cs" /> <Compile Include="Distributions\Multivariate\MatrixNormal.cs" />
<Compile Include="Distributions\Multivariate\Wishart.cs" /> <Compile Include="Distributions\Multivariate\Wishart.cs" />
<Compile Include="LinearAlgebra\Complex32\DenseMatrix.cs" />
<Compile Include="LinearAlgebra\Complex32\DiagonalMatrix.cs" />
<Compile Include="LinearAlgebra\Complex32\IO\DelimitedWriter.cs" /> <Compile Include="LinearAlgebra\Complex32\IO\DelimitedWriter.cs" />
<Compile Include="LinearAlgebra\Complex32\IO\MatlabReader.cs" /> <Compile Include="LinearAlgebra\Complex32\IO\MatlabReader.cs" />
<Compile Include="LinearAlgebra\Complex32\Matrix.cs" />
<Compile Include="LinearAlgebra\Complex32\SparseMatrix.cs" />
<Compile Include="LinearAlgebra\Complex32\Vector.cs" /> <Compile Include="LinearAlgebra\Complex32\Vector.cs" />
<Compile Include="LinearAlgebra\Complex\DenseMatrix.cs" />
<Compile Include="LinearAlgebra\Complex\DenseVector.cs"> <Compile Include="LinearAlgebra\Complex\DenseVector.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="LinearAlgebra\Complex\DiagonalMatrix.cs" />
<Compile Include="LinearAlgebra\Complex\IO\DelimitedWriter.cs" /> <Compile Include="LinearAlgebra\Complex\IO\DelimitedWriter.cs" />
<Compile Include="LinearAlgebra\Complex\IO\MatlabReader.cs" /> <Compile Include="LinearAlgebra\Complex\IO\MatlabReader.cs" />
<Compile Include="LinearAlgebra\Complex\Matrix.cs" /> <Compile Include="LinearAlgebra\Complex\Matrix.cs" />
<Compile Include="LinearAlgebra\Complex\SparseMatrix.cs" />
<Compile Include="LinearAlgebra\Complex\Vector.cs" /> <Compile Include="LinearAlgebra\Complex\Vector.cs" />
<Compile Include="LinearAlgebra\Double\DenseMatrix.cs" />
<Compile Include="LinearAlgebra\Double\DiagonalMatrix.cs" />
<Compile Include="LinearAlgebra\Double\IO\DelimitedWriter.cs" /> <Compile Include="LinearAlgebra\Double\IO\DelimitedWriter.cs" />
<Compile Include="LinearAlgebra\Double\Matrix.cs" /> <Compile Include="LinearAlgebra\Double\Matrix.cs" />
<Compile Include="LinearAlgebra\Double\SparseMatrix.cs" />
<Compile Include="LinearAlgebra\Double\Vector.cs" /> <Compile Include="LinearAlgebra\Double\Vector.cs" />
<Compile Include="LinearAlgebra\Generic\Common.cs" /> <Compile Include="LinearAlgebra\Generic\Common.cs" />
<Compile Include="LinearAlgebra\IO\MatlabReader.cs" /> <Compile Include="LinearAlgebra\IO\MatlabReader.cs" />
@ -212,7 +197,9 @@
<Compile Include="LinearAlgebra\IO\DelimitedWriter.cs" /> <Compile Include="LinearAlgebra\IO\DelimitedWriter.cs" />
<Compile Include="LinearAlgebra\IO\MatrixReader.cs" /> <Compile Include="LinearAlgebra\IO\MatrixReader.cs" />
<Compile Include="LinearAlgebra\IO\MatrixWriter.cs" /> <Compile Include="LinearAlgebra\IO\MatrixWriter.cs" />
<Compile Include="LinearAlgebra\Single\DenseMatrix.cs" />
<Compile Include="LinearAlgebra\Single\DenseVector.cs" /> <Compile Include="LinearAlgebra\Single\DenseVector.cs" />
<Compile Include="LinearAlgebra\Single\DiagonalMatrix.cs" />
<Compile Include="LinearAlgebra\Single\Factorization\DenseGramSchmidt.cs" /> <Compile Include="LinearAlgebra\Single\Factorization\DenseGramSchmidt.cs" />
<Compile Include="LinearAlgebra\Single\Factorization\DenseEvd.cs" /> <Compile Include="LinearAlgebra\Single\Factorization\DenseEvd.cs" />
<Compile Include="LinearAlgebra\Single\Factorization\DenseCholesky.cs" /> <Compile Include="LinearAlgebra\Single\Factorization\DenseCholesky.cs" />
@ -228,6 +215,7 @@
<Compile Include="LinearAlgebra\Single\IO\DelimitedReader.cs" /> <Compile Include="LinearAlgebra\Single\IO\DelimitedReader.cs" />
<Compile Include="LinearAlgebra\Single\IO\DelimitedWriter.cs" /> <Compile Include="LinearAlgebra\Single\IO\DelimitedWriter.cs" />
<Compile Include="LinearAlgebra\Single\IO\MatlabReader.cs" /> <Compile Include="LinearAlgebra\Single\IO\MatlabReader.cs" />
<Compile Include="LinearAlgebra\Single\Matrix.cs" />
<Compile Include="LinearAlgebra\Single\Solvers\Iterative\BiCgStab.cs" /> <Compile Include="LinearAlgebra\Single\Solvers\Iterative\BiCgStab.cs" />
<Compile Include="LinearAlgebra\Single\Solvers\Iterative\CompositeSolver.cs" /> <Compile Include="LinearAlgebra\Single\Solvers\Iterative\CompositeSolver.cs" />
<Compile Include="LinearAlgebra\Single\Solvers\Iterative\GpBiCg.cs" /> <Compile Include="LinearAlgebra\Single\Solvers\Iterative\GpBiCg.cs" />
@ -243,6 +231,7 @@
<Compile Include="LinearAlgebra\Single\Solvers\StopCriterium\FailureStopCriterium.cs" /> <Compile Include="LinearAlgebra\Single\Solvers\StopCriterium\FailureStopCriterium.cs" />
<Compile Include="LinearAlgebra\Single\Solvers\StopCriterium\IterationCountStopCriterium.cs" /> <Compile Include="LinearAlgebra\Single\Solvers\StopCriterium\IterationCountStopCriterium.cs" />
<Compile Include="LinearAlgebra\Single\Solvers\StopCriterium\ResidualStopCriterium.cs" /> <Compile Include="LinearAlgebra\Single\Solvers\StopCriterium\ResidualStopCriterium.cs" />
<Compile Include="LinearAlgebra\Single\SparseMatrix.cs" />
<Compile Include="LinearAlgebra\Single\SparseVector.cs" /> <Compile Include="LinearAlgebra\Single\SparseVector.cs" />
<Compile Include="LinearAlgebra\Generic\Factorization\Cholesky.cs" /> <Compile Include="LinearAlgebra\Generic\Factorization\Cholesky.cs" />
<Compile Include="LinearAlgebra\Double\Factorization\DenseCholesky.cs" /> <Compile Include="LinearAlgebra\Double\Factorization\DenseCholesky.cs" />
@ -398,18 +387,6 @@
<None Include="..\MathNet.Numerics.snk"> <None Include="..\MathNet.Numerics.snk">
<Link>MathNet.Numerics.snk</Link> <Link>MathNet.Numerics.snk</Link>
</None> </None>
<None Include="Algorithms\LinearAlgebra\Atlas\AtlasLinearAlgebraProvider.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>AtlasLinearAlgebraProvider.cs</LastGenOutput>
</None>
<None Include="Algorithms\LinearAlgebra\Atlas\SafeNativeMethods.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>SafeNativeMethods.cs</LastGenOutput>
</None>
<None Include="Algorithms\LinearAlgebra\Mkl\SafeNativeMethods.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>SafeNativeMethods.cs</LastGenOutput>
</None>
<None Include="Algorithms\LinearAlgebra\SafeNativeMethods.include"> <None Include="Algorithms\LinearAlgebra\SafeNativeMethods.include">
<LastGenOutput>SafeNativeMethods.cs</LastGenOutput> <LastGenOutput>SafeNativeMethods.cs</LastGenOutput>
</None> </None>

12
src/Silverlight/Silverlight.csproj

@ -317,6 +317,9 @@
<Compile Include="..\Numerics\LinearAlgebra\Complex32\Factorization\UserSvd.cs"> <Compile Include="..\Numerics\LinearAlgebra\Complex32\Factorization\UserSvd.cs">
<Link>LinearAlgebra\Complex32\Factorization\UserSvd.cs</Link> <Link>LinearAlgebra\Complex32\Factorization\UserSvd.cs</Link>
</Compile> </Compile>
<Compile Include="..\Numerics\LinearAlgebra\Complex32\Matrix.cs">
<Link>LinearAlgebra\Complex32\Matrix.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Complex32\Solvers\Iterative\BiCgStab.cs"> <Compile Include="..\Numerics\LinearAlgebra\Complex32\Solvers\Iterative\BiCgStab.cs">
<Link>LinearAlgebra\Complex32\Solvers\Iterative\BiCgStab.cs</Link> <Link>LinearAlgebra\Complex32\Solvers\Iterative\BiCgStab.cs</Link>
</Compile> </Compile>
@ -416,6 +419,9 @@
<Compile Include="..\Numerics\LinearAlgebra\Complex\Factorization\UserSvd.cs"> <Compile Include="..\Numerics\LinearAlgebra\Complex\Factorization\UserSvd.cs">
<Link>LinearAlgebra\Complex\Factorization\UserSvd.cs</Link> <Link>LinearAlgebra\Complex\Factorization\UserSvd.cs</Link>
</Compile> </Compile>
<Compile Include="..\Numerics\LinearAlgebra\Complex\Matrix.cs">
<Link>LinearAlgebra\Complex\Matrix.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Complex\Solvers\Iterative\BiCgStab.cs"> <Compile Include="..\Numerics\LinearAlgebra\Complex\Solvers\Iterative\BiCgStab.cs">
<Link>LinearAlgebra\Complex\Solvers\Iterative\BiCgStab.cs</Link> <Link>LinearAlgebra\Complex\Solvers\Iterative\BiCgStab.cs</Link>
</Compile> </Compile>
@ -527,6 +533,9 @@
<Compile Include="..\Numerics\LinearAlgebra\Double\Factorization\UserSvd.cs"> <Compile Include="..\Numerics\LinearAlgebra\Double\Factorization\UserSvd.cs">
<Link>LinearAlgebra\Double\Factorization\UserSvd.cs</Link> <Link>LinearAlgebra\Double\Factorization\UserSvd.cs</Link>
</Compile> </Compile>
<Compile Include="..\Numerics\LinearAlgebra\Double\Matrix.cs">
<Link>LinearAlgebra\Double\Matrix.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Double\Solvers\Iterative\BiCgStab.cs"> <Compile Include="..\Numerics\LinearAlgebra\Double\Solvers\Iterative\BiCgStab.cs">
<Link>LinearAlgebra\Double\Solvers\Iterative\BiCgStab.cs</Link> <Link>LinearAlgebra\Double\Solvers\Iterative\BiCgStab.cs</Link>
</Compile> </Compile>
@ -635,6 +644,9 @@
<Compile Include="..\Numerics\LinearAlgebra\Single\Factorization\UserSvd.cs"> <Compile Include="..\Numerics\LinearAlgebra\Single\Factorization\UserSvd.cs">
<Link>LinearAlgebra\Single\Factorization\UserSvd.cs</Link> <Link>LinearAlgebra\Single\Factorization\UserSvd.cs</Link>
</Compile> </Compile>
<Compile Include="..\Numerics\LinearAlgebra\Single\Matrix.cs">
<Link>LinearAlgebra\Single\Matrix.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Single\Solvers\Iterative\BiCgStab.cs"> <Compile Include="..\Numerics\LinearAlgebra\Single\Solvers\Iterative\BiCgStab.cs">
<Link>LinearAlgebra\Single\Solvers\Iterative\BiCgStab.cs</Link> <Link>LinearAlgebra\Single\Solvers\Iterative\BiCgStab.cs</Link>
</Compile> </Compile>

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

@ -45,13 +45,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
var value = new Complex(real, imaginary); var value = new Complex(real, imaginary);
var matrix = TestMatrices["Singular3x3"]; var matrix = TestMatrices["Singular3x3"];
var clone = matrix.Clone(); var clone = matrix.Clone();
clone.Multiply(value); var result = clone.Multiply(value);
for (var i = 0; i < matrix.RowCount; i++) for (var i = 0; i < matrix.RowCount; i++)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var j = 0; j < matrix.ColumnCount; j++)
{ {
AssertHelpers.AreEqual(matrix[i, j] * value, clone[i, j]); AssertHelpers.AreEqual(matrix[i, j] * value, result[i, j]);
} }
} }
} }
@ -184,7 +184,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var j = 0; j < matrix.ColumnCount; j++)
{ {
AssertHelpers.AreEqual(matrix[i, j] * value, result[i, j]); var expected = matrix[i, j] * value;
AssertHelpers.AreEqual(expected, result[i, j]);
} }
} }
} }
@ -241,12 +242,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
var matrixB = TestMatrices[mtxB]; var matrixB = TestMatrices[mtxB];
var matrix = matrixA.Clone(); var matrix = matrixA.Clone();
matrix.Add(matrixB); var result = matrix.Add(matrixB);
for (var i = 0; i < matrix.RowCount; i++) for (var i = 0; i < matrix.RowCount; i++)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var j = 0; j < matrix.ColumnCount; j++)
{ {
AssertHelpers.AreEqual(matrix[i, j], matrixA[i, j] + matrixB[i, j]); AssertHelpers.AreEqual(matrixA[i, j] + matrixB[i, j], result[i,j]);
} }
} }
} }
@ -341,12 +342,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
var matrixB = TestMatrices[mtxB]; var matrixB = TestMatrices[mtxB];
var matrix = matrixA.Clone(); var matrix = matrixA.Clone();
matrix.Subtract(matrixB); var result = matrix.Subtract(matrixB);
for (var i = 0; i < matrix.RowCount; i++) for (var i = 0; i < matrix.RowCount; i++)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var j = 0; j < matrix.ColumnCount; j++)
{ {
AssertHelpers.AreEqual(matrix[i, j], matrixA[i, j] - matrixB[i, j]); AssertHelpers.AreEqual(matrixA[i, j] - matrixB[i, j], result[i, j]);
} }
} }
} }
@ -590,13 +591,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
var matrix = TestMatrices[name]; var matrix = TestMatrices[name];
var copy = matrix.Clone(); var copy = matrix.Clone();
copy.Negate(); var result = copy.Negate();
for (var i = 0; i < matrix.RowCount; i++) for (var i = 0; i < matrix.RowCount; i++)
{ {
for (var j = 0; j < matrix.ColumnCount; j++) for (var j = 0; j < matrix.ColumnCount; j++)
{ {
AssertHelpers.AreEqual(-matrix[i, j], copy[i, j]); AssertHelpers.AreEqual(-matrix[i, j], result[i, j]);
} }
} }
} }
@ -607,13 +608,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
[Row("Square4x4")] [Row("Square4x4")]
[Row("Tall3x2")] [Row("Tall3x2")]
[Row("Wide2x3")] [Row("Wide2x3")]
[MultipleAsserts] [MultipleAsserts, Ignore]
public void CanNegateIntoResult(string name) public void CanNegateIntoResult(string name)
{ {
var matrix = TestMatrices[name]; var matrix = TestMatrices[name];
var copy = matrix.Clone(); var copy = matrix.Clone();
var result = CreateMatrix(copy.RowCount, copy.ColumnCount);
matrix.Negate(copy); //matrix.Negate(copy, result);
for (var i = 0; i < matrix.RowCount; i++) for (var i = 0; i < matrix.RowCount; i++)
{ {
@ -794,26 +795,24 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
[Test] [Test]
public virtual void PointwiseDivideResult() public virtual void PointwiseDivideResult()
{ {
foreach (var data in TestMatrices.Values) var data = TestMatrices["Singular3x3"];
var other = data.Clone();
var result = data.Clone();
data.PointwiseDivide(other, result);
for (var i = 0; i < data.RowCount; i++)
{ {
var other = data.Clone(); for (var j = 0; j < data.ColumnCount; j++)
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]);
{
AssertHelpers.AreEqual(data[i, j] / other[i, j], result[i, j]);
}
} }
}
result = data.PointwiseDivide(other); result = data.PointwiseDivide(other);
for (var i = 0; i < data.RowCount; i++) for (var i = 0; i < data.RowCount; i++)
{
for (var j = 0; j < data.ColumnCount; j++)
{ {
for (var j = 0; j < data.ColumnCount; j++) AssertHelpers.AreEqual(data[i, j] / other[i, j], result[i, j]);
{
AssertHelpers.AreEqual(data[i, j] / other[i, j], result[i, j]);
}
} }
} }
} }

110
src/UnitTests/LinearAlgebraTests/Complex/UserDefinedMatrixTests.cs

@ -3,9 +3,7 @@
// http://numerics.mathdotnet.com // http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2010 Math.NET
//
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
@ -14,10 +12,8 @@
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
//
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@ -30,17 +26,15 @@
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
{ {
using System;
using System.Numerics; using System.Numerics;
using Distributions; using LinearAlgebra.Complex;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using Threading;
internal class UserDefinedMatrix : Matrix<Complex> internal class UserDefinedMatrix : Matrix
{ {
private readonly Complex[,] _data; private readonly Complex[,] _data;
public UserDefinedMatrix(int order): base(order, order) public UserDefinedMatrix(int order) : base(order, order)
{ {
_data = new Complex[order, order]; _data = new Complex[order, order];
} }
@ -85,104 +79,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
return m; return m;
} }
public override void Negate()
{
Multiply(-Complex.One);
}
public override Matrix<Complex> 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 Complex(distribution.Sample(), distribution.Sample());
}
});
return matrix;
}
public override Matrix<Complex> 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 Complex(distribution.Sample(), distribution.Sample());
}
});
return matrix;
}
protected sealed override Complex AddT(Complex val1, Complex val2)
{
return val1 + val2;
}
protected sealed override Complex SubtractT(Complex val1, Complex val2)
{
return val1 - val2;
}
protected sealed override Complex MultiplyT(Complex val1, Complex val2)
{
return val1 * val2;
}
protected sealed override Complex DivideT(Complex val1, Complex val2)
{
return val1 / val2;
}
protected sealed override double AbsoluteT(Complex val1)
{
return val1.Magnitude;
}
public override Matrix<Complex> 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 public class UserDefinedMatrixTests : MatrixTests

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

@ -497,7 +497,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
AssertHelpers.AreEqual(Data[i] / 2.0, vector[i]); AssertHelpers.AreEqual(Data[i] / 2.0, vector[i]);
} }
vector.Divide(1.0); vector = vector.Divide(1.0);
for (var i = 0; i < Data.Length; i++) for (var i = 0; i < Data.Length; i++)
{ {
AssertHelpers.AreEqual(Data[i] / 2.0, vector[i]); AssertHelpers.AreEqual(Data[i] / 2.0, vector[i]);
@ -639,12 +639,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
{ {
AssertHelpers.AreEqual(Data[i] / 2.0, vector[i]); AssertHelpers.AreEqual(Data[i] / 2.0, vector[i]);
} }
vector = vector / 1.0;
for (var i = 0; i < Data.Length; i++)
{
AssertHelpers.AreEqual(Data[i] / 2.0, vector[i]);
}
} }
[Test] [Test]

10
src/UnitTests/LinearAlgebraTests/Complex32/IO/MatlabReaderTests.cs

@ -24,7 +24,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.IO
Assert.AreEqual(100, a.RowCount); Assert.AreEqual(100, a.RowCount);
Assert.AreEqual(100, a.ColumnCount); Assert.AreEqual(100, a.ColumnCount);
AssertHelpers.AlmostEqual(27.232498979698409, a.L2Norm(), 6); AssertHelpers.AlmostEqual(27.232498979698409, a.L2Norm().Real, 6);
} }
[Test] [Test]
@ -42,7 +42,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.IO
Assert.AreEqual(100, a.RowCount); Assert.AreEqual(100, a.RowCount);
Assert.AreEqual(100, a.ColumnCount); Assert.AreEqual(100, a.ColumnCount);
AssertHelpers.AlmostEqual(13.223654390985379, a.L2Norm(), 7); AssertHelpers.AlmostEqual(13.223654390985379, a.L2Norm().Real, 7);
} }
[Test] [Test]
@ -65,7 +65,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.IO
Assert.AreEqual(100, matrix.RowCount); Assert.AreEqual(100, matrix.RowCount);
Assert.AreEqual(100, matrix.ColumnCount); Assert.AreEqual(100, matrix.ColumnCount);
Assert.AreEqual(typeof(DenseMatrix), matrix.GetType()); Assert.AreEqual(typeof(DenseMatrix), matrix.GetType());
AssertHelpers.AlmostEqual(100.108979553704, matrix.FrobeniusNorm(), 6); AssertHelpers.AlmostEqual(100.108979553704, matrix.FrobeniusNorm().Real, 6);
} }
@ -89,7 +89,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.IO
Assert.AreEqual(1, matrices.Length); Assert.AreEqual(1, matrices.Length);
Assert.AreEqual(100, matrices[0].RowCount); Assert.AreEqual(100, matrices[0].RowCount);
Assert.AreEqual(100, matrices[0].ColumnCount); Assert.AreEqual(100, matrices[0].ColumnCount);
AssertHelpers.AlmostEqual(100.431635988639, matrices[0].FrobeniusNorm(), 6); AssertHelpers.AlmostEqual(100.431635988639, matrices[0].FrobeniusNorm().Real, 6);
Assert.AreEqual(typeof(DenseMatrix), matrices[0].GetType()); Assert.AreEqual(typeof(DenseMatrix), matrices[0].GetType());
} }
@ -101,7 +101,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.IO
Assert.AreEqual(100, matrix.RowCount); Assert.AreEqual(100, matrix.RowCount);
Assert.AreEqual(100, matrix.ColumnCount); Assert.AreEqual(100, matrix.ColumnCount);
Assert.AreEqual(typeof(SparseMatrix), matrix.GetType()); Assert.AreEqual(typeof(SparseMatrix), matrix.GetType());
AssertHelpers.AlmostEqual(17.6385090630805, matrix.FrobeniusNorm(), 6); AssertHelpers.AlmostEqual(17.6385090630805, matrix.FrobeniusNorm().Real, 6);
} }
} }
} }

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

@ -1447,52 +1447,52 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
public virtual void FrobeniusNorm() public virtual void FrobeniusNorm()
{ {
var matrix = TestMatrices["Square3x3"]; var matrix = TestMatrices["Square3x3"];
AssertHelpers.AlmostEqual(10.8819655f, (float)matrix.FrobeniusNorm(), 7); AssertHelpers.AlmostEqual(10.8819655f, matrix.FrobeniusNorm().Real, 7);
matrix = TestMatrices["Wide2x3"]; matrix = TestMatrices["Wide2x3"];
AssertHelpers.AlmostEqual(5.1905256f, (float)matrix.FrobeniusNorm(), 7); AssertHelpers.AlmostEqual(5.1905256f, matrix.FrobeniusNorm().Real, 7);
matrix = TestMatrices["Tall3x2"]; matrix = TestMatrices["Tall3x2"];
AssertHelpers.AlmostEqual(7.5904115f, (float)matrix.FrobeniusNorm(), 7); AssertHelpers.AlmostEqual(7.5904115f, matrix.FrobeniusNorm().Real, 7);
} }
[Test] [Test]
public virtual void InfinityNorm() public virtual void InfinityNorm()
{ {
Matrix<Complex32> matrix = TestMatrices["Square3x3"]; Matrix<Complex32> matrix = TestMatrices["Square3x3"];
AssertHelpers.AlmostEqual(16.7777033f, (float)matrix.InfinityNorm(), 6); AssertHelpers.AlmostEqual(16.7777033f, matrix.InfinityNorm().Real, 6);
matrix = TestMatrices["Wide2x3"]; matrix = TestMatrices["Wide2x3"];
AssertHelpers.AlmostEqual(7.3514039f, (float)matrix.InfinityNorm(), 6); AssertHelpers.AlmostEqual(7.3514039f, matrix.InfinityNorm().Real, 6);
matrix = TestMatrices["Tall3x2"]; matrix = TestMatrices["Tall3x2"];
AssertHelpers.AlmostEqual(10.1023756f, (float)matrix.InfinityNorm(), 6); AssertHelpers.AlmostEqual(10.1023756f, matrix.InfinityNorm().Real, 6);
} }
[Test] [Test]
public virtual void L1Norm() public virtual void L1Norm()
{ {
var matrix = TestMatrices["Square3x3"]; var matrix = TestMatrices["Square3x3"];
AssertHelpers.AlmostEqual(12.5401248f, (float)matrix.L1Norm(), 7); AssertHelpers.AlmostEqual(12.5401248f, matrix.L1Norm().Real, 7);
matrix = TestMatrices["Wide2x3"]; matrix = TestMatrices["Wide2x3"];
AssertHelpers.AlmostEqual(5.8647971f, (float)matrix.L1Norm(), 7); AssertHelpers.AlmostEqual(5.8647971f, matrix.L1Norm().Real, 7);
matrix = TestMatrices["Tall3x2"]; matrix = TestMatrices["Tall3x2"];
AssertHelpers.AlmostEqual(9.4933860f, (float)matrix.L1Norm(), 7); AssertHelpers.AlmostEqual(9.4933860f, matrix.L1Norm().Real, 7);
} }
[Test] [Test]
public virtual void L2Norm() public virtual void L2Norm()
{ {
var matrix = TestMatrices["Square3x3"]; var matrix = TestMatrices["Square3x3"];
AssertHelpers.AlmostEqual(10.6381752f, (float)matrix.L2Norm(), 6); AssertHelpers.AlmostEqual(10.6381752f, matrix.L2Norm().Real, 6);
matrix = TestMatrices["Wide2x3"]; matrix = TestMatrices["Wide2x3"];
AssertHelpers.AlmostEqual(5.2058554f, (float)matrix.L2Norm(), 6); AssertHelpers.AlmostEqual(5.2058554f, matrix.L2Norm().Real, 6);
matrix = TestMatrices["Tall3x2"]; matrix = TestMatrices["Tall3x2"];
AssertHelpers.AlmostEqual(7.3582664f, (float)matrix.L2Norm(), 6); AssertHelpers.AlmostEqual(7.3582664f, matrix.L2Norm().Real, 6);
} }
} }
} }

112
src/UnitTests/LinearAlgebraTests/Complex32/UserDefinedMatrixTests.cs

@ -3,9 +3,7 @@
// http://numerics.mathdotnet.com // http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2010 Math.NET
//
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
@ -14,10 +12,8 @@
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
//
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@ -30,17 +26,15 @@
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
{ {
using System; using LinearAlgebra.Complex32;
using Numerics;
using Distributions;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using Threading; using Complex32 = Numerics.Complex32;
internal class UserDefinedMatrix : Matrix<Complex32> internal class UserDefinedMatrix : Matrix
{ {
private readonly Complex32[,] _data; private readonly Complex32[,] _data;
public UserDefinedMatrix(int order): base(order, order) public UserDefinedMatrix(int order) : base(order, order)
{ {
_data = new Complex32[order, order]; _data = new Complex32[order, order];
} }
@ -85,104 +79,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
return m; 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 public class UserDefinedMatrixTests : MatrixTests

97
src/UnitTests/LinearAlgebraTests/Double/UserDefinedMatrixTests.cs

@ -3,9 +3,7 @@
// http://numerics.mathdotnet.com // http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2010 Math.NET
//
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
@ -14,10 +12,8 @@
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
//
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@ -30,17 +26,14 @@
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
{ {
using System; using LinearAlgebra.Double;
using Distributions;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using Properties;
using Threading;
internal class UserDefinedMatrix : Matrix<double> internal class UserDefinedMatrix : Matrix
{ {
private readonly double[,] _data; private readonly double[,] _data;
public UserDefinedMatrix(int order): base(order, order) public UserDefinedMatrix(int order) : base(order, order)
{ {
_data = new double[order, order]; _data = new double[order, order];
} }
@ -85,90 +78,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
return m; return m;
} }
public override void Negate()
{
Multiply(-1);
}
public override Matrix<double> 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] = distribution.Sample();
}
});
return matrix;
}
public override Matrix<double> 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] = distribution.Sample();
}
});
return matrix;
}
protected sealed override double AddT(double val1, double val2)
{
return val1 + val2;
}
protected sealed override double SubtractT(double val1, double val2)
{
return val1 - val2;
}
protected sealed override double MultiplyT(double val1, double val2)
{
return val1 * val2;
}
protected sealed override double DivideT(double val1, double val2)
{
return val1 / val2;
}
protected sealed override double AbsoluteT(double val1)
{
return Math.Abs(val1);
}
} }
public class UserDefinedMatrixTests : MatrixTests public class UserDefinedMatrixTests : MatrixTests

97
src/UnitTests/LinearAlgebraTests/Single/UserDefinedMatrixTests.cs

@ -3,9 +3,7 @@
// http://numerics.mathdotnet.com // http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2010 Math.NET // Copyright (c) 2009-2010 Math.NET
//
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
@ -14,10 +12,8 @@
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
//
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@ -30,17 +26,14 @@
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
{ {
using System;
using Distributions;
using LinearAlgebra.Generic; using LinearAlgebra.Generic;
using Properties; using LinearAlgebra.Single;
using Threading;
internal class UserDefinedMatrix : Matrix<float> internal class UserDefinedMatrix : Matrix
{ {
private readonly float[,] _data; private readonly float[,] _data;
public UserDefinedMatrix(int order): base(order, order) public UserDefinedMatrix(int order) : base(order, order)
{ {
_data = new float[order, order]; _data = new float[order, order];
} }
@ -85,90 +78,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
return m; return m;
} }
public override void Negate()
{
Multiply(-1);
}
public override Matrix<float> 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] = (float)distribution.Sample();
}
});
return matrix;
}
public override Matrix<float> 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] = distribution.Sample();
}
});
return matrix;
}
protected sealed override float AddT(float val1, float val2)
{
return val1 + val2;
}
protected sealed override float SubtractT(float val1, float val2)
{
return val1 - val2;
}
protected sealed override float MultiplyT(float val1, float val2)
{
return val1 * val2;
}
protected sealed override float DivideT(float val1, float val2)
{
return val1 / val2;
}
protected sealed override double AbsoluteT(float val1)
{
return Math.Abs(val1);
}
} }
public class UserDefinedMatrixTests : MatrixTests public class UserDefinedMatrixTests : MatrixTests

Loading…
Cancel
Save