diff --git a/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs index 19cdf881..04aba072 100644 --- a/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs @@ -181,5 +181,69 @@ namespace MathNet.Numerics.LinearAlgebra.Double { Data[column * RowCount + row] = value; } + + #region Elementary operations + /// + /// Adds another matrix to this matrix. The result will be written into this matrix. + /// + /// The matrix to add to this matrix. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override void Add(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixSameDimensions); + } + + DenseMatrix m = other as DenseMatrix; + if (m == null) + { + Parallel.For(0, RowCount, i => + Parallel.For(0, ColumnCount, j => + At(i, j, At(i, j) + other.At(i, j)))); + } + else + { + Control.LinearAlgebraProvider.AddArrays(Data, m.Data, Data); + } + } + + /// + /// Subtracts another matrix from this matrix. The result will be written into this matrix. + /// + /// The matrix to subtract. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override void Subtract(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixSameDimensions); + } + + DenseMatrix m = other as DenseMatrix; + if (m == null) + { + Parallel.For(0, RowCount, i => + Parallel.For(0, ColumnCount, j => + At(i, j, At(i, j) - other.At(i, j)))); + } + else + { + Control.LinearAlgebraProvider.SubtractArrays(Data, m.Data, Data); + } + } + #endregion } } diff --git a/src/Numerics/LinearAlgebra/Double/Matrix.cs b/src/Numerics/LinearAlgebra/Double/Matrix.cs index c5226e2b..e4bcd869 100644 --- a/src/Numerics/LinearAlgebra/Double/Matrix.cs +++ b/src/Numerics/LinearAlgebra/Double/Matrix.cs @@ -30,6 +30,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double { using System; using System.Text; + using Threading; using Properties; @@ -411,5 +412,117 @@ namespace MathNet.Numerics.LinearAlgebra.Double } #endregion + + #region Elementary operations + /// + /// Adds another matrix to this matrix. The result will be written into this matrix. + /// + /// The matrix to add to this matrix. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public virtual void Add(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixSameDimensions); + } + + Parallel.For(0, RowCount, i => + Parallel.For(0, ColumnCount, j => + At(i, j, At(i,j) + other.At(i,j)))); + } + + /// + /// Adds two matrices together and returns the results. + /// + /// This operator will allocate new memory for the result. It will + /// choose the representation of either or depending on which + /// is denser. + /// The left matrix to add. + /// The right matrix to add. + /// The result of the addition. + /// If and don't have the same dimensions. + /// If or is . + public static Matrix operator +(Matrix leftSide, Matrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount || leftSide.ColumnCount != rightSide.ColumnCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixSameDimensions); + } + + Matrix ret = leftSide.Clone(); + ret.Add(rightSide); + return ret; + } + + /// + /// Subtracts another matrix from this matrix. The result will be written into this matrix. + /// + /// The matrix to subtract. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public virtual void Subtract(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixSameDimensions); + } + + Parallel.For(0, RowCount, i => + Parallel.For(0, ColumnCount, j => + At(i, j, At(i, j) - other.At(i, j)))); + } + + /// + /// Subtracts two matrices together and returns the results. + /// + /// This operator will allocate new memory for the result. It will + /// choose the representation of either or depending on which + /// is denser. + /// The left matrix to subtract. + /// The right matrix to subtract. + /// The result of the addition. + /// If and don't have the same dimensions. + /// If or is . + public static Matrix operator -(Matrix leftSide, Matrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount || leftSide.ColumnCount != rightSide.ColumnCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixSameDimensions); + } + + Matrix ret = leftSide.Clone(); + ret.Subtract(rightSide); + return ret; + } + #endregion } } \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs index 3bd95a35..ff88a696 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs @@ -7,10 +7,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public class DenseMatrixTests : MatrixTests { - protected double[] SquareMatrix = new double[] { -1.1, 0.0, 1.0, -4.4, -2.2, 1.1, 2.1, 5.5, -3.3, 2.2, 6.2, 6.6, -4.4, 3.3, 4.3, -7.7 }; - protected int SquareMatrixRows = 4; - protected int SquareMatrixColumns = 4; - protected override Matrix CreateMatrix(int rows, int columns) { return new DenseMatrix(rows, columns); diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs index 41ed50a7..0b81e099 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs @@ -15,12 +15,13 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double protected abstract Matrix CreateMatrix(double[,] data); [SetUp] - public void SetupDistributions() + public void SetupMatrices() { testData2D = new Dictionary(); testData2D.Add("Singular3x3", new double[,] { { 1, 1, 2 }, { 1, 1, 2 }, { 1, 1, 2 } }); testData2D.Add("Square3x3", new double[,] { { -1.1, -2.2, -3.3 }, { 0, 1.1, 2.2 }, { -4.4, 5.5, 6.6 } }); testData2D.Add("Square4x4", new double[,] { { -1.1, -2.2, -3.3, -4.4 }, { 0, 1.1, 2.2, 3.3 }, { 1.0, 2.1, 6.2, 4.3 }, { -4.4, 5.5, 6.6, -7.7 } }); + testData2D.Add("Singular4x4", new double[,] { { -1.1, -2.2, -3.3, -4.4 }, { -1.1, -2.2, -3.3, -4.4 }, { -1.1, -2.2, -3.3, -4.4 }, { -1.1, -2.2, -3.3, -4.4 } }); testData2D.Add("Tall3x2", new double[,] { { -1.1, -2.2 }, { 0, 1.1 }, { -4.4, 5.5 } }); testData2D.Add("Wide2x3", new double[,] { { -1.1, -2.2, -3.3 }, { 0, 1.1, 2.2 } }); @@ -160,5 +161,207 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double public void MatrixGetHashCode() { } + + #region Elementary operations + [Test] + [Row("Singular3x3", "Square3x3")] + [Row("Singular4x4", "Square4x4")] + public void AddMatrix(string mtxA, string mtxB) + { + var A = testMatrices[mtxA]; + var B = testMatrices[mtxB]; + + Matrix matrix = A.Clone(); + matrix.Add(B); + for (int i = 0; i < matrix.RowCount; i++) + { + for (int j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], A[i, j] + B[i, j]); + } + } + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void AddMatrixThrowsExceptionWhenArgumentIsNull() + { + Matrix matrix = testMatrices["Singular4x4"]; + Matrix other = null; + matrix.Add(other); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void AddMatrixThrowsExceptionArgumentHasTooFewColumns() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = testMatrices["Tall3x2"]; + matrix.Add(other); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void AddMatrixThrowsExceptionArgumentHasTooFewRows() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = testMatrices["Wide2x3"]; + matrix.Add(other); + } + + [Test] + [Row("Singular3x3", "Square3x3")] + [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++) + { + for (int j = 0; j < A.ColumnCount; j++) + { + Assert.AreEqual(result[i,j], A[i, j] + B[i, j]); + } + } + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void AddOperatorThrowsExceptionWhenLeftsideIsNull() + { + Matrix matrix = null; + Matrix other = testMatrices["Singular3x3"]; + Matrix result = matrix + other; + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void AddOperatorThrowsExceptionWhenRightsideIsNull() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = null; + Matrix result = matrix + other; + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void AddOperatorThrowsExceptionWhenRightsideHasTooFewColumns() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = testMatrices["Tall3x2"]; + Matrix result = matrix + other; + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void AddOperatorThrowsExceptionWhenRightsideHasTooFewRows() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = testMatrices["Wide2x3"]; + Matrix result = matrix + other; + } + + [Test] + [Row("Singular3x3", "Square3x3")] + [Row("Singular4x4", "Square4x4")] + public void SubtractMatrix(string mtxA, string mtxB) + { + var A = testMatrices[mtxA]; + var B = testMatrices[mtxB]; + + Matrix matrix = A.Clone(); + matrix.Subtract(B); + for (int i = 0; i < matrix.RowCount; i++) + { + for (int j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], A[i, j] - B[i, j]); + } + } + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void SubtractMatrixThrowsExceptionWhenRightSideIsNull() + { + Matrix matrix = testMatrices["Singular4x4"]; + Matrix other = null; + matrix.Subtract(other); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void SubtractMatrixThrowsExceptionWhenRightSideHasTooFewColumns() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = testMatrices["Tall3x2"]; + matrix.Subtract(other); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void SubtractMatrixThrowsExceptionWhenRightSideHasTooFewRows() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = testMatrices["Wide2x3"]; + matrix.Subtract(other); + } + + [Test] + [Row("Singular3x3", "Square3x3")] + [Row("Singular4x4", "Square4x4")] + public void SubtractOperator(string mtxA, string mtxB) + { + var A = testMatrices[mtxA]; + var B = testMatrices[mtxB]; + + Matrix result = A - B; + for (int i = 0; i < A.RowCount; i++) + { + for (int j = 0; j < A.ColumnCount; j++) + { + Assert.AreEqual(result[i, j], A[i, j] - B[i, j]); + } + } + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void SubtractOperatorThrowsExceptionWhenLeftsideIsNull() + { + Matrix matrix = null; + Matrix other = testMatrices["Singular3x3"]; + Matrix result = matrix - other; + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void SubtractOperatorThrowsExceptionWhenRightsideIsNull() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = null; + Matrix result = matrix - other; + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void SubtractOperatorThrowsExceptionWhenRightsideHasTooFewColumns() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = testMatrices["Tall3x2"]; + Matrix result = matrix - other; + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void SubtractOperatorThrowsExceptionWhenRightsideHasTooFewRows() + { + Matrix matrix = testMatrices["Singular3x3"]; + Matrix other = testMatrices["Wide2x3"]; + Matrix result = matrix - other; + } + #endregion } } \ No newline at end of file