diff --git a/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs index 5e8930d4..d5294bc6 100644 --- a/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/DenseMatrix.cs @@ -78,7 +78,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// /// /// The number of columns. - /// /// The value which we assign to each element of the matrix. public DenseMatrix(int rows, int columns, double value) : base(rows, columns) @@ -95,7 +95,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// will reference the one dimensional array and not copy it. /// /// The number of rows. - /// The number of columns.The number of columns. /// The one dimensional array to create this matrix from. This array should store the matrix in column-major order. public DenseMatrix(int rows, int columns, double[] array) : base(rows, columns) @@ -148,6 +148,18 @@ namespace MathNet.Numerics.LinearAlgebra.Double return new DenseMatrix(numberOfRows, numberOfColumns); } + /// + /// Creates a with a the given dimension. + /// + /// The size of the vector. + /// + /// A with the given dimension. + /// + public override Vector CreateVector(int size) + { + return new DenseVector(size); + } + /// /// Retrieves the requested element without range checking. /// diff --git a/src/Numerics/LinearAlgebra/Double/Matrix.cs b/src/Numerics/LinearAlgebra/Double/Matrix.cs index 03f2dce7..2ac79729 100644 --- a/src/Numerics/LinearAlgebra/Double/Matrix.cs +++ b/src/Numerics/LinearAlgebra/Double/Matrix.cs @@ -194,7 +194,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double if (RowCount != target.RowCount || ColumnCount != target.ColumnCount) { - throw new ArgumentException(Resources.ArgumentMatrixSameDimensions, "target"); + throw new ArgumentException(Resources.ArgumentMatrixDimensions, "target"); } // TODO this assumes that all entries matter; if "this" is a sparse matrix, @@ -225,6 +225,18 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// public abstract Matrix CreateMatrix(int numberOfRows, int numberOfColumns); + /// + /// Creates a with a the given dimension. + /// + /// The size of the vector. + /// + /// A with the given dimension. + /// + /// + /// Creates a vector of the same type as the current matrix. + /// + public abstract Vector CreateVector(int size); + /// /// Returns a that represents this instance. /// @@ -236,6 +248,211 @@ namespace MathNet.Numerics.LinearAlgebra.Double return ToString(null, null); } + /// + /// Copies a row into an . + /// + /// The row to copy. + /// A containing the copied elements. + /// If is negative, + /// or greater than or equal to the number of rows. + public virtual Vector GetRow(int index) + { + Vector ret = CreateVector(ColumnCount); + GetRow(index, 0, ColumnCount, ret); + return ret; + } + + /// + /// Copies a row into to the given . + /// + /// The row to copy. + /// The to copy the row into. + /// If the result vector is . + /// If is negative, + /// or greater than or equal to the number of rows. + /// If this.Columns != result.Count. + public virtual void GetRow(int index, Vector result) + { + GetRow(index, 0, ColumnCount, result); + } + + /// + /// Copies the requested row elements into a new . + /// + /// The row to copy elements from. + /// The column to start copying from. + /// The number of elements to copy. + /// A containing the requested elements. + /// 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 + length) >= Columns. + /// If is not positive. + public virtual Vector GetRow(int rowIndex, int columnIndex, int length) + { + Vector ret = CreateVector(length); + GetRow(rowIndex, columnIndex, length, ret); + return ret; + } + + /// + /// Copies the requested row elements into a new . + /// + /// The row to copy elements from. + /// The column to start copying from. + /// The number of elements to copy. + /// The to copy the column into. + /// If the result is . + /// If is negative, + /// or greater than or equal to the number of columns. + /// If is negative, + /// or greater than or equal to the number of rows. + /// If + + /// is greater than or equal to the number of rows. + /// If is not positive. + /// If result.Count < length. + public virtual void GetRow(int rowIndex, int columnIndex, int length, Vector result) + { + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (rowIndex >= RowCount || rowIndex < 0) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + if (columnIndex >= ColumnCount || columnIndex < 0) + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + + if (columnIndex + length > ColumnCount) + { + throw new ArgumentOutOfRangeException("length"); + } + + if (length < 1) + { + throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); + } + + if (result.Count < length) + { + throw new ArgumentException("result", Resources.ArgumentVectorsSameLength); + } + + for (int i = columnIndex, j = 0; i < columnIndex + length; i++, j++) + { + result[j] = At(rowIndex, i); + } + } + + /// + /// Copies a column into a new . + /// + /// The column to copy. + /// A containing the copied elements. + /// If is negative, + /// or greater than or equal to the number of columns. + public virtual Vector GetColumn(int index) + { + Vector result = CreateVector(RowCount); + GetColumn(index, 0, RowCount, result); + return result; + } + + /// + /// Copies a column into to the given . + /// + /// The column to copy. + /// The to copy the column into. + /// If the result is . + /// If is negative, + /// or greater than or equal to the number of columns. + /// If this.Rows != result.Count. + public virtual void GetColumn(int index, Vector result) + { + GetColumn(index, 0, RowCount, result); + } + + /// + /// Copies the requested column elements into a new . + /// + /// The column to copy elements from. + /// The row to start copying from. + /// The number of elements to copy. + /// A containing the requested elements. + /// If: + /// is negative, + /// or greater than or equal to the number of columns. + /// is negative, + /// or greater than or equal to the number of rows. + /// (rowIndex + length) >= Rows. + /// + /// If is not positive. + public virtual Vector GetColumn(int columnIndex, int rowIndex, int length) + { + Vector result = CreateVector(length); + GetColumn(columnIndex, rowIndex, length, result); + return result; + } + + /// + /// Copies the requested column elements into the given vector. + /// + /// The column to copy elements from. + /// The row to start copying from. + /// The number of elements to copy. + /// The to copy the column into. + /// If the result is . + /// If is negative, + /// or greater than or equal to the number of columns. + /// If is negative, + /// or greater than or equal to the number of rows. + /// If + + /// is greater than or equal to the number of rows. + /// If is not positive. + /// If result.Count < length. + public virtual void GetColumn(int columnIndex, int rowIndex, int length, Vector result) + { + if (result == null) + { + throw new ArgumentNullException("result"); + } + + if (columnIndex >= ColumnCount || columnIndex < 0) + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + if (rowIndex >= RowCount || rowIndex < 0) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (rowIndex + length > RowCount) + { + throw new ArgumentOutOfRangeException("length"); + } + + if (length < 1) + { + throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); + } + + if (result.Count < length) + { + throw new ArgumentException("result", Resources.ArgumentVectorsSameLength); + } + + for (int i = rowIndex, j = 0; i < rowIndex + length; i++, j++) + { + result[j] = At(i, columnIndex); + } + } + #region Implemented Interfaces #if !SILVERLIGHT diff --git a/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs index ff88a696..e9b4562f 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs @@ -17,6 +17,16 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double return new DenseMatrix(data); } + protected override Vector CreateVector(int size) + { + return new DenseVector(size); + } + + protected override Vector CreateVector(double[] data) + { + return new DenseVector(data); + } + [Test] public void CanCreateMatrixFrom1DArray() { diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs index 94224489..22a2476d 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs @@ -14,6 +14,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double protected abstract Matrix CreateMatrix(int rows, int columns); protected abstract Matrix CreateMatrix(double[,] data); + protected abstract Vector CreateVector(int size); + protected abstract Vector CreateVector(double[] data); [SetUp] public void SetupMatrices() @@ -115,7 +117,10 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double [Test] [Row(0, 2)] + [Row(2, 0)] + [Row(0, 0)] [Row(-1, 1)] + [Row(1, -1)] [ExpectedArgumentOutOfRangeException] public void ThrowsArgumentExceptionIfSizeIsNotPositive(int rows, int columns) { @@ -177,6 +182,230 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } } + [Test] + [Row(0, "Singular3x3")] + [Row(1, "Singular3x3")] + [Row(2, "Singular3x3")] + [Row(2, "Square3x3")] + public void CanGetRow(int rowIndex, string name) + { + var matrix = testMatrices[name]; + var row = matrix.GetRow(rowIndex); + + Assert.AreEqual(matrix.ColumnCount, row.Count); + for (int j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[rowIndex, j], row[j]); + } + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void GetRowThrowsArgumentOutOfRangeWithNegativeIndex() + { + var matrix = testMatrices["Singular3x3"]; + matrix.GetRow(-1); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void GetRowThrowsArgumentOutOfRangeWithOverflowingRowIndex() + { + var matrix = testMatrices["Singular3x3"]; + matrix.GetRow(matrix.RowCount); + } + + [Test] + [Row(0, "Singular3x3")] + [Row(1, "Singular3x3")] + [Row(2, "Singular3x3")] + [Row(2, "Square3x3")] + public void CanGetRowWithResult(int rowIndex, string name) + { + var matrix = 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++) + { + Assert.AreEqual(matrix[rowIndex, j], row[j]); + } + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void GetRowWithResultFailsWhenResultIsNull() + { + var matrix = testMatrices["Singular3x3"]; + matrix.GetRow(0, null); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void GetRowWithResultThrowsArgumentOutOfRangeWithNegativeIndex() + { + var matrix = testMatrices["Singular3x3"]; + var row = CreateVector(matrix.ColumnCount); + matrix.GetRow(-1, row); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void GetRowWithResultThrowsArgumentOutOfRangeWithOverflowingRowIndex() + { + var matrix = testMatrices["Singular3x3"]; + var row = CreateVector(matrix.ColumnCount); + matrix.GetRow(matrix.RowCount, row); + } + + [Test] + [Row(0, 0, 1, "Singular3x3")] + [Row(1, 1, 2, "Singular3x3")] + [Row(2, 0, 3, "Singular3x3")] + [Row(2, 0, 3, "Square3x3")] + public void CanGetRowWithRange(int rowIndex, int start, int length, string name) + { + var matrix = testMatrices[name]; + var row = matrix.GetRow(rowIndex, start, length); + + Assert.AreEqual(length, row.Count); + for (int j = start; j < start + length; j++) + { + Assert.AreEqual(matrix[rowIndex, j], row[j - start]); + } + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void GetRowWithRangeResultArgumentExeptionWhenLengthIsZero() + { + var matrix = testMatrices["Singular3x3"]; + var result = CreateVector(matrix.ColumnCount); + matrix.GetRow(0, 0, 0, result); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void GetRowWithRangeFailsWithTooSmallResultVector() + { + var matrix = testMatrices["Singular3x3"]; + var result = CreateVector(matrix.ColumnCount - 1); + matrix.GetRow(0, 0, 0, result); + } + + [Test] + [Row(0, "Singular3x3")] + [Row(1, "Singular3x3")] + [Row(2, "Singular3x3")] + [Row(2, "Square3x3")] + public void CanGetColumn(int colIndex, string name) + { + var matrix = testMatrices[name]; + var col = matrix.GetColumn(colIndex); + + Assert.AreEqual(matrix.RowCount, col.Count); + for (int j = 0; j < matrix.RowCount; j++) + { + Assert.AreEqual(matrix[j, colIndex], col[j]); + } + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void GetColumnThrowsArgumentOutOfRangeWithNegativeIndex() + { + var matrix = testMatrices["Singular3x3"]; + matrix.GetColumn(-1); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void GetColumnThrowsArgumentOutOfRangeWithOverflowingRowIndex() + { + var matrix = testMatrices["Singular3x3"]; + matrix.GetColumn(matrix.ColumnCount); + } + + [Test] + [Row(0, "Singular3x3")] + [Row(1, "Singular3x3")] + [Row(2, "Singular3x3")] + [Row(2, "Square3x3")] + public void CanGetColumnWithResult(int colIndex, string name) + { + var matrix = 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++) + { + Assert.AreEqual(matrix[j, colIndex], col[j]); + } + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void GetColumnFailsWhenResultIsNull() + { + var matrix = testMatrices["Singular3x3"]; + matrix.GetColumn(0, null); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void GetColumnWithResultThrowsArgumentOutOfRangeWithNegativeIndex() + { + var matrix = testMatrices["Singular3x3"]; + var column = CreateVector(matrix.ColumnCount); + matrix.GetColumn(-1, column); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void GetColumnWithResultThrowsArgumentOutOfRangeWithOverflowingRowIndex() + { + var matrix = testMatrices["Singular3x3"]; + var column = CreateVector(matrix.RowCount); + matrix.GetRow(matrix.ColumnCount, column); + } + + [Test] + [Row(0, 0, 1, "Singular3x3")] + [Row(1, 1, 2, "Singular3x3")] + [Row(2, 0, 3, "Singular3x3")] + [Row(2, 0, 3, "Square3x3")] + public void CanGetColumnWithRange(int colIndex, int start, int length, string name) + { + var matrix = testMatrices[name]; + var col = matrix.GetColumn(colIndex, start, length); + + Assert.AreEqual(length, col.Count); + for (int j = start; j < start+length; j++) + { + Assert.AreEqual(matrix[j, colIndex], col[j - start]); + } + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void GetColumnWithRangeResultArgumentExeptionWhenLengthIsZero() + { + var matrix = testMatrices["Singular3x3"]; + var col = CreateVector(matrix.RowCount); + matrix.GetColumn(0, 0, 0, col); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void GetColumnWithRangeFailsWithTooSmallResultVector() + { + var matrix = testMatrices["Singular3x3"]; + Vector result = CreateVector(matrix.RowCount - 1); + matrix.GetColumn(0, 0, matrix.RowCount, result); + } + #region Elementary operations [Test] [Row("Singular3x3", "Square3x3")] diff --git a/src/UnitTests/LinearAlgebraTests/Double/UserDefinedMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/UserDefinedMatrixTests.cs index a9893e0c..37a5f925 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/UserDefinedMatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/UserDefinedMatrixTests.cs @@ -30,6 +30,11 @@ { return new UserDefinedMatrix(numberOfRows, numberOfColumns); } + + public override Vector CreateVector(int size) + { + return new UserDefinedVector(size); + } } public class UserDefinedMatrixTests : MatrixTests @@ -43,5 +48,15 @@ { return new UserDefinedMatrix(data); } + + protected override Vector CreateVector(int size) + { + return new UserDefinedVector(size); + } + + protected override Vector CreateVector(double[] data) + { + return new UserDefinedVector(data); + } } }