From 690f625e1e69424e09d17af7ba6dbef38b4e2825 Mon Sep 17 00:00:00 2001 From: Marcus Cuda Date: Sat, 12 Jun 2010 13:17:37 +0300 Subject: [PATCH] merged Hany additions --- .../LinearAlgebra/Double/DenseMatrix.cs | 83 +- .../LinearAlgebra/Double/Matrix.Arithmetic.cs | 430 ++++--- src/Numerics/LinearAlgebra/Double/Matrix.cs | 1024 +++++++++++++++-- src/Numerics/LinearAlgebra/Double/Vector.cs | 4 +- .../Double/MatrixTests.Arithmetic.cs | 547 ++++----- .../LinearAlgebraTests/Double/MatrixTests.cs | 991 ++++++++++++++-- .../LinearAlgebraTests/Double/VectorTests.cs | 6 +- 7 files changed, 2467 insertions(+), 618 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs index a90ead04..1d6c375d 100644 --- a/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs @@ -3,9 +3,7 @@ // 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 @@ -14,10 +12,8 @@ // 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 @@ -48,7 +44,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double public DenseMatrix(int order) : base(order) { - Data = new double[order * order]; + this.Data = new double[order * order]; } /// @@ -63,7 +59,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double public DenseMatrix(int rows, int columns) : base(rows, columns) { - Data = new double[rows * columns]; + this.Data = new double[rows * columns]; } /// @@ -79,10 +75,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double public DenseMatrix(int rows, int columns, double value) : base(rows, columns) { - Data = new double[rows * columns]; - for (var i = 0; i < Data.Length; i++) + this.Data = new double[rows * columns]; + for (var i = 0; i < this.Data.Length; i++) { - Data[i] = value; + this.Data[i] = value; } } @@ -96,7 +92,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double public DenseMatrix(int rows, int columns, double[] array) : base(rows, columns) { - Data = array; + this.Data = array; } /// @@ -109,12 +105,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double { var rows = array.GetLength(0); var columns = array.GetLength(1); - Data = new double[rows * columns]; + this.Data = new double[rows * columns]; for (var i = 0; i < rows; i++) { for (var j = 0; j < columns; j++) { - Data[(j * rows) + i] = array[i, j]; + this.Data[(j * rows) + i] = array[i, j]; } } } @@ -123,7 +119,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// Gets the matrix's data. /// /// The matrix's data. - internal double[] Data { get; private set; } + internal double[] Data + { + get; + private set; + } /// /// Creates a DenseMatrix for the given number of rows and columns. @@ -168,7 +168,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// public override double At(int row, int column) { - return Data[(column * RowCount) + row]; + return this.Data[(column * this.RowCount) + row]; } /// @@ -185,7 +185,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// public override void At(int row, int column, double value) { - Data[(column * RowCount) + row] = value; + this.Data[(column * this.RowCount) + row] = value; } /// @@ -193,7 +193,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// public override void Clear() { - Array.Clear(Data, 0, Data.Length); + Array.Clear(this.Data, 0, this.Data.Length); } /// @@ -202,15 +202,16 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// The transpose of this matrix. public override Matrix Transpose() { - DenseMatrix ret = new DenseMatrix(ColumnCount, RowCount); - for (int j = 0; j < ColumnCount; j++) + var ret = new DenseMatrix(this.ColumnCount, this.RowCount); + for (var j = 0; j < this.ColumnCount; j++) { - int index = j * RowCount; - for (int i = 0; i < RowCount; i++) + var index = j * this.RowCount; + for (var i = 0; i < this.RowCount; i++) { - ret.Data[i * ColumnCount + j] = Data[index + i]; + ret.Data[(i * this.ColumnCount) + j] = this.Data[index + i]; } } + return ret; } @@ -231,7 +232,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - Add(m); + this.Add(m); } } @@ -248,12 +249,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentNullException("other"); } - if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + if (other.RowCount != this.RowCount || other.ColumnCount != this.ColumnCount) { throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); } - Control.LinearAlgebraProvider.AddArrays(Data, other.Data, Data); + Control.LinearAlgebraProvider.AddArrays(this.Data, other.Data, this.Data); } /// @@ -271,7 +272,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - Subtract(m); + this.Subtract(m); } } @@ -288,12 +289,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentNullException("other"); } - if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + if (other.RowCount != this.RowCount || other.ColumnCount != this.ColumnCount) { throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); } - Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); + Control.LinearAlgebraProvider.SubtractArrays(this.Data, other.Data, this.Data); } /// @@ -302,7 +303,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// The scalar to multiply with. public override void Multiply(double scalar) { - Control.LinearAlgebraProvider.ScaleArray(scalar, Data); + Control.LinearAlgebraProvider.ScaleArray(scalar, this.Data); } /// @@ -326,12 +327,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentNullException("result"); } - if (ColumnCount != other.RowCount) + if (this.ColumnCount != other.RowCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions); } - if (result.RowCount != RowCount || result.ColumnCount != other.ColumnCount) + if (result.RowCount != this.RowCount || result.ColumnCount != other.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions); } @@ -346,12 +347,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double else { Control.LinearAlgebraProvider.MatrixMultiply( - Data, - RowCount, - ColumnCount, - m.Data, - m.RowCount, - m.ColumnCount, + this.Data, + this.RowCount, + this.ColumnCount, + m.Data, + m.RowCount, + m.ColumnCount, r.Data); } } @@ -370,7 +371,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentNullException("other"); } - if (ColumnCount != other.RowCount) + if (this.ColumnCount != other.RowCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions); } @@ -381,7 +382,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double return base.Multiply(other); } - var result = (DenseMatrix)CreateMatrix(RowCount, other.ColumnCount); + var result = (DenseMatrix)this.CreateMatrix(this.RowCount, other.ColumnCount); Multiply(other, result); return result; } @@ -417,22 +418,26 @@ namespace MathNet.Numerics.LinearAlgebra.Double #endregion #region Static constructors for special matrices. + /// /// Initializes a square with all zero's except for ones on the diagonal. /// /// the size of the square matrix. + /// A dense identity matrix. /// /// If is less than one. /// public static DenseMatrix Identity(int order) { var m = new DenseMatrix(order); - for (int i = 0; i < order; i++) + for (var i = 0; i < order; i++) { m[i, i] = 1.0; } + return m; } + #endregion } } \ No newline at end of file diff --git a/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs b/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs index 855ab364..ce120717 100644 --- a/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs +++ b/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs @@ -3,9 +3,7 @@ // 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 @@ -14,10 +12,8 @@ // 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 @@ -31,6 +27,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double { using System; + using Distributions; using Properties; using Threading; @@ -58,8 +55,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double } CommonParallel.For( - 0, - this.RowCount, + 0, + this.RowCount, i => { for (var j = 0; j < this.ColumnCount; j++) @@ -88,8 +85,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double } CommonParallel.For( - 0, - this.RowCount, + 0, + this.RowCount, i => { for (var j = 0; j < this.ColumnCount; j++) @@ -111,8 +108,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double } CommonParallel.For( - 0, - this.RowCount, + 0, + this.RowCount, i => { for (var j = 0; j < this.ColumnCount; j++) @@ -204,8 +201,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double else { CommonParallel.For( - 0, - this.RowCount, + 0, + this.RowCount, i => { double s = 0; @@ -215,7 +212,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } result[i] = s; - }); + }); } } @@ -273,8 +270,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double else { CommonParallel.For( - 0, - this.RowCount, + 0, + this.RowCount, j => { double s = 0; @@ -284,7 +281,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } result[j] = s; - }); + }); } } @@ -328,8 +325,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double else { CommonParallel.For( - 0, - this.RowCount, + 0, + this.RowCount, j => { for (var i = 0; i != other.ColumnCount; i++) @@ -342,7 +339,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double result.At(j, i, s); } - }); + }); } } @@ -604,118 +601,110 @@ namespace MathNet.Numerics.LinearAlgebra.Double } /// - /// Concatenates this matrix with the given matrix. + /// Pointwise multiplies this matrix with another matrix. /// - /// The matrix to concatenate. - /// The combined matrix. - public virtual Matrix Append(Matrix right) + /// The matrix to pointwise multiply with this one. + /// If the other matrix is . + /// If this matrix and are not the same size. + /// A new matrix that is the pointwise multiplication of this matrix and . + public virtual Matrix PointwiseMultiply(Matrix other) { - if (right == null) + if (other == null) { - throw new ArgumentNullException("right"); + throw new ArgumentNullException("other"); } - if (right.RowCount != RowCount) + if (this.ColumnCount != other.ColumnCount || this.RowCount != other.RowCount) { - throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "other"); } - Matrix result = CreateMatrix(RowCount, ColumnCount + right.ColumnCount); - Append(right, result); + var result = this.CreateMatrix(this.RowCount, this.ColumnCount); + this.PointwiseMultiply(other, result); return result; } /// - /// Concatenates this matrix with the given matrix and places the result into the result matrix. + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. /// - /// The matrix to concatenate. - /// The combined matrix. - public virtual void Append(Matrix right, Matrix result) + /// The matrix to pointwise multiply with this one. + /// The matrix to store the result of the pointwise multiplication. + /// If the other matrix is . + /// If the result matrix is . + /// If this matrix and are not the same size. + /// If this matrix and are not the same size. + public virtual void PointwiseMultiply(Matrix other, Matrix result) { - if (right == null) + if (other == null) { - throw new ArgumentNullException("right"); + throw new ArgumentNullException("other"); } - if (right.RowCount != RowCount) + if (result == null) { - throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); + throw new ArgumentNullException("result"); } - if (result == null) + if (this.ColumnCount != other.ColumnCount || this.RowCount != other.RowCount) { - throw new ArgumentNullException("result"); + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } - if (result.ColumnCount != (ColumnCount + right.ColumnCount) || result.RowCount != RowCount) + if (this.ColumnCount != result.ColumnCount || this.RowCount != result.RowCount) { - throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } - CommonParallel.Invoke( - () => - { - CommonParallel.For( - 0, - this.RowCount, - i => - { - CommonParallel.For(0, this.ColumnCount, j => result.At(i, j, At(i, j))); - }); - }, - () => + CommonParallel.For( + 0, + this.ColumnCount, + j => { - CommonParallel.For( - 0, - right.RowCount, - i => - { - CommonParallel.For(0, right.ColumnCount, j => result.At(i, j + ColumnCount, right.At(i, j))); - }); - }); + for (var i = 0; i < this.RowCount; i++) + { + result.At(i, j, this.At(i, j) * other.At(i, j)); + } + }); } /// - /// Stacks this matrix on top of the given matrix and places the result into the result matrix. + /// Pointwise divide this matrix by another matrix. /// - /// The matrix to stack this matrix upon. - /// The combined matrix. - /// If lower is . - /// If upper.Columns != lower.Columns. - public virtual Matrix Stack(Matrix lower) + /// The matrix to pointwise subtract this one by. + /// If the other matrix is . + /// If this matrix and are not the same size. + /// A new matrix that is the pointwise division of this matrix and . + public virtual Matrix PointwiseDivide(Matrix other) { - if (lower == null) + if (other == null) { - throw new ArgumentNullException("lower"); + throw new ArgumentNullException("other"); } - if (lower.ColumnCount != ColumnCount) + if (this.ColumnCount != other.ColumnCount || this.RowCount != other.RowCount) { - throw new ArgumentException("lower", Resources.ArgumentMatrixSameColumnDimension); + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "other"); } - Matrix result = CreateMatrix(RowCount + lower.RowCount, ColumnCount); - Stack(lower, result); + var result = this.CreateMatrix(this.RowCount, this.ColumnCount); + this.PointwiseDivide(other, result); return result; } /// - /// Stacks this matrix on top of the given matrix and places the result into the result matrix. + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. /// - /// The matrix to stack this matrix upon. - /// The combined matrix. - /// If lower is . - /// If upper.Columns != lower.Columns. - public virtual void Stack(Matrix lower, Matrix result) + /// The matrix to pointwise divide this one by. + /// The matrix to store the result of the pointwise division. + /// If the other matrix is . + /// If the result matrix is . + /// If this matrix and are not the same size. + /// If this matrix and are not the same size. + public virtual void PointwiseDivide(Matrix other, Matrix result) { - if (lower == null) - { - throw new ArgumentNullException("lower"); - } - - if (lower.ColumnCount != ColumnCount) + if (other == null) { - throw new ArgumentException("lower", Resources.ArgumentMatrixSameColumnDimension); + throw new ArgumentNullException("other"); } if (result == null) @@ -723,88 +712,176 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentNullException("result"); } - if (result.RowCount != (RowCount + lower.RowCount) || result.ColumnCount != ColumnCount) + if (this.ColumnCount != other.ColumnCount || this.RowCount != other.RowCount) { - throw new ArgumentException("result", Resources.ArgumentMatrixDimensions); + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } - CommonParallel.Invoke( - () => + if (this.ColumnCount != result.ColumnCount || this.RowCount != result.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); + } + + CommonParallel.For( + 0, + this.ColumnCount, + j => { - CommonParallel.For( - 0, - this.RowCount, - i => - { - CommonParallel.For(0, this.ColumnCount, j => result.At(i, j, At(i, j))); - }); - }, - () => + for (var i = 0; i < this.RowCount; i++) + { + result.At(i, j, this.At(i, j) / other.At(i, j)); + } + }); + } + + /// + /// Generates matrix with random elements. + /// + /// Number of rows. + /// Number of columns. + /// Continuous Random Distribution or Source + /// + /// An numberOfRows-by-numberOfColumns matrix with elements distributed according to the provided distribution. + /// + /// If the parameter numberOfRows is not positive. + /// If the parameter numberOfColumns is not positive. + public virtual Matrix 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 = this.CreateMatrix(numberOfRows, numberOfColumns); + CommonParallel.For( + 0, + this.ColumnCount, + j => { - CommonParallel.For( - 0, - lower.RowCount, - i => - { - CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j, lower.At(i, j))); - }); + for (var i = 0; i < matrix.RowCount; i++) + { + matrix[i, j] = distribution.Sample(); + } + }); + + return matrix; + } + + /// + /// Generates matrix with random elements. + /// + /// Number of rows. + /// Number of columns. + /// Continuous Random Distribution or Source + /// + /// An numberOfRows-by-numberOfColumns matrix with elements distributed according to the provided distribution. + /// + /// If the parameter numberOfRows is not positive. + /// If the parameter numberOfColumns is not positive. + public virtual Matrix 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 = this.CreateMatrix(numberOfRows, numberOfColumns); + CommonParallel.For( + 0, + this.ColumnCount, + j => + { + for (var i = 0; i < matrix.RowCount; i++) + { + matrix[i, j] = distribution.Sample(); + } }); + + return matrix; } /// /// Computes the trace of this matrix. /// /// The trace of this matrix - /// If the matrix is not square + /// If the matrix is not square public virtual double Trace() { - if (RowCount != ColumnCount) + if (this.RowCount != this.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare); } - double t = 0.0; - for (int i = 0; i < RowCount; i++) - { - t += this[i, i]; - } + return CommonParallel.Aggregate(0, this.RowCount, i => this[i, i]); + } - return t; + /// + /// Calculates the rank of the matrix + /// + /// effective numerical rank, obtained from SVD + public virtual int Rank() + { + throw new NotImplementedException(); + } + + /// Calculates the condition number of this matrix. + /// The condition number of the matrix. + /// The condition number is calculated using singular value decomposition. + public virtual double ConditionNumber() + { + throw new NotImplementedException(); + } + + /// Computes the determinant of this matrix. + /// The determinant of this matrix. + public virtual double Determinant() + { + throw new NotImplementedException(); } /// - /// Diagonally stacks his matrix on top of the given matrix. The new matrix is a M-by-N matrix, - /// where M = this.Rows + lower.Rows and N = this.Columns + lower.Columns. - /// The values of off the off diagonal matrices/blocks are set to zero. + /// Computes the Kronecker product of this matrix with the given matrix. The new matrix is M-by-N + /// with M = this.Rows * lower.Rows and N = this.Columns * lower.Columns. /// - /// The lower, right matrix. - /// If lower is . - /// the combined matrix - public virtual Matrix DiagonalStack(Matrix lower) + /// The other matrix. + /// If other is . + /// The kronecker product of the two matrices. + public virtual Matrix KroneckerProduct(Matrix other) { - if (lower == null) + if (other == null) { - throw new ArgumentNullException("lower"); + throw new ArgumentNullException("other"); } - Matrix result = CreateMatrix(RowCount + lower.RowCount, ColumnCount + lower.ColumnCount); - DiagonalStack(lower, result); + var result = this.CreateMatrix(this.RowCount * other.RowCount, this.ColumnCount * other.ColumnCount); + this.KroneckerProduct(other, result); return result; } /// - /// Diagonally stacks his matrix on top of the given matrix and places the combined matrix into the result matrix. + /// Computes the Kronecker product of this matrix with the given matrix. The new matrix is M-by-N + /// with M = this.Rows * lower.Rows and N = this.Columns * lower.Columns. /// - /// The lower, right matrix. - /// The combined matrix - /// If lower is . + /// The other matrix. + /// The kronecker product of the two matrices. + /// If other is . /// If the result matrix is . - /// If the result matrix's dimensions are not (this.Rows + lower.rows) x (this.Columns + lower.Columns). - public virtual void DiagonalStack(Matrix lower, Matrix result) + /// If the result matrix's dimensions are not (this.Rows * lower.rows) x (this.Columns * lower.Columns). + public virtual void KroneckerProduct(Matrix other, Matrix result) { - if (lower == null) + if (other == null) { - throw new ArgumentNullException("lower"); + throw new ArgumentNullException("other"); } if (result == null) @@ -812,41 +889,80 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentNullException("result"); } - if (result.RowCount != RowCount + lower.RowCount || result.ColumnCount != ColumnCount + lower.ColumnCount) + if (result.RowCount != (this.RowCount * other.RowCount) || result.ColumnCount != (this.ColumnCount * other.ColumnCount)) { - throw new ArgumentException("result", Resources.ArgumentMatrixDimensions); + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } - CommonParallel.Invoke( - () => + CommonParallel.For( + 0, + this.ColumnCount, + j => { - CommonParallel.For( - 0, - this.RowCount, - i => - { - CommonParallel.For(0, this.ColumnCount, j => result.At(i, j, At(i, j))); - }); - }, - () => + for (var i = 0; i < this.RowCount; i++) + { + result.SetSubMatrix(i * other.RowCount, other.RowCount, j * other.ColumnCount, other.ColumnCount, this.At(i, j) * other); + } + }); + } + + /// + /// Normalizes the columns of a matrix. + /// + /// The norm under which to normalize the columns under. + /// A normalized version of the matrix. + /// If the parameter p is not positive. + public virtual Matrix NormalizeColumns(int p) + { + if (p < 1) + { + throw new ArgumentOutOfRangeException("p", Resources.ArgumentMustBePositive); + } + + var ret = this.Clone(); + CommonParallel.For( + 0, + this.ColumnCount, + i => { - CommonParallel.For( - 0, - lower.RowCount, - i => - { - CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j))); - }); + var coli = this.GetColumn(i); + var norm = coli.NormP(p); + for (var j = 0; j < this.RowCount; j++) + { + ret[j, i] = coli[j] / norm; + } }); + return ret; } /// - /// Calculates the rank of the matrix + /// Normalizes the rows of a matrix. /// - /// effective numerical rank, obtained from SVD - public virtual int Rank() + /// The norm under which to normalize the rows under. + /// A normalized version of the matrix. + /// If the parameter p is not positive. + public virtual Matrix NormalizeRows(int p) { - throw new NotImplementedException(); + if (p < 1) + { + throw new ArgumentOutOfRangeException("p", Resources.ArgumentMustBePositive); + } + + var ret = this.Clone(); + CommonParallel.For( + 0, + this.ColumnCount, + j => + { + var rowj = this.GetRow(j); + var norm = rowj.NormP(p); + for (var i = 0; i < this.RowCount; i++) + { + ret[i, j] = rowj[j] / norm; + } + }); + + return ret; } } } \ No newline at end of file diff --git a/src/Numerics/LinearAlgebra/Double/Matrix.cs b/src/Numerics/LinearAlgebra/Double/Matrix.cs index 82945183..c2f3d0f4 100644 --- a/src/Numerics/LinearAlgebra/Double/Matrix.cs +++ b/src/Numerics/LinearAlgebra/Double/Matrix.cs @@ -31,10 +31,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double { using System; + using System.Collections.Generic; using System.Text; using Properties; - using MathNet.Numerics.Threading; - + using Threading; + /// /// Defines the base class for Matrix classes. /// @@ -458,87 +459,324 @@ namespace MathNet.Numerics.LinearAlgebra.Double } /// - /// Copies the elements of a vector into a specific row. The length of the vector must match the number of columns - /// in the matrix. + /// Returns a new matrix containing the lower triangle of this matrix. + /// + /// The lower triangle of this matrix. + public virtual Matrix GetLowerTriangle() + { + Matrix ret = CreateMatrix(RowCount, ColumnCount); + CommonParallel.For( + 0, + ColumnCount, + j => + { + for (int i = j; i < RowCount; i++) + { + ret.At(i, j, At(i, j)); + } + }); + return ret; + } + + /// + /// Puts the lower triangle of this matrix into the result matrix. + /// + /// Where to store the lower triangle. + /// If is . + /// If the result matrix's dimensions are not the same as this matrix. + public virtual void GetLowerTriangle(Matrix result) + { + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); + } + + CommonParallel.For( + 0, + ColumnCount, + j => + { + for (int i = 0; i < RowCount; i++) + { + result.At(i, j, i >= j ? this.At(i, j) : 0); + } + }); + } + + /// + /// Returns a new matrix containing the upper triangle of this matrix. + /// + /// The upper triangle of this matrix. + public virtual Matrix GetUpperTriangle() + { + Matrix ret = CreateMatrix(RowCount, ColumnCount); + CommonParallel.For( + 0, + ColumnCount, + j => + { + for (int i = 0; i < RowCount; i++) + { + if (i <= j) + { + ret.At(i, j, At(i, j)); + } + } + }); + return ret; + } + + /// + /// Puts the upper triangle of this matrix into the result matrix. + /// + /// Where to store the lower triangle. + /// If is . + /// If the result matrix's dimensions are not the same as this matrix. + public virtual void GetUpperTriangle(Matrix result) + { + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); + } + + CommonParallel.For( + 0, + ColumnCount, + j => + { + for (int i = 0; i < RowCount; i++) + { + result.At(i, j, i <= j ? this.At(i, j) : 0); + } + }); + } + + /// + /// Creates a matrix that contains the values from the requested sub-matrix. /// - /// The row in which to copy into. - /// The vector to copy from. - public virtual void SetRow(int r, Vector v) + /// The row to start copying from. + /// The number of rows to copy. Must be positive. + /// The column to start copying from. + /// The number of columns to copy. Must be positive. + /// The requested sub-matrix. + /// If: is + /// negative, or greater than or equal to the number of rows. + /// is negative, or greater than or equal to the number + /// of columns. + /// (columnIndex + columnLength) >= Columns + /// (rowIndex + rowLength) >= Rows + /// If or + /// is not positive. + public virtual Matrix SubMatrix(int rowIndex, int rowLength, int columnIndex, int columnLength) { - if (r < 0 || r >= RowCount) + if (rowIndex >= RowCount || rowIndex < 0) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (columnIndex >= ColumnCount || columnIndex < 0) + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + + if (rowLength < 1) + { + throw new ArgumentException(Resources.ArgumentMustBePositive, "rowLength"); + } + + if (columnLength < 1) { - throw new ArgumentException(Resources.ArgumentMatrixIndexOutOfRange, "r"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "columnLength"); } - if (v == null) + int colMax = columnIndex + columnLength; + int rowMax = rowIndex + rowLength; + + if (rowMax > RowCount) { - throw new ArgumentNullException("v"); + throw new ArgumentOutOfRangeException("rowLength"); } - if (v.Count != ColumnCount) + if (colMax > ColumnCount) { - throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixSameColumnDimension, "v"); + throw new ArgumentOutOfRangeException("columnLength"); } - for (int i = 0; i < v.Count; i++) + Matrix result = CreateMatrix(rowLength, columnLength); + + CommonParallel.For( + columnIndex, + colMax, + j => + { + for (int i = rowIndex, ii = 0; i < rowMax; i++, ii++) + { + result.At(ii, j - columnIndex, At(i, j)); + } + }); + return result; + } + + /// + /// Returns an that enumerates over the matrix columns. + /// + /// An that enumerates over the matrix columns + /// + public virtual IEnumerable> ColumnEnumerator() + { + for (int i = 0; i < ColumnCount; i++) { - this[r, i] = v[i]; + yield return new KeyValuePair(i, GetColumn(i)); } } /// - /// Copies the elements of a vector into a specific column. The length of the vector must match the number of rows - /// in the matrix. + /// Returns an that enumerates the requested matrix columns. /// - /// The column in which to copy into. - /// The vector to copy from. - public virtual void SetColumn(int c, Vector v) + /// The column to start enumerating over. + /// The number of columns to enumerating over. + /// An that enumerates over requested matrix columns. + /// + /// If: + /// is negative, + /// or greater than or equal to the number of columns. + /// (index + length) >= Columns. + /// + /// If is not positive. + public virtual IEnumerable> ColumnEnumerator(int index, int length) { - if (c < 0 || c >= RowCount) + if (index >= this.ColumnCount || index < 0) { - throw new ArgumentException(Resources.ArgumentMatrixIndexOutOfRange, "r"); + throw new ArgumentOutOfRangeException("index"); } - if (v == null) + if (index + length > ColumnCount) { - throw new ArgumentNullException("v"); + throw new ArgumentOutOfRangeException("length"); } - if (v.Count != ColumnCount) + if (length < 1) { - throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixSameRowDimension, "v"); + throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); } - for (int i = 0; i < v.Count; i++) + int maxIndex = index + length; + for (int i = index; i < maxIndex; i++) { - this[i, c] = v[i]; + yield return new KeyValuePair(i, GetColumn(i)); } } /// - /// Returns a new matrix containing the lower triangle of this matrix. + /// Returns an that enumerates the requested matrix rows. /// - /// The lower triangle of this matrix. - public virtual Matrix GetLowerTriangle() + /// The row to start enumerating over. + /// The number of rows to enumerating over. + /// An that enumerates over requested matrix rows. + /// + /// If: + /// is negative, + /// or greater than or equal to the number of rows. + /// (index + length) >= Rows. + /// If is not positive. + public virtual IEnumerable> RowEnumerator(int index, int length) { - Matrix ret = CreateMatrix(RowCount, ColumnCount); - CommonParallel.For(0, ColumnCount, j => + if (index >= RowCount || index < 0) + { + throw new ArgumentOutOfRangeException("index"); + } + + if (index + length > RowCount) + { + throw new ArgumentOutOfRangeException("length"); + } + + if (length < 1) + { + throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); + } + + int maxi = index + length; + for (int i = index; i < maxi; i++) { - for (int i = j; i < RowCount; i++) + yield return new KeyValuePair(i, GetRow(i)); + } + } + + /// + /// Returns an that enumerates over the matrix rows. + /// + /// An that enumerates over the matrix rows + /// + public virtual IEnumerable> RowEnumerator() + { + for (int i = 0; i < RowCount; i++) + { + yield return new KeyValuePair(i, GetRow(i)); + } + } + + /// + /// Returns the elements of the diagonal in a . + /// + /// The elements of the diagonal. + /// For non-square matrices, the method returns Min(Rows, Columns) elements where + /// i == j (i is the row index, and j is the column index). + public virtual Vector Diagonal() + { + int min = Math.Min(RowCount, ColumnCount); + Vector diagonal = CreateVector(min); + CommonParallel.For( + 0, + min, + i => { - ret.At(i, j, At(i, j)); - } - }); - return ret; + diagonal[i] = At(i, i); + }); + return diagonal; } /// - /// Puts the lower triangle of this matrix into the result matrix. + /// Returns a new matrix containing the lower triangle of this matrix. The new matrix + /// does not contain the diagonal elements of this matrix. + /// + /// The lower triangle of this matrix. + public virtual Matrix StrictlyLowerTriangle() + { + Matrix result = CreateMatrix(RowCount, ColumnCount); + CommonParallel.For( + 0, + RowCount, + i => + { + for (int j = 0; j < ColumnCount; j++) + { + if (i > j) + { + result.At(i, j, At(i, j)); + } + } + }); + return result; + } + + /// + /// Puts the strictly lower triangle of this matrix into the result matrix. /// /// Where to store the lower triangle. /// If is . /// If the result matrix's dimensions are not the same as this matrix. - public virtual void GetLowerTriangle(Matrix result) + public virtual void StrictlyLowerTriangle(Matrix result) { if (result == null) { @@ -550,46 +788,409 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } - CommonParallel.For(0, ColumnCount, j => - { - for (int i = 0; i < RowCount; i++) + CommonParallel.For( + 0, + RowCount, + i => { - if (i >= j) + for (int j = 0; j < ColumnCount; j++) { - result.At(i, j, At(i, j)); + result.At(i, j, i > j ? this.At(i, j) : 0); } - else + }); + } + + /// + /// Returns a new matrix containing the upper triangle of this matrix. The new matrix + /// does not contain the diagonal elements of this matrix. + /// + /// The upper triangle of this matrix. + public virtual Matrix StrictlyUpperTriangle() + { + Matrix result = CreateMatrix(RowCount, ColumnCount); + CommonParallel.For( + 0, + RowCount, + i => + { + for (int j = 0; j < ColumnCount; j++) { - result.At(i, j, 0); + if (i < j) + { + result.At(i, j, At(i, j)); + } } - } - }); + }); + return result; + } + + /// + /// Creates a new matrix and inserts the given column at the given index. + /// + /// The index of where to insert the column. + /// The column to insert. + /// A new matrix with the inserted column. + /// If is . + /// If is < zero or > the number of columns. + /// If the size of != the number of rows. + public virtual Matrix InsertColumn(int columnIndex, Vector column) + { + if (column == null) + { + throw new ArgumentNullException("column"); + } + + if (columnIndex < 0 || columnIndex > ColumnCount) + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + + if (column.Count != RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "column"); + } + + Matrix result = CreateMatrix(RowCount, ColumnCount + 1); + + for (int i = 0; i < columnIndex; i++) + { + result.SetColumn(i, GetColumn(i)); + } + + result.SetColumn(columnIndex, column); + + for (int i = columnIndex + 1; i < ColumnCount + 1; i++) + { + result.SetColumn(i, GetColumn(i - 1)); + } + + return result; + } + + /// + /// Copies the values of the given array to the specified column. + /// + /// The column to copy the values to. + /// The array to copy the values from. + /// If is . + /// If is less than zero, + /// or greater than or equal to the number of columns. + /// If the size of does not + /// equal the number of rows of this Matrix. + /// If the size of does not + /// equal the number of rows of this Matrix. + public virtual void SetColumn(int columnIndex, double[] column) + { + if (columnIndex < 0 || columnIndex >= ColumnCount) + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + + if (column == null) + { + throw new ArgumentNullException("column"); + } + + if (column.Length != RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "column"); + } + + CommonParallel.For( + 0, + RowCount, + i => this.At(i, columnIndex, column[i])); + } + + /// + /// Copies the values of the given to the specified column. + /// + /// The column to copy the values to. + /// The vector to copy the values from. + /// If is . + /// If is less than zero, + /// or greater than or equal to the number of columns. + /// If the size of does not + /// equal the number of rows of this Matrix. + public virtual void SetColumn(int columnIndex, Vector column) + { + if (columnIndex < 0 || columnIndex >= ColumnCount) + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + + if (column == null) + { + throw new ArgumentNullException("column"); + } + + if (column.Count != RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "column"); + } + + CommonParallel.For( + 0, + RowCount, + i => this.At(i, columnIndex, column[i])); + } + + /// + /// Creates a new matrix and inserts the given row at the given index. + /// + /// The index of where to insert the row. + /// The row to insert. + /// A new matrix with the inserted column. + /// If is . + /// If is < zero or > the number of rows. + /// If the size of != the number of columns. + public virtual Matrix InsertRow(int rowIndex, Vector row) + { + if (row == null) + { + throw new ArgumentNullException("row"); + } + + if (rowIndex < 0 || rowIndex > RowCount) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (row.Count != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); + } + + Matrix result = CreateMatrix(RowCount + 1, ColumnCount); + + for (int i = 0; i < rowIndex; i++) + { + result.SetRow(i, GetRow(i)); + } + + result.SetRow(rowIndex, row); + + for (int i = rowIndex + 1; i < RowCount; i++) + { + result.SetRow(i, GetRow(i - 1)); + } + + return result; + } + + /// + /// Copies the values of the given to the specified row. + /// + /// The row to copy the values to. + /// The vector to copy the values from. + /// If is . + /// If is less than zero, + /// or greater than or equal to the number of rows. + /// If the size of does not + /// equal the number of columns of this Matrix. + public virtual void SetRow(int rowIndex, Vector row) + { + if (rowIndex < 0 || rowIndex >= RowCount) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (row == null) + { + throw new ArgumentNullException("row"); + } + + if (row.Count != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); + } + + CommonParallel.For( + 0, + ColumnCount, + i => this.At(rowIndex, i, row[i])); } /// - /// Returns a new matrix containing the upper triangle of this matrix. + /// Copies the values of the given array to the specified row. /// - /// The upper triangle of this matrix. - public virtual Matrix GetUpperTriangle() + /// The row to copy the values to. + /// The array to copy the values from. + /// If is . + /// If is less than zero, + /// or greater than or equal to the number of rows. + /// If the size of does not + /// equal the number of columns of this Matrix. + public virtual void SetRow(int rowIndex, double[] row) { - Matrix ret = CreateMatrix(RowCount, ColumnCount); - CommonParallel.For(0, ColumnCount, j => + if (rowIndex < 0 || rowIndex >= RowCount) { - for (int i = 0; i <= j; i++) - { - ret.At(i, j, At(i, j)); - } - }); - return ret; + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (row == null) + { + throw new ArgumentNullException("row"); + } + + if (row.Length != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); + } + + CommonParallel.For( + 0, + ColumnCount, + i => this.At(rowIndex, i, row[i])); } /// - /// Puts the upper triangle of this matrix into the result matrix. + /// Copies the values of a given matrix into a region in this matrix. + /// + /// The row to start copying to. + /// The number of rows to copy. Must be positive. + /// The column to start copying to. + /// The number of columns to copy. Must be positive. + /// The submatrix to copy from. + /// If: is + /// negative, or greater than or equal to the number of rows. + /// is negative, or greater than or equal to the number + /// of columns. + /// (columnIndex + columnLength) >= Columns + /// (rowIndex + rowLength) >= Rows + /// If is + /// the size of is not at least x . + /// If or + /// is not positive. + public virtual void SetSubMatrix(int rowIndex, int rowLength, int columnIndex, int columnLength, Matrix subMatrix) + { + if (rowIndex >= RowCount || rowIndex < 0) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (columnIndex >= ColumnCount || columnIndex < 0) + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + + if (rowLength < 1) + { + throw new ArgumentException(Resources.ArgumentMustBePositive, "rowLength"); + } + + if (columnLength < 1) + { + throw new ArgumentException(Resources.ArgumentMustBePositive, "columnLength"); + } + + if (subMatrix == null) + { + throw new ArgumentNullException("subMatrix"); + } + + if (columnLength > subMatrix.ColumnCount) + { + throw new ArgumentOutOfRangeException("columnLength", "columnLength can be at most the number of columns in subMatrix."); + } + + if (rowLength > subMatrix.RowCount) + { + throw new ArgumentOutOfRangeException("rowLength", "rowLength can be at most the number of rows in subMatrix."); + } + + int colMax = columnIndex + columnLength; + int rowMax = rowIndex + rowLength; + + if (rowMax > RowCount) + { + throw new ArgumentOutOfRangeException("rowLength"); + } + + if (colMax > ColumnCount) + { + throw new ArgumentOutOfRangeException("columnLength"); + } + + CommonParallel.For( + columnIndex, + colMax, + j => + { + for (int i = rowIndex, ii = 0; i < rowMax; i++, ii++) + { + At(i, j, subMatrix[ii, j - columnIndex]); + } + }); + } + + /// + /// Copies the values of the given to the diagonal. + /// + /// The vector to copy the values from. The length of the vector should be + /// Min(Rows, Columns). + /// If is . + /// If the length of does not + /// equal Min(Rows, Columns). + /// For non-square matrices, the elements of are copied to + /// this[i,i]. + public virtual void SetDiagonal(Vector source) + { + if (source == null) + { + throw new ArgumentNullException("source"); + } + + int min = Math.Min(RowCount, ColumnCount); + + if (source.Count != min) + { + throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source"); + } + + CommonParallel.For( + 0, + min, + i => this.At(i, i, source[i])); + } + + /// + /// Copies the values of the given array to the diagonal. + /// + /// The array to copy the values from. The length of the vector should be + /// Min(Rows, Columns). + /// If is . + /// If the length of does not + /// equal Min(Rows, Columns). + /// For non-square matrices, the elements of are copied to + /// this[i,i]. + public virtual void SetDiagonal(double[] source) + { + if (source == null) + { + throw new ArgumentNullException("source"); + } + + int min = Math.Min(RowCount, ColumnCount); + + if (source.Length != min) + { + throw new ArgumentException(Resources.ArgumentArraysSameLength, "source"); + } + + CommonParallel.For( + 0, + min, + i => this.At(i, i, source[i])); + } + + /// + /// Puts the strictly upper triangle of this matrix into the result matrix. /// /// Where to store the lower triangle. /// If is . /// If the result matrix's dimensions are not the same as this matrix. - public virtual void GetUpperTriangle(Matrix result) + public virtual void StrictlyUpperTriangle(Matrix result) { if (result == null) { @@ -601,20 +1202,85 @@ namespace MathNet.Numerics.LinearAlgebra.Double throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } - CommonParallel.For(0, ColumnCount, j => - { - for (int i = 0; i < RowCount; i++) + CommonParallel.For( + 0, + RowCount, + i => { - if (i <= j) + for (int j = 0; j < ColumnCount; j++) { - result.At(i, j, At(i, j)); + result.At(i, j, i < j ? this.At(i, j) : 0); } - else + }); + } + + /// + /// Returns this matrix as a multidimensional array. + /// + /// A multidimensional containing the values of this matrix. + public virtual double[,] ToArray() + { + var ret = new double[RowCount, ColumnCount]; + CommonParallel.For( + 0, + ColumnCount, + j => + { + for (int i = 0; i < RowCount; i++) { - result.At(i, j, 0); + ret[i, j] = At(i, j); } + }); + return ret; + } + + /// + /// Returns the matrix's elements as an array with the data laid out column-wise. + /// + ///
+        /// 1, 2, 3
+        /// 4, 5, 6  will be returned as  1, 4, 7, 2, 5, 8, 3, 6, 9
+        /// 7, 8, 9
+        /// 
+ /// An array containing the matrix's elements. + public virtual double[] ToColumnWiseArray() + { + var ret = new double[RowCount * ColumnCount]; + foreach (KeyValuePair column in ColumnEnumerator()) + { + int columnIndex = column.Key * RowCount; + foreach (KeyValuePair element in column.Value.GetIndexedEnumerator()) + { + ret[columnIndex + element.Key] = element.Value; + } + } + + return ret; + } + + /// + /// Returns the matrix's elements as an array with the data laid row-wise. + /// + ///
+        /// 1, 2, 3
+        /// 4, 5, 6  will be returned as  1, 2, 3, 4, 5, 6, 7, 8, 9
+        /// 7, 8, 9
+        /// 
+ /// An array containing the matrix's elements. + public virtual double[] ToRowWiseArray() + { + var ret = new double[RowCount * ColumnCount]; + + foreach (KeyValuePair row in RowEnumerator()) + { + int rowIndex = row.Key * ColumnCount; + foreach (KeyValuePair element in row.Value.GetIndexedEnumerator()) + { + ret[rowIndex + element.Key] = element.Value; } - }); + } + + return ret; } #region Implemented Interfaces @@ -876,5 +1542,221 @@ namespace MathNet.Numerics.LinearAlgebra.Double } } } - } + + /// + /// Concatenates this matrix with the given matrix. + /// + /// The matrix to concatenate. + /// The combined matrix. + public virtual Matrix Append(Matrix right) + { + if (right == null) + { + throw new ArgumentNullException("right"); + } + + if (right.RowCount != RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); + } + + Matrix result = CreateMatrix(RowCount, ColumnCount + right.ColumnCount); + Append(right, result); + return result; + } + + /// + /// Concatenates this matrix with the given matrix and places the result into the result matrix. + /// + /// The matrix to concatenate. + /// The combined matrix. + public virtual void Append(Matrix right, Matrix result) + { + if (right == null) + { + throw new ArgumentNullException("right"); + } + + if (right.RowCount != RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); + } + + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (result.ColumnCount != (ColumnCount + right.ColumnCount) || result.RowCount != RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); + } + + CommonParallel.Invoke( + () => + { + for (var i = 0; i < this.RowCount; i++) + { + for (var j = 0; j < this.ColumnCount; j++) + { + result.At(i, j, At(i, j)); + } + } + }, + () => + { + for (var i = 0; i < this.RowCount; i++) + { + for (var j = 0; j < right.ColumnCount; j++) + { + result.At(i, j + ColumnCount, right.At(i, j)); + } + } + }); + } + + /// + /// Stacks this matrix on top of the given matrix and places the result into the result matrix. + /// + /// The matrix to stack this matrix upon. + /// The combined matrix. + /// If lower is . + /// If upper.Columns != lower.Columns. + public virtual Matrix Stack(Matrix lower) + { + if (lower == null) + { + throw new ArgumentNullException("lower"); + } + + if (lower.ColumnCount != ColumnCount) + { + throw new ArgumentException("lower", Resources.ArgumentMatrixSameColumnDimension); + } + + Matrix result = CreateMatrix(RowCount + lower.RowCount, ColumnCount); + Stack(lower, result); + return result; + } + + /// + /// Stacks this matrix on top of the given matrix and places the result into the result matrix. + /// + /// The matrix to stack this matrix upon. + /// The combined matrix. + /// If lower is . + /// If upper.Columns != lower.Columns. + public virtual void Stack(Matrix lower, Matrix result) + { + if (lower == null) + { + throw new ArgumentNullException("lower"); + } + + if (lower.ColumnCount != ColumnCount) + { + throw new ArgumentException("lower", Resources.ArgumentMatrixSameColumnDimension); + } + + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (result.RowCount != (RowCount + lower.RowCount) || result.ColumnCount != ColumnCount) + { + throw new ArgumentException("result", Resources.ArgumentMatrixDimensions); + } + + CommonParallel.Invoke( + () => + { + for (var i = 0; i < this.RowCount; i++) + { + for (var j = 0; j < this.ColumnCount; j++) + { + result.At(i, j, At(i, j)); + } + } + }, + () => + { + for (var i = 0; i < lower.RowCount; i++) + { + for (var j = 0; j < this.ColumnCount; j++) + { + result.At(i + RowCount, j, lower.At(i, j)); + } + } + }); + } + + /// + /// Diagonally stacks his matrix on top of the given matrix. The new matrix is a M-by-N matrix, + /// where M = this.Rows + lower.Rows and N = this.Columns + lower.Columns. + /// The values of off the off diagonal matrices/blocks are set to zero. + /// + /// The lower, right matrix. + /// If lower is . + /// the combined matrix + public virtual Matrix DiagonalStack(Matrix lower) + { + if (lower == null) + { + throw new ArgumentNullException("lower"); + } + + Matrix result = CreateMatrix(RowCount + lower.RowCount, ColumnCount + lower.ColumnCount); + DiagonalStack(lower, result); + return result; + } + + /// + /// Diagonally stacks his matrix on top of the given matrix and places the combined matrix into the result matrix. + /// + /// The lower, right matrix. + /// The combined matrix + /// If lower is . + /// If the result matrix is . + /// If the result matrix's dimensions are not (this.Rows + lower.rows) x (this.Columns + lower.Columns). + public virtual void DiagonalStack(Matrix lower, Matrix result) + { + if (lower == null) + { + throw new ArgumentNullException("lower"); + } + + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (result.RowCount != RowCount + lower.RowCount || result.ColumnCount != ColumnCount + lower.ColumnCount) + { + throw new ArgumentException("result", Resources.ArgumentMatrixDimensions); + } + + CommonParallel.Invoke( + () => + { + for (var i = 0; i < this.RowCount; i++) + { + for (var j = 0; j < this.ColumnCount; j++) + { + result.At(i, j, At(i, j)); + } + } + }, + () => + { + for (var i = 0; i < lower.RowCount; i++) + { + for (var j = 0; j < lower.ColumnCount; j++) + { + result.At(i + RowCount, j + ColumnCount, lower.At(i, j)); + } + } + }); + } + } } \ No newline at end of file diff --git a/src/Numerics/LinearAlgebra/Double/Vector.cs b/src/Numerics/LinearAlgebra/Double/Vector.cs index 5c44bad7..b87d40fd 100644 --- a/src/Numerics/LinearAlgebra/Double/Vector.cs +++ b/src/Numerics/LinearAlgebra/Double/Vector.cs @@ -727,7 +727,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// If the n vector is non poisitive. public virtual Vector Random(int length, IContinuousDistribution randomDistribution) { - if (length < 0) + if (length < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); } @@ -753,7 +753,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// If the n vector is non poisitive. public virtual Vector Random(int length, IDiscreteDistribution randomDistribution) { - if (length < 0) + if (length < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); } diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs index ad5da2b2..042e9ef2 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs @@ -3,9 +3,7 @@ // 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 @@ -14,10 +12,8 @@ // 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 @@ -30,9 +26,10 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double { - using System; - using LinearAlgebra.Double; - using MbUnit.Framework; + using System; + using Distributions; + using LinearAlgebra.Double; + using MbUnit.Framework; public abstract partial class MatrixTests { @@ -43,13 +40,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanMultiplyWithScalar(double scalar) { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var clone = matrix.Clone(); clone.Multiply(scalar); - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j] * scalar, clone[i, j]); } @@ -59,13 +56,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Test] public void CanMultiplyWithVector() { - var A = testMatrices["Singular3x3"]; - var x = new DenseVector(new double[] { 1.0, 2.0, 3.0 }); + var A = this.testMatrices["Singular3x3"]; + var x = new DenseVector(new[] { 1.0, 2.0, 3.0 }); var y = A * x; Assert.AreEqual(A.RowCount, y.Count); - for (int i = 0; i < A.RowCount; i++) + for (var i = 0; i < A.RowCount; i++) { var ar = A.GetRow(i); var dot = ar * x; @@ -76,12 +73,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Test] public void CanMultiplyWithVectorIntoResult() { - var A = testMatrices["Singular3x3"]; - var x = new DenseVector(new double[] { 1.0, 2.0, 3.0 }); + var A = this.testMatrices["Singular3x3"]; + var x = new DenseVector(new[] { 1.0, 2.0, 3.0 }); var y = new DenseVector(3); A.Multiply(x, y); - for (int i = 0; i < A.RowCount; i++) + for (var i = 0; i < A.RowCount; i++) { var ar = A.GetRow(i); var dot = ar * x; @@ -92,15 +89,15 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Test] public void CanMultiplyWithVectorIntoResultWhenUpdatingInputArgument() { - var A = testMatrices["Singular3x3"]; - var x = new DenseVector(new double[] { 1.0, 2.0, 3.0 }); + var A = this.testMatrices["Singular3x3"]; + var x = new DenseVector(new[] { 1.0, 2.0, 3.0 }); var y = x; A.Multiply(x, x); Assert.AreSame(y, x); - y = new DenseVector(new double[] { 1.0, 2.0, 3.0 }); - for (int i = 0; i < A.RowCount; i++) + y = new DenseVector(new[] { 1.0, 2.0, 3.0 }); + for (var i = 0; i < A.RowCount; i++) { var ar = A.GetRow(i); var dot = ar * y; @@ -112,8 +109,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentNullException] public void MultiplyWithVectorIntoResultFailsWhenResultIsNull() { - var A = testMatrices["Singular3x3"]; - var x = new DenseVector(new double[] { 1.0, 2.0, 3.0 }); + var A = this.testMatrices["Singular3x3"]; + var x = new DenseVector(new[] { 1.0, 2.0, 3.0 }); Vector y = null; A.Multiply(x, y); } @@ -122,8 +119,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentException] public void MultiplyWithVectorIntoResultFailsWhenResultIsTooLarge() { - var A = testMatrices["Singular3x3"]; - var x = new DenseVector(new double[] { 1.0, 2.0, 3.0 }); + var A = this.testMatrices["Singular3x3"]; + var x = new DenseVector(new[] { 1.0, 2.0, 3.0 }); Vector y = new DenseVector(4); A.Multiply(x, y); } @@ -135,12 +132,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanOperatorLeftMultiplyWithScalar(double scalar) { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var clone = matrix * scalar; - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j] * scalar, clone[i, j]); } @@ -154,12 +151,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanOperatorRightMultiplyWithScalar(double scalar) { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var clone = matrix * scalar; - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j] * scalar, clone[i, j]); } @@ -173,13 +170,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanMultiplyWithScalarIntoResult(double scalar) { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var result = matrix.Clone(); matrix.Multiply(scalar, result); - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j] * scalar, result[i, j]); } @@ -190,7 +187,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentNullException))] public void MultiplyWithScalarIntoResultFailsWhenResultIsNull() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; Matrix result = null; matrix.Multiply(2.3, result); } @@ -199,8 +196,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentException] public void MultiplyWithScalarFailsWhenResultHasMoreRows() { - var matrix = testMatrices["Singular3x3"]; - Matrix result = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); + var matrix = this.testMatrices["Singular3x3"]; + var result = this.CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); matrix.Multiply(2.3, result); } @@ -208,8 +205,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentException] public void MultiplyWithScalarFailsWhenResultHasMoreColumns() { - var matrix = testMatrices["Singular3x3"]; - Matrix result = CreateMatrix(matrix.RowCount, matrix.ColumnCount + 1); + var matrix = this.testMatrices["Singular3x3"]; + var result = this.CreateMatrix(matrix.RowCount, matrix.ColumnCount + 1); matrix.Multiply(2.3, result); } @@ -218,7 +215,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public void OperatorLeftMultiplyWithScalarFailsWhenMatrixIsNull() { Matrix matrix = null; - Matrix result = 2.3 * matrix; + var result = 2.3 * matrix; } [Test] @@ -226,7 +223,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public void OperatorRightMultiplyWithScalarFailsWhenMatrixIsNull() { Matrix matrix = null; - Matrix result = matrix * 2.3; + var result = matrix * 2.3; } [Test] @@ -234,14 +231,14 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row("Singular4x4", "Square4x4")] public void CanAddMatrix(string mtxA, string mtxB) { - var A = testMatrices[mtxA]; - var B = testMatrices[mtxB]; + var A = this.testMatrices[mtxA]; + var B = this.testMatrices[mtxB]; - Matrix matrix = A.Clone(); + var matrix = A.Clone(); matrix.Add(B); - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j], A[i, j] + B[i, j]); } @@ -252,7 +249,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentNullException))] public void AddMatrixThrowsExceptionWhenArgumentIsNull() { - Matrix matrix = testMatrices["Singular4x4"]; + var matrix = this.testMatrices["Singular4x4"]; Matrix other = null; matrix.Add(other); } @@ -261,8 +258,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void AddMatrixThrowsExceptionArgumentHasTooFewColumns() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix other = testMatrices["Tall3x2"]; + var matrix = this.testMatrices["Singular3x3"]; + var other = this.testMatrices["Tall3x2"]; matrix.Add(other); } @@ -270,8 +267,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void AddMatrixThrowsExceptionArgumentHasTooFewRows() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix other = testMatrices["Wide2x3"]; + var matrix = this.testMatrices["Singular3x3"]; + var other = this.testMatrices["Wide2x3"]; matrix.Add(other); } @@ -280,15 +277,15 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row("Singular4x4", "Square4x4")] public void AddOperator(string mtxA, string mtxB) { - var A = testMatrices[mtxA]; - var B = testMatrices[mtxB]; - - Matrix result = A + B; - for (int i = 0; i < A.RowCount; i++) + var A = this.testMatrices[mtxA]; + var B = this.testMatrices[mtxB]; + + var result = A + B; + for (var i = 0; i < A.RowCount; i++) { - for (int j = 0; j < A.ColumnCount; j++) + for (var j = 0; j < A.ColumnCount; j++) { - Assert.AreEqual(result[i,j], A[i, j] + B[i, j]); + Assert.AreEqual(result[i, j], A[i, j] + B[i, j]); } } } @@ -298,35 +295,35 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public void AddOperatorThrowsExceptionWhenLeftsideIsNull() { Matrix matrix = null; - Matrix other = testMatrices["Singular3x3"]; - Matrix result = matrix + other; + var other = this.testMatrices["Singular3x3"]; + var result = matrix + other; } [Test] [ExpectedException(typeof(ArgumentNullException))] public void AddOperatorThrowsExceptionWhenRightsideIsNull() { - Matrix matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; Matrix other = null; - Matrix result = matrix + other; + var result = matrix + other; } [Test] [ExpectedException(typeof(ArgumentOutOfRangeException))] public void AddOperatorThrowsExceptionWhenRightsideHasTooFewColumns() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix other = testMatrices["Tall3x2"]; - Matrix result = matrix + other; + var matrix = this.testMatrices["Singular3x3"]; + var other = this.testMatrices["Tall3x2"]; + var result = matrix + other; } [Test] [ExpectedException(typeof(ArgumentOutOfRangeException))] public void AddOperatorThrowsExceptionWhenRightsideHasTooFewRows() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix other = testMatrices["Wide2x3"]; - Matrix result = matrix + other; + var matrix = this.testMatrices["Singular3x3"]; + var other = this.testMatrices["Wide2x3"]; + var result = matrix + other; } [Test] @@ -334,14 +331,14 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row("Singular4x4", "Square4x4")] public void CanSubtractMatrix(string mtxA, string mtxB) { - var A = testMatrices[mtxA]; - var B = testMatrices[mtxB]; + var A = this.testMatrices[mtxA]; + var B = this.testMatrices[mtxB]; - Matrix matrix = A.Clone(); + var matrix = A.Clone(); matrix.Subtract(B); - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j], A[i, j] - B[i, j]); } @@ -352,7 +349,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentNullException))] public void SubtractMatrixThrowsExceptionWhenRightSideIsNull() { - Matrix matrix = testMatrices["Singular4x4"]; + var matrix = this.testMatrices["Singular4x4"]; Matrix other = null; matrix.Subtract(other); } @@ -361,8 +358,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void SubtractMatrixThrowsExceptionWhenRightSideHasTooFewColumns() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix other = testMatrices["Tall3x2"]; + var matrix = this.testMatrices["Singular3x3"]; + var other = this.testMatrices["Tall3x2"]; matrix.Subtract(other); } @@ -370,8 +367,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void SubtractMatrixThrowsExceptionWhenRightSideHasTooFewRows() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix other = testMatrices["Wide2x3"]; + var matrix = this.testMatrices["Singular3x3"]; + var other = this.testMatrices["Wide2x3"]; matrix.Subtract(other); } @@ -380,13 +377,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row("Singular4x4", "Square4x4")] public void SubtractOperator(string mtxA, string mtxB) { - var A = testMatrices[mtxA]; - var B = testMatrices[mtxB]; + var A = this.testMatrices[mtxA]; + var B = this.testMatrices[mtxB]; - Matrix result = A - B; - for (int i = 0; i < A.RowCount; i++) + var result = A - B; + for (var i = 0; i < A.RowCount; i++) { - for (int j = 0; j < A.ColumnCount; j++) + for (var j = 0; j < A.ColumnCount; j++) { Assert.AreEqual(result[i, j], A[i, j] - B[i, j]); } @@ -398,35 +395,35 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public void SubtractOperatorThrowsExceptionWhenLeftsideIsNull() { Matrix matrix = null; - Matrix other = testMatrices["Singular3x3"]; - Matrix result = matrix - other; + var other = this.testMatrices["Singular3x3"]; + var result = matrix - other; } [Test] [ExpectedException(typeof(ArgumentNullException))] public void SubtractOperatorThrowsExceptionWhenRightsideIsNull() { - Matrix matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; Matrix other = null; - Matrix result = matrix - other; + var result = matrix - other; } [Test] [ExpectedException(typeof(ArgumentOutOfRangeException))] public void SubtractOperatorThrowsExceptionWhenRightsideHasTooFewColumns() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix other = testMatrices["Tall3x2"]; - Matrix result = matrix - other; + var matrix = this.testMatrices["Singular3x3"]; + var other = this.testMatrices["Tall3x2"]; + var result = matrix - other; } [Test] [ExpectedException(typeof(ArgumentOutOfRangeException))] public void SubtractOperatorThrowsExceptionWhenRightsideHasTooFewRows() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix other = testMatrices["Wide2x3"]; - Matrix result = matrix - other; + var matrix = this.testMatrices["Singular3x3"]; + var other = this.testMatrices["Wide2x3"]; + var result = matrix - other; } [Test] @@ -438,16 +435,16 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanMultiplyMatrixWithMatrix(string nameA, string nameB) { - Matrix A = testMatrices[nameA]; - Matrix B = testMatrices[nameB]; - Matrix C = A * B; + var A = this.testMatrices[nameA]; + var B = this.testMatrices[nameB]; + var C = A * B; Assert.AreEqual(C.RowCount, A.RowCount); Assert.AreEqual(C.ColumnCount, B.ColumnCount); - for (int i = 0; i < C.RowCount; i++) + for (var i = 0; i < C.RowCount; i++) { - for (int j = 0; j < C.ColumnCount; j++) + for (var j = 0; j < C.ColumnCount; j++) { AssertHelpers.AlmostEqual(A.GetRow(i) * B.GetColumn(j), C[i, j], 15); } @@ -458,9 +455,9 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentException))] public void MultiplyMatrixMatrixFailsWhenSizesAreIncompatible() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix other = testMatrices["Wide2x3"]; - Matrix result = matrix * other; + var matrix = this.testMatrices["Singular3x3"]; + var other = this.testMatrices["Wide2x3"]; + var result = matrix * other; } [Test] @@ -468,17 +465,17 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public void MultiplyMatrixMatrixFailsWhenLeftArgumentIsNull() { Matrix matrix = null; - Matrix other = testMatrices["Wide2x3"]; - Matrix result = matrix * other; + var other = this.testMatrices["Wide2x3"]; + var result = matrix * other; } [Test] [ExpectedException(typeof(ArgumentNullException))] public void MultiplyMatrixMatrixFailsWhenRightArgumentIsNull() { - Matrix matrix = testMatrices["Wide2x3"]; + var matrix = this.testMatrices["Wide2x3"]; Matrix other = null; - Matrix result = matrix * other; + var result = matrix * other; } [Test] @@ -490,17 +487,17 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanMultiplyMatrixWithMatrixIntoResult(string nameA, string nameB) { - Matrix A = testMatrices[nameA]; - Matrix B = testMatrices[nameB]; - Matrix C = CreateMatrix(A.RowCount, B.ColumnCount); + var A = this.testMatrices[nameA]; + var B = this.testMatrices[nameB]; + var C = this.CreateMatrix(A.RowCount, B.ColumnCount); A.Multiply(B, C); Assert.AreEqual(C.RowCount, A.RowCount); Assert.AreEqual(C.ColumnCount, B.ColumnCount); - for (int i = 0; i < C.RowCount; i++) + for (var i = 0; i < C.RowCount; i++) { - for (int j = 0; j < C.ColumnCount; j++) + for (var j = 0; j < C.ColumnCount; j++) { AssertHelpers.AlmostEqual(A.GetRow(i) * B.GetColumn(j), C[i, j], 15); } @@ -516,14 +513,14 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanNegate(string name) { - var matrix = testMatrices[name]; + var matrix = this.testMatrices[name]; var copy = matrix.Clone(); copy.Negate(); - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(-matrix[i, j], copy[i, j]); } @@ -539,14 +536,14 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanNegateIntoResult(string name) { - var matrix = testMatrices[name]; + var matrix = this.testMatrices[name]; var copy = matrix.Clone(); matrix.Negate(copy); - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(-matrix[i, j], copy[i, j]); } @@ -557,7 +554,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentNullException] public void NegateIntoResultFailsWhenResultIsNull() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; Matrix copy = null; matrix.Negate(copy); } @@ -566,8 +563,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentException] public void NegateIntoResultFailsWhenResultHasMoreRows() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix target = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); + var matrix = this.testMatrices["Singular3x3"]; + var target = this.CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); matrix.Negate(target); } @@ -575,242 +572,248 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentException] public void NegateIntoResultFailsWhenResultHasMoreColumns() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix target = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); + var matrix = this.testMatrices["Singular3x3"]; + var target = this.CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); matrix.Negate(target); } + [Test] - public void Append() + public void KroneckerProduct() { - Matrix left = testMatrices["Singular3x3"]; - Matrix right = testMatrices["Tall3x2"]; - Matrix result = left.Append(right); - Assert.AreEqual(left.ColumnCount + right.ColumnCount, result.ColumnCount); - Assert.AreEqual(left.RowCount, right.RowCount); - - for (int i = 0; i < result.RowCount; i++) + var A = this.testMatrices["Wide2x3"]; + var B = this.testMatrices["Square3x3"]; + var result = this.CreateMatrix(A.RowCount * B.RowCount, A.ColumnCount * B.ColumnCount); + A.KroneckerProduct(B, result); + for (var i = 0; i < A.RowCount; i++) { - for (int j = 0; j < result.ColumnCount; j++) + for (var j = 0; j < A.ColumnCount; j++) { - if (j < left.ColumnCount) + for (var ii = 0; ii < B.RowCount; ii++) { - Assert.AreEqual(left[i, j], result[i, j]); - } - else - { - Assert.AreEqual(right[i, j - left.ColumnCount], result[i, j]); + for (var jj = 0; jj < B.ColumnCount; jj++) + { + Assert.AreEqual(result[i * B.RowCount + ii, j * B.ColumnCount + jj], A[i, j] * B[ii, jj]); + } } } } } [Test] - [ExpectedArgumentNullException] - public void AppendWithRightParameterNullShouldThrowException() + public void KroneckerProductResult() { - Matrix left = testMatrices["Square3x3"]; - Matrix right = null; - left.Append(right); - } - - [Test] - [ExpectedArgumentNullException] - public void AppendWithResultParameterNullShouldThrowException() - { - Matrix left = testMatrices["Square3x3"]; - Matrix right = testMatrices["Tall3x2"]; - Matrix result = null; - left.Append(right, result); + var A = this.testMatrices["Wide2x3"]; + var B = this.testMatrices["Square3x3"]; + var result = A.KroneckerProduct(B); + for (var i = 0; i < A.RowCount; i++) + { + for (var j = 0; j < A.ColumnCount; j++) + { + for (var ii = 0; ii < B.RowCount; ii++) + { + for (var jj = 0; jj < B.ColumnCount; jj++) + { + Assert.AreEqual(result[i * B.RowCount + ii, j * B.ColumnCount + jj], A[i, j] * B[ii, jj]); + } + } + } + } } [Test] - [ExpectedArgumentException] - public void AppendingTwoMatricesWithDifferentRowCountShouldThrowException() + [Row(1)] + [Row(2)] + [Row(-4, ExpectedException = typeof(ArgumentOutOfRangeException))] + public void NormalizeColumns(int pValue) { - Matrix left = testMatrices["Square3x3"]; - Matrix right = testMatrices["Wide2x3"]; - Matrix result = left.Append(right); + var matrix = this.testMatrices["Singular3x3"]; + var result = matrix.NormalizeColumns(pValue); + for (var j = 0; j < result.ColumnCount; j++) + { + var col = result.GetColumn(j); + Assert.AreApproximatelyEqual(1.0, col.NormP(pValue), 10e-12); + } } [Test] - [ExpectedArgumentException] - public void AppendingWithInvalidResultMatrixColumnsShouldThrowException() + [Row(1)] + [Row(2)] + [Row(-3, ExpectedException = typeof(ArgumentOutOfRangeException))] + public void NormalizeRows(int pValue) { - Matrix left = testMatrices["Square3x3"]; - Matrix right = testMatrices["Tall3x2"]; - Matrix result = CreateMatrix(3, 2); - left.Append(right, result); + var matrix = this.testMatrices["Singular3x3"].NormalizeRows(pValue); + for (var i = 0; i < matrix.RowCount; i++) + { + var row = matrix.GetRow(i); + Assert.AreApproximatelyEqual(1.0, row.NormP(pValue), 10e-12); + } } [Test] - public void Stack() + public void PointwiseMultiplyResult() { - Matrix top = testMatrices["Square3x3"]; - Matrix bottom = testMatrices["Wide2x3"]; - Matrix result = top.Stack(bottom); - Assert.AreEqual(top.RowCount + bottom.RowCount, result.RowCount); - Assert.AreEqual(top.ColumnCount, result.ColumnCount); - - for (int i = 0; i < result.RowCount; i++) + foreach (var data in this.testMatrices.Values) { - for (int j = 0; j < result.ColumnCount; j++) + var other = data.Clone(); + var result = data.Clone(); + data.PointwiseMultiply(other, result); + for (var i = 0; i < data.RowCount; i++) { - if (i < top.RowCount) + for (var j = 0; j < data.ColumnCount; j++) { - Assert.AreEqual(result[i, j], top[i, j]); + Assert.AreEqual(data[i, j] * other[i, j], result[i, j]); } - else + } + + result = data.PointwiseMultiply(other); + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) { - Assert.AreEqual(result[i, j], bottom[i - top.RowCount, j]); + Assert.AreEqual(data[i, j] * other[i, j], result[i, j]); } } } } [Test] - [ExpectedArgumentNullException] - public void StackWithBottomParameterNullShouldThrowException() + [ExpectedException(typeof(ArgumentNullException))] + public void PointwiseMultiplyWithNullOtherShouldThrowException() { - Matrix top = testMatrices["Square3x3"]; - Matrix bottom = null; - Matrix result = CreateMatrix(top.RowCount + top.RowCount, top.ColumnCount); - top.Stack(bottom, result); + var matrix = this.testMatrices["Wide2x3"]; + Matrix other = null; + var result = matrix.Clone(); + matrix.PointwiseMultiply(other, result); } [Test] - [ExpectedArgumentNullException] - public void StackWithResultParameterNullShouldThrowException() + [ExpectedException(typeof(ArgumentNullException))] + public void PointwiseMultiplyWithResultNullShouldThrowException() { - Matrix top = testMatrices["Square3x3"]; - Matrix bottom = testMatrices["Square3x3"]; - Matrix result = null; - top.Stack(bottom, result); + var matrix = this.testMatrices["Wide2x3"]; + var other = matrix.Clone(); + matrix.PointwiseMultiply(other, null); } [Test] - [ExpectedArgumentException] - public void StackTwoMatricesWithDifferentColumnsShouldThrowException() + [ExpectedException(typeof(ArgumentException))] + public void PointwiseMultiplyWithInvalidOtherMatrixDimensionsShouldThrowException() { - Matrix top = testMatrices["Square3x3"]; - Matrix lower = testMatrices["Tall3x2"]; - Matrix result = CreateMatrix(top.RowCount + lower.RowCount, top.ColumnCount); - top.Stack(lower, result); + var matrix = this.testMatrices["Wide2x3"]; + var other = this.CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); + var result = matrix.Clone(); + matrix.PointwiseMultiply(other, result); } [Test] - [ExpectedArgumentException] - public void StackingWithInvalidResultMatrixRowsShouldThrowException() + [ExpectedException(typeof(ArgumentException))] + public void PointwiseMultiplyWithInvalidResultMatrixDimensionsShouldThrowException() { - Matrix top = testMatrices["Square3x3"]; - Matrix bottom = testMatrices["Wide2x3"]; - Matrix result = CreateMatrix(1, 3); - top.Stack(bottom, result); + var matrix = this.testMatrices["Wide2x3"]; + var other = matrix.Clone(); + var result = this.CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); + matrix.PointwiseMultiply(other, result); } [Test] - public void Trace() + public void PointwiseDivideIResult() { - Matrix matrix = testMatrices["Square3x3"]; - double trace = matrix.Trace(); - Assert.AreEqual(6.6, trace); + foreach (var data in this.testMatrices.Values) + { + var other = data.Clone(); + var result = data.Clone(); + data.PointwiseDivide(other, result); + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + Assert.AreEqual(data[i, j] / other[i, j], result[i, j]); + } + } + + result = data.PointwiseDivide(other); + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + Assert.AreEqual(data[i, j] / other[i, j], result[i, j]); + } + } + } } [Test] - [ExpectedArgumentException] - public void TraceOfNonSquareMatrixShouldThrowException() + [ExpectedException(typeof(ArgumentNullException))] + public void PointwiseDivideWithNullOtherShouldThrowException() { - Matrix matrix = testMatrices["Wide2x3"]; - double trace = matrix.Trace(); + var matrix = this.testMatrices["Wide2x3"]; + Matrix other = null; + var result = matrix.Clone(); + matrix.PointwiseDivide(other, result); } [Test] - public void DiagonalStack() + [ExpectedException(typeof(ArgumentNullException))] + public void PointwiseDivideWithResultNullShouldThrowException() { - Matrix top = testMatrices["Tall3x2"]; - Matrix bottom = testMatrices["Wide2x3"]; - Matrix result = top.DiagonalStack(bottom); - Assert.AreEqual(top.RowCount + bottom.RowCount, result.RowCount); - Assert.AreEqual(top.ColumnCount + bottom.ColumnCount, result.ColumnCount); + var matrix = this.testMatrices["Wide2x3"]; + var other = matrix.Clone(); + matrix.PointwiseDivide(other, null); + } - for (int i = 0; i < result.RowCount; i++) - { - for (int j = 0; j < result.ColumnCount; j++) - { - if (i < top.RowCount && j < top.ColumnCount) - { - Assert.AreEqual(top[i, j], result[i, j]); - } - else if (i >= top.RowCount && j >= top.ColumnCount) - { - Assert.AreEqual(bottom[i - top.RowCount, j - top.ColumnCount], result[i, j]); - } - else - { - Assert.AreEqual(0, result[i, j]); - } - } - } + [Test] + [ExpectedException(typeof(ArgumentException))] + public void PointwiseDivideWithInvalidOtherMatrixDimensionsShouldThrowException() + { + var matrix = this.testMatrices["Wide2x3"]; + var other = this.CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); + var result = matrix.Clone(); + matrix.PointwiseDivide(other, result); } [Test] - [ExpectedArgumentNullException] - public void DiagonalStackWithLowerNullShouldThrowException() + [ExpectedException(typeof(ArgumentException))] + public void PointwiseDivideWithInvalidResultMatrixDimensionsShouldThrowException() { - Matrix top = testMatrices["Square3x3"]; - Matrix lower = null; - top.DiagonalStack(lower); + var matrix = this.testMatrices["Wide2x3"]; + var other = matrix.Clone(); + var result = this.CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); + matrix.PointwiseDivide(other, result); } [Test] - public void DiagonalStackWithPassingResult() + [Row(0, ExpectedException = typeof(ArgumentException))] + [Row(-2, ExpectedException = typeof(ArgumentException))] + public void RandomWithNonPositiveNumberOfRowsShouldThrowException(int numberOfRows) { - Matrix top = testMatrices["Tall3x2"]; - Matrix bottom = testMatrices["Wide2x3"]; - Matrix result = CreateMatrix(top.RowCount + bottom.RowCount, top.ColumnCount + bottom.ColumnCount); - top.DiagonalStack(bottom, result); - Assert.AreEqual(top.RowCount + bottom.RowCount, result.RowCount); - Assert.AreEqual(top.ColumnCount + bottom.ColumnCount, result.ColumnCount); + var matrix = this.CreateMatrix(2, 3); + matrix = matrix.Random(numberOfRows, 4, new ContinuousUniform()); + } - for (int i = 0; i < result.RowCount; i++) - { - for (int j = 0; j < result.ColumnCount; j++) - { - if (i < top.RowCount && j < top.ColumnCount) - { - Assert.AreEqual(top[i, j], result[i, j]); - } - else if (i >= top.RowCount && j >= top.ColumnCount) - { - Assert.AreEqual(bottom[i - top.RowCount, j - top.ColumnCount], result[i, j]); - } - else - { - Assert.AreEqual(0, result[i, j]); - } - } - } + [Test] + [Row(0, ExpectedException = typeof(ArgumentException))] + [Row(-2, ExpectedException = typeof(ArgumentException))] + public void RandomWithNonPositiveNumberOfRowsShouldThrowException2(int numberOfRows) + { + var matrix = this.CreateMatrix(2, 3); + matrix = matrix.Random(numberOfRows, 4, new DiscreteUniform(0, 2)); } [Test] - [ExpectedArgumentNullException] - public void DiagonalStackWithResultNullShouldThrowException() + public void Trace() { - Matrix top = testMatrices["Square3x3"]; - Matrix lower = testMatrices["Wide2x3"]; - Matrix result = null; - top.DiagonalStack(lower,result); + var matrix = this.testMatrices["Square3x3"]; + var trace = matrix.Trace(); + Assert.AreEqual(6.6, trace); } [Test] [ExpectedArgumentException] - public void DiagonalStackWithInvalidResultMatrixShouldThrowException() + public void TraceOfNonSquareMatrixShouldThrowException() { - Matrix top = testMatrices["Square3x3"]; - Matrix lower = testMatrices["Wide2x3"]; - Matrix result = CreateMatrix(top.RowCount + lower.RowCount + 2, top.ColumnCount + lower.ColumnCount); - top.DiagonalStack(lower, result); - + var matrix = this.testMatrices["Wide2x3"]; + var trace = matrix.Trace(); } } } \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs index 2dba1e05..a3a59f7e 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs @@ -3,9 +3,7 @@ // 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 @@ -14,10 +12,8 @@ // 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 @@ -30,9 +26,9 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double { - using System; - using LinearAlgebra.Double; - using MbUnit.Framework; + using System; + using LinearAlgebra.Double; + using MbUnit.Framework; [TestFixture] public abstract partial class MatrixTests : MatrixLoader @@ -46,7 +42,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanCloneMatrix(string name) { - var matrix = CreateMatrix(testData2D[name]); + var matrix = this.CreateMatrix(this.testData2D[name]); var clone = matrix.Clone(); Assert.AreNotSame(matrix, clone); @@ -56,7 +52,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double { for (var j = 0; j < matrix.ColumnCount; j++) { - Assert.AreEqual(matrix[i,j], clone[i,j]); + Assert.AreEqual(matrix[i, j], clone[i, j]); } } } @@ -70,7 +66,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanCloneMatrixUsingICloneable(string name) { - var matrix = testMatrices[name]; + var matrix = this.testMatrices[name]; var clone = (Matrix)((ICloneable)matrix).Clone(); Assert.AreNotSame(matrix, clone); @@ -94,8 +90,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanCopyTo(string name) { - var matrix = testMatrices[name]; - var copy = CreateMatrix(matrix.RowCount, matrix.ColumnCount); + var matrix = this.testMatrices[name]; + var copy = this.CreateMatrix(matrix.RowCount, matrix.ColumnCount); matrix.CopyTo(copy); Assert.AreNotSame(matrix, copy); @@ -112,7 +108,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentNullException] public void CopyToFailsWhenTargetIsNull() { - Matrix matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; Matrix target = null; matrix.CopyTo(target); } @@ -121,8 +117,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentException] public void CopyToFailsWhenTargetHasMoreRows() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix target = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); + var matrix = this.testMatrices["Singular3x3"]; + var target = this.CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); matrix.CopyTo(target); } @@ -130,8 +126,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentException] public void CopyToFailsWhenTargetHasMoreColumns() { - Matrix matrix = testMatrices["Singular3x3"]; - Matrix target = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); + var matrix = this.testMatrices["Singular3x3"]; + var target = this.CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); matrix.CopyTo(target); } @@ -144,7 +140,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Test] public void CanCreateMatrix() { - var expected = CreateMatrix(5, 6); + var expected = this.CreateMatrix(5, 6); var actual = expected.CreateMatrix(5, 6); Assert.AreEqual(expected.GetType(), actual.GetType(), "Matrices are same type."); } @@ -158,9 +154,9 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanEquateMatrices(string name) { - var matrix1 = CreateMatrix(testData2D[name]); - var matrix2 = CreateMatrix(testData2D[name]); - var matrix3 = CreateMatrix(testData2D[name].GetLength(0), testData2D[name].GetLength(1)); + var matrix1 = this.CreateMatrix(this.testData2D[name]); + var matrix2 = this.CreateMatrix(this.testData2D[name]); + var matrix3 = this.CreateMatrix(this.testData2D[name].GetLength(0), this.testData2D[name].GetLength(1)); Assert.IsTrue(matrix1.Equals(matrix1)); Assert.IsTrue(matrix1.Equals(matrix2)); Assert.IsFalse(matrix1.Equals(matrix3)); @@ -176,7 +172,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedArgumentOutOfRangeException] public void ThrowsArgumentExceptionIfSizeIsNotPositive(int rows, int columns) { - var A = CreateMatrix(rows, columns); + var A = this.CreateMatrix(rows, columns); } [Test] @@ -187,7 +183,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row("Wide2x3")] public void TestingForEqualityWithNonMatrixReturnsFalse(string name) { - var matrix = CreateMatrix(testData2D[name]); + var matrix = this.CreateMatrix(this.testData2D[name]); Assert.IsFalse(matrix.Equals(2)); } @@ -199,8 +195,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row("Wide2x3")] public void CanTestForEqualityUsingObjectEquals(string name) { - var matrix1 = CreateMatrix(testData2D[name]); - var matrix2 = CreateMatrix(testData2D[name]); + var matrix1 = this.CreateMatrix(this.testData2D[name]); + var matrix2 = this.CreateMatrix(this.testData2D[name]); Assert.IsTrue(matrix1.Equals((object)matrix2)); } @@ -211,7 +207,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void RangeCheckFails(int i, int j, string name) { - var d = testMatrices[name][i, j]; + var d = this.testMatrices[name][i, j]; } [Test] @@ -223,11 +219,11 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Test] public void CanClearMatrix() { - Matrix matrix = (Matrix) testMatrices["Singular3x3"].Clone(); + var matrix = this.testMatrices["Singular3x3"].Clone(); matrix.Clear(); - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(0, matrix[i, j]); } @@ -241,11 +237,11 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row(2, "Square3x3")] public void CanGetRow(int rowIndex, string name) { - var matrix = testMatrices[name]; + var matrix = this.testMatrices[name]; var row = matrix.GetRow(rowIndex); Assert.AreEqual(matrix.ColumnCount, row.Count); - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[rowIndex, j], row[j]); } @@ -255,7 +251,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void GetRowThrowsArgumentOutOfRangeWithNegativeIndex() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; matrix.GetRow(-1); } @@ -263,7 +259,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void GetRowThrowsArgumentOutOfRangeWithOverflowingRowIndex() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; matrix.GetRow(matrix.RowCount); } @@ -274,12 +270,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row(2, "Square3x3")] public void CanGetRowWithResult(int rowIndex, string name) { - var matrix = testMatrices[name]; + var matrix = this.testMatrices[name]; var row = CreateVector(matrix.ColumnCount); matrix.GetRow(rowIndex, row); Assert.AreEqual(matrix.ColumnCount, row.Count); - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[rowIndex, j], row[j]); } @@ -289,7 +285,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentNullException))] public void GetRowWithResultFailsWhenResultIsNull() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; matrix.GetRow(0, null); } @@ -297,7 +293,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void GetRowWithResultThrowsArgumentOutOfRangeWithNegativeIndex() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var row = CreateVector(matrix.ColumnCount); matrix.GetRow(-1, row); } @@ -306,7 +302,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void GetRowWithResultThrowsArgumentOutOfRangeWithOverflowingRowIndex() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var row = CreateVector(matrix.ColumnCount); matrix.GetRow(matrix.RowCount, row); } @@ -318,11 +314,11 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row(2, 0, 3, "Square3x3")] public void CanGetRowWithRange(int rowIndex, int start, int length, string name) { - var matrix = testMatrices[name]; + var matrix = this.testMatrices[name]; var row = matrix.GetRow(rowIndex, start, length); Assert.AreEqual(length, row.Count); - for (int j = start; j < start + length; j++) + for (var j = start; j < start + length; j++) { Assert.AreEqual(matrix[rowIndex, j], row[j - start]); } @@ -332,7 +328,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentException))] public void GetRowWithRangeResultArgumentExeptionWhenLengthIsZero() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var result = CreateVector(matrix.ColumnCount); matrix.GetRow(0, 0, 0, result); } @@ -341,8 +337,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentException))] public void GetRowWithRangeFailsWithTooSmallResultVector() { - var matrix = testMatrices["Singular3x3"]; - var result = CreateVector(matrix.ColumnCount - 1); + var matrix = this.testMatrices["Singular3x3"]; + var result = this.CreateVector(matrix.ColumnCount - 1); matrix.GetRow(0, 0, 0, result); } @@ -353,11 +349,11 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row(2, "Square3x3")] public void CanGetColumn(int colIndex, string name) { - var matrix = testMatrices[name]; + var matrix = this.testMatrices[name]; var col = matrix.GetColumn(colIndex); Assert.AreEqual(matrix.RowCount, col.Count); - for (int j = 0; j < matrix.RowCount; j++) + for (var j = 0; j < matrix.RowCount; j++) { Assert.AreEqual(matrix[j, colIndex], col[j]); } @@ -367,7 +363,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void GetColumnThrowsArgumentOutOfRangeWithNegativeIndex() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; matrix.GetColumn(-1); } @@ -375,7 +371,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void GetColumnThrowsArgumentOutOfRangeWithOverflowingRowIndex() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; matrix.GetColumn(matrix.ColumnCount); } @@ -386,12 +382,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row(2, "Square3x3")] public void CanGetColumnWithResult(int colIndex, string name) { - var matrix = testMatrices[name]; + var matrix = this.testMatrices[name]; var col = CreateVector(matrix.RowCount); matrix.GetColumn(colIndex, col); Assert.AreEqual(matrix.RowCount, col.Count); - for (int j = 0; j < matrix.RowCount; j++) + for (var j = 0; j < matrix.RowCount; j++) { Assert.AreEqual(matrix[j, colIndex], col[j]); } @@ -401,7 +397,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentNullException))] public void GetColumnFailsWhenResultIsNull() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; matrix.GetColumn(0, null); } @@ -409,7 +405,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void GetColumnWithResultThrowsArgumentOutOfRangeWithNegativeIndex() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var column = CreateVector(matrix.ColumnCount); matrix.GetColumn(-1, column); } @@ -418,7 +414,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentOutOfRangeException))] public void GetColumnWithResultThrowsArgumentOutOfRangeWithOverflowingRowIndex() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var column = CreateVector(matrix.RowCount); matrix.GetRow(matrix.ColumnCount, column); } @@ -430,11 +426,11 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row(2, 0, 3, "Square3x3")] public void CanGetColumnWithRange(int colIndex, int start, int length, string name) { - var matrix = testMatrices[name]; + var matrix = this.testMatrices[name]; var col = matrix.GetColumn(colIndex, start, length); Assert.AreEqual(length, col.Count); - for (int j = start; j < start+length; j++) + for (var j = start; j < start + length; j++) { Assert.AreEqual(matrix[j, colIndex], col[j - start]); } @@ -444,7 +440,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentException))] public void GetColumnWithRangeResultArgumentExeptionWhenLengthIsZero() { - var matrix = testMatrices["Singular3x3"]; + var matrix = this.testMatrices["Singular3x3"]; var col = CreateVector(matrix.RowCount); matrix.GetColumn(0, 0, 0, col); } @@ -453,8 +449,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [ExpectedException(typeof(ArgumentException))] public void GetColumnWithRangeFailsWithTooSmallResultVector() { - var matrix = testMatrices["Singular3x3"]; - Vector result = CreateVector(matrix.RowCount - 1); + var matrix = this.testMatrices["Singular3x3"]; + var result = this.CreateVector(matrix.RowCount - 1); matrix.GetColumn(0, 0, matrix.RowCount, result); } @@ -465,12 +461,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row(2, "Square3x3")] public void CanSetRow(int rowIndex, string name) { - var matrix = (Matrix) testMatrices[name].Clone(); - matrix.SetRow(rowIndex, new DenseVector(matrix.ColumnCount, 0.0)); + var matrix = this.testMatrices[name].Clone(); + matrix.SetRow(rowIndex, CreateVector(matrix.ColumnCount)); - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { if (i == rowIndex) { @@ -478,7 +474,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } else { - Assert.AreEqual(testMatrices[name][i, j], matrix[i, j]); + Assert.AreEqual(this.testMatrices[name][i, j], matrix[i, j]); } } } @@ -491,12 +487,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Row(2, "Square3x3")] public void CanSetColumn(int colIndex, string name) { - var matrix = (Matrix)testMatrices[name].Clone(); - matrix.SetColumn(colIndex, new DenseVector(matrix.ColumnCount, 0.0)); + var matrix = this.testMatrices[name].Clone(); + matrix.SetColumn(colIndex, CreateVector(matrix.ColumnCount)); - for (int i = 0; i < matrix.RowCount; i++) + for (var i = 0; i < matrix.RowCount; i++) { - for (int j = 0; j < matrix.ColumnCount; j++) + for (var j = 0; j < matrix.ColumnCount; j++) { if (j == colIndex) { @@ -504,12 +500,217 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } else { - Assert.AreEqual(testMatrices[name][i, j], matrix[i, j]); + Assert.AreEqual(this.testMatrices[name][i, j], matrix[i, j]); + } + } + } + } + + [Test] + [Row("Singular3x3")] + [Row("Square3x3")] + [Row("Square4x4")] + [Row("Tall3x2")] + [Row("Wide2x3")] + [MultipleAsserts] + public void UpperTriangleResult(string name) + { + var data = this.testMatrices[name]; + var result = this.CreateMatrix(data.RowCount, data.ColumnCount); + var lower = data.GetUpperTriangle(); + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + if (i <= j) + { + Assert.AreEqual(data[i, j], + lower[i, j]); + } + else + { + Assert.AreEqual(0, lower[i, j]); } } } } + [Test] + [ExpectedArgumentNullException] + public void UpperTriangleWithResultNullShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + Matrix result = null; + data.GetUpperTriangle(result); + } + + [Test] + [ExpectedArgumentException] + public void UpperTriangleWithUnEqualRowsShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + var result = this.CreateMatrix(data.RowCount + 1, data.ColumnCount); + data.GetUpperTriangle(result); + } + + [Test] + [ExpectedArgumentException] + public void UpperTriangleWithUnEqualColumnsShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + var result = this.CreateMatrix(data.RowCount, data.ColumnCount + 1); + data.GetUpperTriangle(result); + } + + [Test] + public void StrictlyLowerTriangle() + { + foreach (var data in this.testMatrices.Values) + { + var lower = data.StrictlyLowerTriangle(); + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + if (i > j) + { + Assert.AreEqual(data[i, j], lower[i, j]); + } + else + { + Assert.AreEqual(0, lower[i, j]); + } + } + } + } + } + + [Test] + public void StrictlyLowerTriangleResult() + { + foreach (var data in this.testMatrices.Values) + { + var lower = this.CreateMatrix(data.RowCount, data.ColumnCount); + data.StrictlyLowerTriangle(lower); + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + if (i > j) + { + Assert.AreEqual(data[i, j], lower[i, j]); + } + else + { + Assert.AreEqual(0, lower[i, j]); + } + } + } + } + } + + [Test] + [ExpectedArgumentNullException] + public void StrictlyLowerTriangleWithNullParameterShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + Matrix lower = null; + data.StrictlyLowerTriangle(lower); + } + + [Test] + [ExpectedArgumentException] + public void StrictlyLowerTriangleWithInvalidColumnNumberShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + var lower = this.CreateMatrix(data.RowCount, data.ColumnCount + 1); + data.StrictlyLowerTriangle(lower); + } + + [Test] + [ExpectedArgumentException] + public void StrictlyLowerTriangleWithInvalidRowNumberShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + var lower = this.CreateMatrix(data.RowCount + 1, data.ColumnCount); + data.StrictlyLowerTriangle(lower); + } + + + [Test] + public void StrictlyUpperTriangle() + { + foreach (var data in this.testMatrices.Values) + { + var lower = data.StrictlyUpperTriangle(); + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + if (i < j) + { + Assert.AreEqual(data[i, j], lower[i, j]); + } + else + { + Assert.AreEqual(0, lower[i, j]); + } + } + } + } + } + + [Test] + public void StrictlyUpperTriangleResult() + { + foreach (var data in this.testMatrices.Values) + { + var lower = this.CreateMatrix(data.RowCount, data.ColumnCount); + data.StrictlyUpperTriangle(lower); + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + if (i < j) + { + Assert.AreEqual(data[i, j], lower[i, j]); + } + else + { + Assert.AreEqual(0, lower[i, j]); + } + } + } + } + } + + [Test] + [ExpectedArgumentNullException] + public void StrictlyUpperTriangleWithNullParameterShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + Matrix lower = null; + data.StrictlyUpperTriangle(lower); + } + + [Test] + [ExpectedArgumentException] + public void StrictlyUpperTriangleWithInvalidColumnNumberShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + var lower = this.CreateMatrix(data.RowCount, data.ColumnCount + 1); + data.StrictlyUpperTriangle(lower); + } + + [Test] + [ExpectedArgumentException] + public void StrictlyUpperTriangleWithInvalidRowNumberShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + var lower = this.CreateMatrix(data.RowCount + 1, data.ColumnCount); + data.StrictlyUpperTriangle(lower); + } + [Test] [Row("Singular3x3")] [Row("Square3x3")] @@ -519,7 +720,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanTransposeMatrix(string name) { - var matrix = CreateMatrix(testData2D[name]); + var matrix = this.CreateMatrix(this.testData2D[name]); var transpose = matrix.Transpose(); Assert.AreNotSame(matrix, transpose); @@ -534,6 +735,432 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } } + [Test] + [Row("Singular3x3", new double[] { 1, 2, 3 })] + [Row("Square3x3", new double[] { 1, 2, 3 })] + [Row("Tall3x2", new double[] { 1, 2, 3 })] + [Row("Wide2x3", new double[] { 1, 2 })] + [Row("Singular3x3", null, ExpectedException = typeof(ArgumentNullException))] + [Row("Singular3x3", new double[] { 1, 2, 3, 4, 5 }, ExpectedException = typeof(ArgumentException))] + public void SetColumnWithArray(string name, double[] column) + { + var matrix = this.testMatrices[name]; + for (var i = 0; i < matrix.ColumnCount; i++) + { + matrix.SetColumn(i, column); + for (var j = 0; j < matrix.RowCount; j++) + { + Assert.AreEqual(matrix[j, i], column[j]); + } + } + } + + [Test] + [ExpectedArgumentOutOfRangeException] + public void SetColumnArrayWithInvalidColumnIndexShouldThrowException() + { + var matrix = this.testMatrices["Square3x3"]; + double[] column = { 1, 2, 3 }; + matrix.SetColumn(-1, column); + } + + [Test] + [ExpectedArgumentOutOfRangeException] + public void SetColumnArrayWithInvalidColumnIndexShouldThrowException2() + { + var matrix = this.testMatrices["Square3x3"]; + double[] column = { 1, 2, 3 }; + matrix.SetColumn(matrix.ColumnCount + 1, column); + } + + [Test] + [Row("Singular3x3", new double[] { 1, 2, 3 })] + [Row("Square3x3", new double[] { 1, 2, 3 })] + [Row("Tall3x2", new double[] { 1, 2, 3 })] + [Row("Wide2x3", new double[] { 1, 2 })] + [Row("Singular3x3", new double[] { 1, 2, 3, 4, 5 }, ExpectedException = typeof(ArgumentException))] + public void SetColumnWithVector(string name, double[] column) + { + var matrix = this.testMatrices[name]; + var columnVector = CreateVector(column); + for (var i = 0; i < matrix.ColumnCount; i++) + { + matrix.SetColumn(i, column); + for (var j = 0; j < matrix.RowCount; j++) + { + Assert.AreEqual(matrix[j, i], columnVector[j]); + } + } + } + + [Test] + [ExpectedArgumentNullException] + public void SetColumnWithNullVectorShouldThrowException() + { + var matrix = this.testMatrices["Square3x3"]; + Vector columnVector = null; + matrix.SetColumn(1, columnVector); + } + + [Test] + [ExpectedArgumentOutOfRangeException] + public void SetColumnVectorWithInvalidColumnIndexShouldThrowException() + { + var matrix = this.testMatrices["Square3x3"]; + var column = this.CreateVector(new double[] { 1, 2, 3 }); + matrix.SetColumn(-1, column); + } + + [Test] + [ExpectedArgumentOutOfRangeException] + public void SetColumnVectorWithInvalidColumnIndexShouldThrowException2() + { + var matrix = this.testMatrices["Square3x3"]; + var column = this.CreateVector(new double[] { 1, 2, 3 }); + matrix.SetColumn(matrix.ColumnCount + 1, column); + } + + [Test] + public void InsertColumn() + { + var matrix = this.CreateMatrix(3, 3); + var column = CreateVector(matrix.RowCount); + for (var i = 0; i < column.Count; i++) + { + column[i] = i; + } + + for (var k = 0; k < matrix.ColumnCount + 1; k++) + { + var result = matrix.InsertColumn(k, column); + Assert.AreEqual(result.ColumnCount, matrix.ColumnCount + 1); + for (var col = 0; col < result.ColumnCount; col++) + { + for (var row = 0; row < result.RowCount; row++) + { + if (col == k) + { + Assert.AreEqual(row, result[row, col]); + } + else + { + Assert.AreEqual(0, result[row, col]); + } + } + } + } + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void InsertNullColumnShouldThrowExecption() + { + var matrix = this.testMatrices["Square3x3"]; + matrix.InsertColumn(0, null); + } + + [Test] + [Row(-1, ExpectedException = typeof(ArgumentOutOfRangeException))] + [Row(5, ExpectedException = typeof(ArgumentOutOfRangeException))] + public void InsertColumnWithInvalidColumnIndexShouldThrowExceptiopn(int columnIndex) + { + var matrix = this.CreateMatrix(3, 3); + var column = CreateVector(matrix.RowCount); + matrix.InsertColumn(columnIndex, column); + } + + public void InsertColumnWithInvalidNumberOfElementsShouldThrowException() + { + var matrix = this.CreateMatrix(3, 3); + var column = this.CreateVector(matrix.RowCount + 1); + matrix.InsertColumn(0, column); + } + + [Test] + [Row("Singular3x3", new double[] { 1, 2, 3 })] + [Row("Square3x3", new double[] { 1, 2, 3 })] + [Row("Tall3x2", new double[] { 1, 2 })] + [Row("Wide2x3", new double[] { 1, 2, 3 })] + [Row("Singular3x3", null, ExpectedException = typeof(ArgumentNullException))] + [Row("Singular3x3", new double[] { 1, 2, 3, 4, 5 }, ExpectedException = typeof(ArgumentException))] + public void SetRowWithArray(string name, double[] row) + { + var matrix = this.testMatrices[name]; + for (var i = 0; i < matrix.RowCount; i++) + { + matrix.SetRow(i, row); + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], row[j]); + } + } + } + + [Test] + [ExpectedArgumentOutOfRangeException] + public void SetRowArrayWithInvalidRowIndexShouldThrowException() + { + var matrix = this.testMatrices["Square3x3"]; + double[] row = { 1, 2, 3 }; + matrix.SetRow(-1, row); + } + + [Test] + [ExpectedArgumentOutOfRangeException] + public void SetRowArrayWithInvalidRowIndexShouldThrowException2() + { + var matrix = this.testMatrices["Square3x3"]; + double[] row = { 1, 2, 3 }; + matrix.SetRow(matrix.RowCount + 1, row); + } + + [Test] + [Row("Singular3x3", new double[] { 1, 2, 3 })] + [Row("Square3x3", new double[] { 1, 2, 3 })] + [Row("Tall3x2", new double[] { 1, 2 })] + [Row("Wide2x3", new double[] { 1, 2, 3 })] + [Row("Singular3x3", new double[] { 1, 2, 3, 4, 5 }, ExpectedException = typeof(ArgumentException))] + public void SetRowWithVector(string name, double[] row) + { + var matrix = this.testMatrices[name]; + var rowVector = CreateVector(row); + for (var i = 0; i < matrix.RowCount; i++) + { + matrix.SetRow(i, row); + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], rowVector[j]); + } + } + } + + [Test] + [ExpectedArgumentNullException] + public void SetRowWithNullVectorShouldThrowException() + { + var matrix = this.testMatrices["Square3x3"]; + Vector rowVector = null; + matrix.SetRow(1, rowVector); + } + + [Test] + [ExpectedArgumentOutOfRangeException] + public void SetRowVectorWithInvalidRowIndexShouldThrowException() + { + var matrix = this.testMatrices["Square3x3"]; + var row = this.CreateVector(new double[] { 1, 2, 3 }); + matrix.SetRow(-1, row); + } + + [Test] + [ExpectedArgumentOutOfRangeException] + public void SetRowVectorWithInvalidRowIndexShouldThrowException2() + { + var matrix = this.testMatrices["Square3x3"]; + var row = this.CreateVector(new double[] { 1, 2, 3 }); + matrix.SetRow(matrix.RowCount + 1, row); + } + + [Test] + [Row(0, 2, 0, 2)] + [Row(1, 1, 1, 1)] + [Row(0, 4, 0, 2, ExpectedException = typeof(ArgumentOutOfRangeException))] + [Row(0, 2, 0, 4, ExpectedException = typeof(ArgumentOutOfRangeException))] + [Row(4, 2, 0, 2, ExpectedException = typeof(ArgumentOutOfRangeException))] + [Row(0, 2, 4, 2, ExpectedException = typeof(ArgumentOutOfRangeException))] + [Row(-1, 2, 0, 2, ExpectedException = typeof(ArgumentOutOfRangeException))] + [Row(0, 2, -1, 2, ExpectedException = typeof(ArgumentOutOfRangeException))] + [Row(0, -1, 0, 2, ExpectedException = typeof(ArgumentException))] + [Row(0, 2, 0, -1, ExpectedException = typeof(ArgumentException))] + public void SetSubMatrix(int rowStart, int rowLength, int colStart, int colLength) + { + foreach (var matrix in this.testMatrices.Values) + { + var subMatrix = matrix.SubMatrix(0, 2, 0, 2); + subMatrix[0, 0] = 10.0; + subMatrix[0, 1] = -1.0; + subMatrix[1, 0] = 3.0; + subMatrix[1, 1] = 4.0; + matrix.SetSubMatrix(rowStart, rowLength, colStart, colLength, subMatrix); + + for (int i = rowStart, ii = 0; i < rowLength; i++, ii++) + { + for (int j = colStart, jj = 0; j < colLength; j++, jj++) + { + Assert.AreEqual(matrix[i, j], subMatrix[ii, jj]); + } + } + } + } + + [Test] + [ExpectedArgumentNullException] + public void SetSubMatrixWithNullSubMatrixShouldThrowException() + { + var data = this.testMatrices["Square3x3"]; + Matrix subMatrix = null; + data.SetSubMatrix(0, 2, 0, 2, subMatrix); + } + + [Test] + [Row("Square3x3", new double[] { 1, 2, 3 })] + [Row("Wide2x3", new double[] { 1, 2 })] + [Row("Wide2x3", new double[] { 1, 2, 3 }, ExpectedException = typeof(ArgumentException))] + [Row("Tall3x2", new double[] { 1, 2 })] + public void SetDiagonalVector(string name, double[] diagonal) + { + var matrix = this.testMatrices[name]; + var vector = CreateVector(diagonal); + matrix.SetDiagonal(vector); + + var min = Math.Min(matrix.ColumnCount, matrix.RowCount); + Assert.AreEqual(diagonal.Length, min); + + for (var i = 0; i < vector.Count; i++) + { + Assert.AreEqual(vector[i], matrix[i, i]); + } + } + + [Test] + [ExpectedArgumentNullException] + public void SetDiagonalWithNullVectorParameterShouldThrowException() + { + var matrix = this.testMatrices["Square3x3"]; + Vector vector = null; + matrix.SetDiagonal(vector); + } + + [Test] + [Row("Square3x3", new double[] { 1, 2, 3 })] + [Row("Wide2x3", new double[] { 1, 2 })] + [Row("Wide2x3", new double[] { 1, 2, 3 }, ExpectedException = typeof(ArgumentException))] + [Row("Tall3x2", new double[] { 1, 2 })] + [Row("Square3x3", null, ExpectedException = typeof(ArgumentNullException))] + public void SetDiagonalArray(string name, double[] diagonal) + { + var matrix = this.testMatrices[name]; + matrix.SetDiagonal(diagonal); + var min = Math.Min(matrix.ColumnCount, matrix.RowCount); + Assert.AreEqual(diagonal.Length, min); + for (var i = 0; i < diagonal.Length; i++) + { + Assert.AreEqual(diagonal[i], matrix[i, i]); + } + } + + [Test] + public void InsertRow() + { + var matrix = this.CreateMatrix(3, 3); + var row = CreateVector(matrix.ColumnCount); + for (var i = 0; i < row.Count; i++) + { + row[i] = i; + } + + for (var insertedRowIndex = 0; insertedRowIndex < matrix.RowCount + 1; insertedRowIndex++) + { + var result = matrix.InsertRow(insertedRowIndex, row); + Assert.AreEqual(result.RowCount, matrix.ColumnCount + 1); + for (var i = 0; i < result.RowCount; i++) + { + for (var j = 0; j < result.ColumnCount; j++) + { + if (i == insertedRowIndex) + { + Assert.AreEqual(row[j], result[i, j]); + } + else + { + Assert.AreEqual(0, result[i, j]); + } + } + } + } + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void InsertNullRowShouldThrowExecption() + { + var matrix = this.testMatrices["Square3x3"]; + matrix.InsertRow(0, null); + } + + [Test] + [Row(-1, ExpectedException = typeof(ArgumentOutOfRangeException))] + [Row(5, ExpectedException = typeof(ArgumentOutOfRangeException))] + public void InsertRowWithInvalidRowIndexShouldThrowExceptiopn(int rowIndex) + { + var matrix = this.CreateMatrix(3, 3); + var row = CreateVector(matrix.ColumnCount); + matrix.InsertRow(rowIndex, row); + } + + public void InsertRowWithInvalidNumberOfElementsShouldThrowException() + { + var matrix = this.CreateMatrix(3, 3); + var row = this.CreateVector(matrix.ColumnCount + 1); + matrix.InsertRow(0, row); + } + + [Test] + public void ToArray() + { + foreach (var data in this.testMatrices.Values) + { + var array = data.ToArray(); + Assert.AreEqual(data.RowCount, array.GetLength(0)); + Assert.AreEqual(data.ColumnCount, array.GetLength(1)); + + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + Assert.AreEqual(data[i, j], array[i, j]); + } + } + } + } + + [Test] + public void ToColumnWiseArray() + { + foreach (var data in this.testMatrices.Values) + { + var array = data.ToColumnWiseArray(); + Assert.AreEqual(data.RowCount * data.ColumnCount, array.Length); + + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + Assert.AreEqual(data[i, j], array[j * data.RowCount + i]); + } + } + } + } + + [Test] + public void ToRowWiseArray() + { + foreach (var data in this.testMatrices.Values) + { + var array = data.ToRowWiseArray(); + Assert.AreEqual(data.RowCount * data.ColumnCount, array.Length); + + for (var i = 0; i < data.RowCount; i++) + { + for (var j = 0; j < data.ColumnCount; j++) + { + Assert.AreEqual(data[i, j], array[i * data.ColumnCount + j]); + } + } + } + } + + [Test] [Row("Singular3x3")] [Row("Square3x3")] @@ -541,10 +1168,10 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanPermuteMatrixRows(string name) { - var matrix = CreateMatrix(testData2D[name]); - var matrixp = CreateMatrix(testData2D[name]); + var matrix = this.CreateMatrix(this.testData2D[name]); + var matrixp = this.CreateMatrix(this.testData2D[name]); - var permutation = new Permutation(new int[] { 2, 0, 1 }); + var permutation = new Permutation(new[] { 2, 0, 1 }); matrixp.PermuteRows(permutation); Assert.AreNotSame(matrix, matrixp); @@ -566,10 +1193,10 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [MultipleAsserts] public void CanPermuteMatrixColumns(string name) { - var matrix = CreateMatrix(testData2D[name]); - var matrixp = CreateMatrix(testData2D[name]); + var matrix = this.CreateMatrix(this.testData2D[name]); + var matrixp = this.CreateMatrix(this.testData2D[name]); - var permutation = new Permutation(new int[] { 2, 0, 1 }); + var permutation = new Permutation(new[] { 2, 0, 1 }); matrixp.PermuteColumns(permutation); Assert.AreNotSame(matrix, matrixp); @@ -583,5 +1210,221 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } } } + + [Test] + public void CanAppendMatrices() + { + var left = this.CreateMatrix(this.testData2D["Singular3x3"]); + var right = this.CreateMatrix(this.testData2D["Tall3x2"]); + var result = left.Append(right); + Assert.AreEqual(left.ColumnCount + right.ColumnCount, result.ColumnCount); + Assert.AreEqual(left.RowCount, right.RowCount); + + for (var i = 0; i < result.RowCount; i++) + { + for (var j = 0; j < result.ColumnCount; j++) + { + if (j < left.ColumnCount) + { + Assert.AreEqual(left[i, j], result[i, j]); + } + else + { + Assert.AreEqual(right[i, j - left.ColumnCount], result[i, j]); + } + } + } + } + + [Test] + [ExpectedArgumentNullException] + public void CanAppendWithRightParameterNullShouldThrowException() + { + var left = this.testMatrices["Square3x3"]; + Matrix right = null; + left.Append(right); + } + + [Test] + [ExpectedArgumentNullException] + public void CanAppendWithResultParameterNullShouldThrowException() + { + var left = this.testMatrices["Square3x3"]; + var right = this.testMatrices["Tall3x2"]; + Matrix result = null; + left.Append(right, result); + } + + [Test] + [ExpectedArgumentException] + public void AppendingTwoMatricesWithDifferentRowCountShouldThrowException() + { + var left = this.testMatrices["Square3x3"]; + var right = this.testMatrices["Wide2x3"]; + var result = left.Append(right); + } + + [Test] + [ExpectedArgumentException] + public void AppendingWithInvalidResultMatrixColumnsShouldThrowException() + { + var left = this.testMatrices["Square3x3"]; + var right = this.testMatrices["Tall3x2"]; + var result = this.CreateMatrix(3, 2); + left.Append(right, result); + } + + [Test] + public void CanStackMatrices() + { + var top = this.testMatrices["Square3x3"]; + var bottom = this.testMatrices["Wide2x3"]; + var result = top.Stack(bottom); + Assert.AreEqual(top.RowCount + bottom.RowCount, result.RowCount); + Assert.AreEqual(top.ColumnCount, result.ColumnCount); + + for (var i = 0; i < result.RowCount; i++) + { + for (var j = 0; j < result.ColumnCount; j++) + { + if (i < top.RowCount) + { + Assert.AreEqual(result[i, j], top[i, j]); + } + else + { + Assert.AreEqual(result[i, j], bottom[i - top.RowCount, j]); + } + } + } + } + + [Test] + [ExpectedArgumentNullException] + public void StackingWithBottomParameterNullShouldThrowException() + { + var top = this.testMatrices["Square3x3"]; + Matrix bottom = null; + var result = this.CreateMatrix(top.RowCount + top.RowCount, top.ColumnCount); + top.Stack(bottom, result); + } + + [Test] + [ExpectedArgumentNullException] + public void StackingWithResultParameterNullShouldThrowException() + { + var top = this.testMatrices["Square3x3"]; + var bottom = this.testMatrices["Square3x3"]; + Matrix result = null; + top.Stack(bottom, result); + } + + [Test] + [ExpectedArgumentException] + public void StackingTwoMatricesWithDifferentColumnsShouldThrowException() + { + var top = this.testMatrices["Square3x3"]; + var lower = this.testMatrices["Tall3x2"]; + var result = this.CreateMatrix(top.RowCount + lower.RowCount, top.ColumnCount); + top.Stack(lower, result); + } + + [Test] + [ExpectedArgumentException] + public void StackingWithInvalidResultMatrixRowsShouldThrowException() + { + var top = this.testMatrices["Square3x3"]; + var bottom = this.testMatrices["Wide2x3"]; + var result = this.CreateMatrix(1, 3); + top.Stack(bottom, result); + } + + [Test] + public void CanDiagonallyStackMatrics() + { + var top = this.testMatrices["Tall3x2"]; + var bottom = this.testMatrices["Wide2x3"]; + var result = top.DiagonalStack(bottom); + Assert.AreEqual(top.RowCount + bottom.RowCount, result.RowCount); + Assert.AreEqual(top.ColumnCount + bottom.ColumnCount, result.ColumnCount); + + for (var i = 0; i < result.RowCount; i++) + { + for (var j = 0; j < result.ColumnCount; j++) + { + if (i < top.RowCount && j < top.ColumnCount) + { + Assert.AreEqual(top[i, j], result[i, j]); + } + else if (i >= top.RowCount && j >= top.ColumnCount) + { + Assert.AreEqual(bottom[i - top.RowCount, j - top.ColumnCount], result[i, j]); + } + else + { + Assert.AreEqual(0, result[i, j]); + } + } + } + } + + [Test] + [ExpectedArgumentNullException] + public void DiagonalStackWithLowerNullShouldThrowException() + { + var top = this.testMatrices["Square3x3"]; + Matrix lower = null; + top.DiagonalStack(lower); + } + + [Test] + public void CanDiagonallyStackMatricesWithPassingResult() + { + var top = this.testMatrices["Tall3x2"]; + var bottom = this.testMatrices["Wide2x3"]; + var result = this.CreateMatrix(top.RowCount + bottom.RowCount, top.ColumnCount + bottom.ColumnCount); + top.DiagonalStack(bottom, result); + Assert.AreEqual(top.RowCount + bottom.RowCount, result.RowCount); + Assert.AreEqual(top.ColumnCount + bottom.ColumnCount, result.ColumnCount); + + for (var i = 0; i < result.RowCount; i++) + { + for (var j = 0; j < result.ColumnCount; j++) + { + if (i < top.RowCount && j < top.ColumnCount) + { + Assert.AreEqual(top[i, j], result[i, j]); + } + else if (i >= top.RowCount && j >= top.ColumnCount) + { + Assert.AreEqual(bottom[i - top.RowCount, j - top.ColumnCount], result[i, j]); + } + else + { + Assert.AreEqual(0, result[i, j]); + } + } + } + } + + [Test] + [ExpectedArgumentNullException] + public void DiagonalStackWithResultNullShouldThrowException() + { + var top = this.testMatrices["Square3x3"]; + var lower = this.testMatrices["Wide2x3"]; + Matrix result = null; + top.DiagonalStack(lower, result); + } + + [Test] + [ExpectedArgumentException] + public void DiagonalStackWithInvalidResultMatrixShouldThrowException() + { + var top = this.testMatrices["Square3x3"]; + var lower = this.testMatrices["Wide2x3"]; + var result = this.CreateMatrix(top.RowCount + lower.RowCount + 2, top.ColumnCount + lower.ColumnCount); + top.DiagonalStack(lower, result); + } } } \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs b/src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs index b2c25cf7..93212f72 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/VectorTests.cs @@ -300,7 +300,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public void CanFindAbsoluteMaximumIndex() { var source = this.CreateVector(this._data); - var expected = 0; + var expected = 4; var actual = source.AbsoluteMaximumIndex(); Assert.AreEqual(expected, actual); } @@ -309,7 +309,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public void CanFindAbsoluteMaximum() { var source = this.CreateVector(this._data); - double expected = 1; + double expected = 5; var actual = source.AbsoluteMaximum(); Assert.AreEqual(expected, actual); } @@ -418,7 +418,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public void RandomWithNumberOfElementsLessThanZeroShouldThrowException() { var vector = this.CreateVector(4); - vector = vector.Random(-3, new ContinuousUniform()); + vector = vector.Random(-2, new ContinuousUniform()); } protected abstract Vector CreateVector(int size);