diff --git a/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs b/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs index 745894f5..e3b7d47b 100644 --- a/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs +++ b/src/Numerics/LinearAlgebra/Double/Matrix.Arithmetic.cs @@ -602,5 +602,242 @@ namespace MathNet.Numerics.LinearAlgebra.Double return rightSide.LeftMultiply(leftSide); } + + /// + /// 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.For( + 0, + this.RowCount, + i => + { + for (int j = 0; j < this.ColumnCount; j++) + { + result.At(i, j, At(i, j)); + } + }); + + CommonParallel.For( + 0, + right.RowCount, + i => + { + for (int 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.For( + 0, + this.RowCount, + i => + { + for (int j = 0; j < this.ColumnCount; j++) + { + result.At(i, j, At(i, j)); + } + }); + + CommonParallel.For( + 0, + lower.RowCount, + i => + { + for (int j = 0; j < lower.ColumnCount; j++) + { + result.At(i + RowCount, j, lower.At(i, j)); + } + }); + } + + /// + /// Computes the trace of this matrix. + /// + /// The trace of this matrix + /// If the matrix is not square + public virtual double Trace() + { + if (RowCount != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + double t = 0.0; + for (int i = 0; i < RowCount; i++) + { + t += this[i, i]; + } + + return t; + } + + /// + /// 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.For( + 0, + this.RowCount, + i => + { + for (var j = 0; j < this.ColumnCount; j++) + { + result.At(i, j, At(i, j)); + } + }); + + CommonParallel.For( + 0, + 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 774358ce..07adaa61 100644 --- a/src/Numerics/LinearAlgebra/Double/Vector.cs +++ b/src/Numerics/LinearAlgebra/Double/Vector.cs @@ -548,6 +548,66 @@ namespace MathNet.Numerics.LinearAlgebra.Double result.Multiply(1.0 / scalar); } + /// + /// Pointwise multiplies this vector with another vector. + /// + /// The vector to pointwise multiply with this one. + /// If the other vector is . + /// If this vector and are not the same size. + /// A new vector that is the pointwise multiplication of this vector and . + public virtual Vector PointWiseMultiply(Vector other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (Count != other.Count) + { + throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + } + + Vector result = CreateVector(Count); + PointWiseMultiply(other, result); + return result; + } + + /// + /// Pointwise multiplies this vector with another vector and stores the result into the result vector. + /// + /// The vector to pointwise multiply with this one. + /// The vector to store the result of the pointwise multiplication. + /// If the other vector is . + /// If the result vector is . + /// If this vector and are not the same size. + /// If this vector and are not the same size. + public virtual void PointWiseMultiply(Vector other, Vector result) + { + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (Count != other.Count) + { + throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); + } + + if (Count != result.Count) + { + throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); + } + + CommonParallel.For( + 0, + this.Count, + index => result[index] = this[index] * other[index]); + } #endregion #region Arithmetic Operator Overloading diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs index fbef83e7..ad5da2b2 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs @@ -579,5 +579,238 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double Matrix target = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); matrix.Negate(target); } + + [Test] + public void Append() + { + 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++) + { + for (int 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 AppendWithRightParameterNullShouldThrowException() + { + 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); + } + + [Test] + [ExpectedArgumentException] + public void AppendingTwoMatricesWithDifferentRowCountShouldThrowException() + { + Matrix left = testMatrices["Square3x3"]; + Matrix right = testMatrices["Wide2x3"]; + Matrix result = left.Append(right); + } + + [Test] + [ExpectedArgumentException] + public void AppendingWithInvalidResultMatrixColumnsShouldThrowException() + { + Matrix left = testMatrices["Square3x3"]; + Matrix right = testMatrices["Tall3x2"]; + Matrix result = CreateMatrix(3, 2); + left.Append(right, result); + } + + [Test] + public void Stack() + { + 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++) + { + for (int 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 StackWithBottomParameterNullShouldThrowException() + { + Matrix top = testMatrices["Square3x3"]; + Matrix bottom = null; + Matrix result = CreateMatrix(top.RowCount + top.RowCount, top.ColumnCount); + top.Stack(bottom, result); + } + + [Test] + [ExpectedArgumentNullException] + public void StackWithResultParameterNullShouldThrowException() + { + Matrix top = testMatrices["Square3x3"]; + Matrix bottom = testMatrices["Square3x3"]; + Matrix result = null; + top.Stack(bottom, result); + } + + [Test] + [ExpectedArgumentException] + public void StackTwoMatricesWithDifferentColumnsShouldThrowException() + { + Matrix top = testMatrices["Square3x3"]; + Matrix lower = testMatrices["Tall3x2"]; + Matrix result = CreateMatrix(top.RowCount + lower.RowCount, top.ColumnCount); + top.Stack(lower, result); + } + + [Test] + [ExpectedArgumentException] + public void StackingWithInvalidResultMatrixRowsShouldThrowException() + { + Matrix top = testMatrices["Square3x3"]; + Matrix bottom = testMatrices["Wide2x3"]; + Matrix result = CreateMatrix(1, 3); + top.Stack(bottom, result); + } + + [Test] + public void Trace() + { + Matrix matrix = testMatrices["Square3x3"]; + double trace = matrix.Trace(); + Assert.AreEqual(6.6, trace); + } + + [Test] + [ExpectedArgumentException] + public void TraceOfNonSquareMatrixShouldThrowException() + { + Matrix matrix = testMatrices["Wide2x3"]; + double trace = matrix.Trace(); + } + + [Test] + public void DiagonalStack() + { + 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); + + 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] + [ExpectedArgumentNullException] + public void DiagonalStackWithLowerNullShouldThrowException() + { + Matrix top = testMatrices["Square3x3"]; + Matrix lower = null; + top.DiagonalStack(lower); + } + + [Test] + public void DiagonalStackWithPassingResult() + { + 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); + + 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] + [ExpectedArgumentNullException] + public void DiagonalStackWithResultNullShouldThrowException() + { + Matrix top = testMatrices["Square3x3"]; + Matrix lower = testMatrices["Wide2x3"]; + Matrix result = null; + top.DiagonalStack(lower,result); + } + + [Test] + [ExpectedArgumentException] + public void DiagonalStackWithInvalidResultMatrixShouldThrowException() + { + Matrix top = testMatrices["Square3x3"]; + Matrix lower = testMatrices["Wide2x3"]; + Matrix result = 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.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Double/VectorTests.Arithmetic.cs index f71a02d3..56dee3ae 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/VectorTests.Arithmetic.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/VectorTests.Arithmetic.cs @@ -726,5 +726,61 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double double d = dataA * dataB; } + + [Test] + public void PointWiseMultiply() + { + Vector vector1 = CreateVector(_data); + Vector vector2 = vector1.Clone(); + Vector result = CreateVector(vector1.Count); + vector1.PointWiseMultiply(vector2, result); + for (int i = 0; i < vector1.Count; i++) + { + Assert.AreEqual(_data[i] * _data[i], result[i]); + } + } + + [Test] + [ExpectedArgumentNullException] + public void PointWiseMultiplyWithOtherNullShouldThrowException() + { + Vector vector1 = CreateVector(_data); + Vector vector2 = null; + Vector result = CreateVector(vector1.Count); + vector1.PointWiseMultiply(vector2, result); + } + + [Test] + [ExpectedArgumentNullException] + public void PointWiseMultiplyWithResultNullShouldThrowException() + { + Vector vector1 = CreateVector(_data); + Vector vector2 = vector1.Clone(); + Vector result = null; + vector1.PointWiseMultiply(vector2, result); + } + + [Test] + [ExpectedArgumentException] + public void PointWiseMultiplyWithInvalidResultLengthShouldThrowException() + { + Vector vector1 = CreateVector(_data); + Vector vector2 = vector1.Clone(); + Vector result = CreateVector(vector1.Count + 1); + vector1.PointWiseMultiply(vector2, result); + } + + [Test] + public void PointWiseMultiplyWithResult() + { + Vector vector1 = CreateVector(_data); + Vector vector2 = vector1.Clone(); + Vector result = vector1.PointWiseMultiply(vector2); + for (int i = 0; i < vector1.Count; i++) + { + Assert.AreEqual(_data[i] * _data[i], result[i]); + } + } + } } \ No newline at end of file