Browse Source

Added matrix multiplication

Added Matrix.GetRow
Added Matrix.GetColumn
Added Matrix.GetRow unit tests
Added Matrix.GetColumn unit tests
la-knuth
Jurgen Van Gael 17 years ago
parent
commit
1b20b266a3
  1. 16
      src/Numerics/LinearAlgebra/Double/DenseMatrix.cs
  2. 219
      src/Numerics/LinearAlgebra/Double/Matrix.cs
  3. 10
      src/UnitTests/LinearAlgebraTests/Double/DenseMatrixTests.cs
  4. 229
      src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs
  5. 15
      src/UnitTests/LinearAlgebraTests/Double/UserDefinedMatrixTests.cs

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

@ -78,7 +78,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// </param>
/// <param name="columns">
/// The number of columns.
/// </param
/// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param>
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.
/// </summary>
/// <param name="rows">The number of rows.</param>
/// <param name="columns">The number of columns.</param
/// <param name="columns">The number of columns.</param>
/// <param name="array">The one dimensional array to create this matrix from. This array should store the matrix in column-major order. <seealso cref="http://en.wikipedia.org/wiki/Row-major_order"/></param>
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);
}
/// <summary>
/// Creates a <see cref="Vector"/> with a the given dimension.
/// </summary>
/// <param name="size">The size of the vector.</param>
/// <returns>
/// A <see cref="Vector"/> with the given dimension.
/// </returns>
public override Vector CreateVector(int size)
{
return new DenseVector(size);
}
/// <summary>
/// Retrieves the requested element without range checking.
/// </summary>

219
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
/// </remarks>
public abstract Matrix CreateMatrix(int numberOfRows, int numberOfColumns);
/// <summary>
/// Creates a <see cref="Vector"/> with a the given dimension.
/// </summary>
/// <param name="size">The size of the vector.</param>
/// <returns>
/// A <see cref="Vector"/> with the given dimension.
/// </returns>
/// <remarks>
/// Creates a vector of the same type as the current matrix.
/// </remarks>
public abstract Vector CreateVector(int size);
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
@ -236,6 +248,211 @@ namespace MathNet.Numerics.LinearAlgebra.Double
return ToString(null, null);
}
/// <summary>
/// Copies a row into an <see cref="Vector"/>.
/// </summary>
/// <param name="index">The row to copy.</param>
/// <returns>A <see cref="Vector"/> containing the copied elements.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
/// or greater than or equal to the number of rows.</exception>
public virtual Vector GetRow(int index)
{
Vector ret = CreateVector(ColumnCount);
GetRow(index, 0, ColumnCount, ret);
return ret;
}
/// <summary>
/// Copies a row into to the given <see cref="Vector"/>.
/// </summary>
/// <param name="index">The row to copy.</param>
/// <param name="result">The <see cref="Vector"/> to copy the row into.</param>
/// <exception cref="ArgumentNullException">If the result vector is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="NotConformableException">If <b>this.Columns != result.Count</b>.</exception>
public virtual void GetRow(int index, Vector result)
{
GetRow(index, 0, ColumnCount, result);
}
/// <summary>
/// Copies the requested row elements into a new <see cref="Vector"/>.
/// </summary>
/// <param name="rowIndex">The row to copy elements from.</param>
/// <param name="columnIndex">The column to start copying from.</param>
/// <param name="length">The number of elements to copy.</param>
/// <returns>A <see cref="Vector"/> containing the requested elements.</returns>
/// <exception cref="ArgumentOutOfRangeException">If:
/// <list><item><paramref name="rowIndex"/> is negative,
/// or greater than or equal to the number of rows.</item>
/// <item><paramref name="columnIndex"/> is negative,
/// or greater than or equal to the number of columns.</item>
/// <item><c>(columnIndex + length) &gt;= Columns.</c></item></list></exception>
/// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
public virtual Vector GetRow(int rowIndex, int columnIndex, int length)
{
Vector ret = CreateVector(length);
GetRow(rowIndex, columnIndex, length, ret);
return ret;
}
/// <summary>
/// Copies the requested row elements into a new <see cref="Vector"/>.
/// </summary>
/// <param name="rowIndex">The row to copy elements from.</param>
/// <param name="columnIndex">The column to start copying from.</param>
/// <param name="length">The number of elements to copy.</param>
/// <param name="result">The <see cref="Vector"/> to copy the column into.</param>
/// <exception cref="ArgumentNullException">If the result <see cref="Vector"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is negative,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is negative,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> + <paramref name="length"/>
/// is greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
/// <exception cref="NotConformableException">If <strong>result.Count &lt; length</strong>.</exception>
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);
}
}
/// <summary>
/// Copies a column into a new <see cref="Vector"/>.
/// </summary>
/// <param name="index">The column to copy.</param>
/// <returns>A <see cref="Vector"/> containing the copied elements.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
/// or greater than or equal to the number of columns.</exception>
public virtual Vector GetColumn(int index)
{
Vector result = CreateVector(RowCount);
GetColumn(index, 0, RowCount, result);
return result;
}
/// <summary>
/// Copies a column into to the given <see cref="Vector"/>.
/// </summary>
/// <param name="index">The column to copy.</param>
/// <param name="result">The <see cref="Vector"/> to copy the column into.</param>
/// <exception cref="ArgumentNullException">If the result <see cref="Vector"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="NotConformableException">If <b>this.Rows != result.Count</b>.</exception>
public virtual void GetColumn(int index, Vector result)
{
GetColumn(index, 0, RowCount, result);
}
/// <summary>
/// Copies the requested column elements into a new <see cref="Vector"/>.
/// </summary>
/// <param name="columnIndex">The column to copy elements from.</param>
/// <param name="rowIndex">The row to start copying from.</param>
/// <param name="length">The number of elements to copy.</param>
/// <returns>A <see cref="Vector"/> containing the requested elements.</returns>
/// <exception cref="ArgumentOutOfRangeException">If:
/// <list><item><paramref name="columnIndex"/> is negative,
/// or greater than or equal to the number of columns.</item>
/// <item><paramref name="rowIndex"/> is negative,
/// or greater than or equal to the number of rows.</item>
/// <item><c>(rowIndex + length) &gt;= Rows.</c></item></list>
/// </exception>
/// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
public virtual Vector GetColumn(int columnIndex, int rowIndex, int length)
{
Vector result = CreateVector(length);
GetColumn(columnIndex, rowIndex, length, result);
return result;
}
/// <summary>
/// Copies the requested column elements into the given vector.
/// </summary>
/// <param name="columnIndex">The column to copy elements from.</param>
/// <param name="rowIndex">The row to start copying from.</param>
/// <param name="length">The number of elements to copy.</param>
/// <param name="result">The <see cref="Vector"/> to copy the column into.</param>
/// <exception cref="ArgumentNullException">If the result <see cref="Vector"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is negative,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is negative,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> + <paramref name="length"/>
/// is greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
/// <exception cref="NotConformableException">If <strong>result.Count &lt; length</strong>.</exception>
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

10
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()
{

229
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")]

15
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);
}
}
}

Loading…
Cancel
Save