From 363793d9cb933b1d5ece15e03153ccfceb1ff41b Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 21 Nov 2012 15:51:54 +0200 Subject: [PATCH 01/33] Add new interface: IStorageIndexer Signed-off-by: Alexander Karatarakis --- .../Storage/Indexers/IStorageIndexer.cs | 28 +++++++++++++++++++ src/Numerics/Numerics.csproj | 4 +++ 2 files changed, 32 insertions(+) create mode 100644 src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs diff --git a/src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs b/src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs new file mode 100644 index 00000000..7b86b5fc --- /dev/null +++ b/src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs @@ -0,0 +1,28 @@ +namespace MathNet.Numerics.LinearAlgebra.Storage.Indexers +{ + /// + /// Abstract class that defines common features for all storage schemes. + /// + public interface IStorageIndexer + { + /// + /// Retrieves the index of the requested element without parameter checking. + /// + /// The row of the element. + /// + /// The column of the element. + /// + /// The requested index. + /// + int IndexOf(int row, int column); + + /// + /// Retrieves the index of the requested diagonal element without parameter checking. + /// + /// The row=column of the diagonal element. + /// + /// The requested index. + /// + int IndexOfDiagonal(int row); + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 18d2fdbb..36973819 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -141,6 +141,7 @@ + @@ -480,6 +481,9 @@ + + + From d1e4fd9a5a8f9b2a0a3d63f2ce47f2da61a5c2d4 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 21 Nov 2012 16:09:17 +0200 Subject: [PATCH 02/33] Add new abstract class: StaticStorageIndexer Signed-off-by: Alexander Karatarakis --- .../Indexers/Static/StaticStorageIndexer.cs | 56 +++++++++++++++++++ src/Numerics/Numerics.csproj | 5 +- 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs diff --git a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs new file mode 100644 index 00000000..5237ab96 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs @@ -0,0 +1,56 @@ +namespace MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static +{ + /// + /// Classes that contain indexing information of a static storage scheme. + /// + /// + /// A static storage scheme is always the same and only depends on the size of the matrix. + /// + public abstract class StaticStorageIndexer : IStorageIndexer + { + /// + /// Gets the index of the given element. + /// + /// + /// The row of the element. + /// + /// + /// The column of the element. + /// + /// + /// This method is parameter checked. and to get values without parameter checking. + /// + public abstract int this[int row, int column] + { + get; + } + + /// + /// Gets the length of the stored data. + /// + public abstract int DataLength + { + get; + } + + /// + /// Retrieves the index of the requested element without parameter checking. + /// + /// The row of the element. + /// + /// The column of the element. + /// + /// The requested index. + /// + public abstract int IndexOf(int row, int column); + + /// + /// Retrieves the index of the requested diagonal element without parameter checking. + /// + /// The row=column of the diagonal element. + /// + /// The requested index. + /// + public abstract int IndexOfDiagonal(int row); + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 36973819..4e1d798f 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -142,6 +142,7 @@ + @@ -481,9 +482,7 @@ - - - + From 18b5790a7c549ddb5bc58ffb3bca4196e1108161 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 21 Nov 2012 16:14:05 +0200 Subject: [PATCH 03/33] Add new abstract class: PackedStorageIndexer Signed-off-by: Alexander Karatarakis --- .../Indexers/Static/PackedStorageIndexer.cs | 50 +++++++++++++++++++ src/Numerics/Numerics.csproj | 1 + 2 files changed, 51 insertions(+) create mode 100644 src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs diff --git a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs new file mode 100644 index 00000000..6d4eba54 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs @@ -0,0 +1,50 @@ +namespace MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static +{ + using System; + using Properties; + + /// + /// A class for managing indexing when using Packed Storage indexer, which is a column-major packing scheme for dense Symmetric, Hermitian or Triangular square matrices. + /// + public abstract class PackedStorageIndexer : StaticStorageIndexer + { + /// + /// Number of rows or columns. + /// + protected readonly int Order; + + /// + /// Length of the stored data. + /// + private readonly int _dataLength; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The order of the matrix. + /// + /// is out of range. + protected PackedStorageIndexer(int order) + { + if (order <= 0) + { + throw new ArgumentOutOfRangeException(Resources.MatrixRowsOrColumnsMustBePositive); + } + + Order = order; + _dataLength = order * (order + 1) / 2; + } + + /// + /// Gets the length of the stored data. + /// + public override int DataLength + { + get + { + return _dataLength; + } + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 4e1d798f..9d2198d4 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -142,6 +142,7 @@ + From 3d22fa59fef3bf1290542968e94437a043ea8dd5 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 21 Nov 2012 16:19:21 +0200 Subject: [PATCH 04/33] Add new class: PackedStorageIndexerUpper Signed-off-by: Alexander Karatarakis --- .../Static/PackedStorageIndexerUpper.cs | 88 +++++++++++++++++++ src/Numerics/Numerics.csproj | 1 + 2 files changed, 89 insertions(+) create mode 100644 src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs diff --git a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs new file mode 100644 index 00000000..4fc29f00 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs @@ -0,0 +1,88 @@ +namespace MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static +{ + using System; + + /// + /// A class for managing indexing when using Packed Storage scheme, which is a column-Wise packing scheme for Symmetric, Hermitian or Triangular square matrices. + /// This variation provides indexes for storing the upper triangle of a matrix (row less than or equal to column). + /// + public class PackedStorageIndexerUpper : PackedStorageIndexer + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The order of the matrix. + /// + internal PackedStorageIndexerUpper(int order) + : base(order) + { + } + + /// + /// Gets the index of the given element. + /// + /// + /// The row of the element. + /// + /// + /// The column of the element. + /// + /// + /// This method is parameter checked. and to get values without parameter checking. + /// + public override int this[int row, int column] + { + get + { + if (row < 0 || row >= Order) + { + throw new ArgumentOutOfRangeException("row"); + } + + if (column < 0 || column >= Order) + { + throw new ArgumentOutOfRangeException("column"); + } + + if (row > column) + { + throw new ArgumentException("Row must be less than or equal to column"); + } + + return IndexOf(row, column); + } + } + + /// + /// Retrieves the index of the requested element without parameter checking. Row must be less than or equal to column. + /// + /// + /// The row of the element. + /// + /// + /// The column of the element. + /// + /// + /// The requested index. + /// + public override int IndexOf(int row, int column) + { + return row + ((column * (column + 1)) / 2); + } + + /// + /// Retrieves the index of the requested diagonal element without parameter checking. + /// + /// + /// The row=column of the diagonal element. + /// + /// + /// The requested index. + /// + public override int IndexOfDiagonal(int row) + { + return (row * (row + 3)) / 2; + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 9d2198d4..ce386ecb 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -143,6 +143,7 @@ + From 708a4d3820217280cdb374f76103e078b1e0caf5 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 21 Nov 2012 16:49:30 +0200 Subject: [PATCH 05/33] Add new class: DenseColumnMajorSymmetricMatrixStorage Signed-off-by: Alexander Karatarakis --- .../DenseColumnMajorSymmetricMatrixStorage.cs | 77 +++++++++++++++++++ .../Indexers/Static/PackedStorageIndexer.cs | 2 +- .../Static/PackedStorageIndexerUpper.cs | 2 +- src/Numerics/Numerics.csproj | 1 + 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs diff --git a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs new file mode 100644 index 00000000..c58279b6 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs @@ -0,0 +1,77 @@ +using System; + +namespace MathNet.Numerics.LinearAlgebra.Storage +{ + using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static; + using MathNet.Numerics.Properties; + + public class DenseColumnMajorSymmetricMatrixStorage : MatrixStorage + where T : struct, IEquatable, IFormattable + { + // [ruegg] public fields are OK here + + public readonly T[] Data; + + public readonly PackedStorageIndexerUpper Indexer; + + internal DenseColumnMajorSymmetricMatrixStorage(int order) + : base(order, order) + { + Indexer = new PackedStorageIndexerUpper(order); + Data = new T[Indexer.DataLength]; + } + + internal DenseColumnMajorSymmetricMatrixStorage(int order, T[] data) + : base(order, order) + { + if (data == null) + { + throw new ArgumentNullException("data"); + } + + Indexer = new PackedStorageIndexerUpper(order); + + if (data.Length != Indexer.DataLength) + { + throw new ArgumentOutOfRangeException("data", string.Format(Resources.ArgumentArrayWrongLength, Indexer.DataLength)); + } + + Data = data; + } + + /// + /// Retrieves the requested element without range checking. + /// + /// + /// The row of the element. + /// + /// + /// The column of the element. + /// + /// + /// The requested element. + /// + /// Not range-checked. + public override T At(int row, int column) + { + return Data[Indexer.IndexOf(row, column)]; + } + + /// + /// Sets the element without range checking. + /// + /// The row of the element. + /// The column of the element. + /// The value to set the element to. + /// WARNING: This method is not thread safe. Use "lock" with it and be sure to avoid deadlocks. + public override void At(int row, int column, T value) + { + Data[Indexer.IndexOf(row, column)] = value; + } + + public override void Clear() + { + Array.Clear(Data, 0, Data.Length); + } + } +} diff --git a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs index 6d4eba54..56a22c4a 100644 --- a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs +++ b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs @@ -4,7 +4,7 @@ using Properties; /// - /// A class for managing indexing when using Packed Storage indexer, which is a column-major packing scheme for dense Symmetric, Hermitian or Triangular square matrices. + /// A class for managing indexing when using Packed Storage, which is a column-major packing scheme for dense Symmetric, Hermitian or Triangular square matrices. /// public abstract class PackedStorageIndexer : StaticStorageIndexer { diff --git a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs index 4fc29f00..d9e91bc2 100644 --- a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs +++ b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs @@ -3,7 +3,7 @@ using System; /// - /// A class for managing indexing when using Packed Storage scheme, which is a column-Wise packing scheme for Symmetric, Hermitian or Triangular square matrices. + /// A class for managing indexes when using Packed Storage, which is a column-major packing scheme for Symmetric, Hermitian or Triangular square matrices. /// This variation provides indexes for storing the upper triangle of a matrix (row less than or equal to column). /// public class PackedStorageIndexerUpper : PackedStorageIndexer diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index ce386ecb..a744dbca 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -140,6 +140,7 @@ + From 767f8a8e9b51e26fb47bc9ee1ec59760c680c6c5 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 21 Nov 2012 16:51:01 +0200 Subject: [PATCH 06/33] [IStorageIndexer] Rename methods from IndexOf() to Of() Signed-off-by: Alexander Karatarakis --- .../Storage/DenseColumnMajorSymmetricMatrixStorage.cs | 4 ++-- .../LinearAlgebra/Storage/Indexers/IStorageIndexer.cs | 4 ++-- .../Storage/Indexers/Static/PackedStorageIndexerUpper.cs | 8 ++++---- .../Storage/Indexers/Static/StaticStorageIndexer.cs | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs index c58279b6..0c273907 100644 --- a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs @@ -54,7 +54,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage /// Not range-checked. public override T At(int row, int column) { - return Data[Indexer.IndexOf(row, column)]; + return Data[Indexer.Of(row, column)]; } /// @@ -66,7 +66,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage /// WARNING: This method is not thread safe. Use "lock" with it and be sure to avoid deadlocks. public override void At(int row, int column, T value) { - Data[Indexer.IndexOf(row, column)] = value; + Data[Indexer.Of(row, column)] = value; } public override void Clear() diff --git a/src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs b/src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs index 7b86b5fc..7a7e5975 100644 --- a/src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs +++ b/src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs @@ -14,7 +14,7 @@ /// /// The requested index. /// - int IndexOf(int row, int column); + int Of(int row, int column); /// /// Retrieves the index of the requested diagonal element without parameter checking. @@ -23,6 +23,6 @@ /// /// The requested index. /// - int IndexOfDiagonal(int row); + int OfDiagonal(int row); } } diff --git a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs index d9e91bc2..9989b864 100644 --- a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs +++ b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs @@ -29,7 +29,7 @@ /// The column of the element. /// /// - /// This method is parameter checked. and to get values without parameter checking. + /// This method is parameter checked. and to get values without parameter checking. /// public override int this[int row, int column] { @@ -50,7 +50,7 @@ throw new ArgumentException("Row must be less than or equal to column"); } - return IndexOf(row, column); + return this.Of(row, column); } } @@ -66,7 +66,7 @@ /// /// The requested index. /// - public override int IndexOf(int row, int column) + public override int Of(int row, int column) { return row + ((column * (column + 1)) / 2); } @@ -80,7 +80,7 @@ /// /// The requested index. /// - public override int IndexOfDiagonal(int row) + public override int OfDiagonal(int row) { return (row * (row + 3)) / 2; } diff --git a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs index 5237ab96..d447fbee 100644 --- a/src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs +++ b/src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs @@ -18,7 +18,7 @@ /// The column of the element. /// /// - /// This method is parameter checked. and to get values without parameter checking. + /// This method is parameter checked. and to get values without parameter checking. /// public abstract int this[int row, int column] { @@ -42,7 +42,7 @@ /// /// The requested index. /// - public abstract int IndexOf(int row, int column); + public abstract int Of(int row, int column); /// /// Retrieves the index of the requested diagonal element without parameter checking. @@ -51,6 +51,6 @@ /// /// The requested index. /// - public abstract int IndexOfDiagonal(int row); + public abstract int OfDiagonal(int row); } } From c606b329b89e2908415c722748df15a71faccdc6 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 21 Nov 2012 17:17:28 +0200 Subject: [PATCH 07/33] Add SymmetricMatrixStorage Signed-off-by: Alexander Karatarakis --- .../DenseColumnMajorSymmetricMatrixStorage.cs | 6 +-- .../Storage/SymmetricMatrixStorage.cs | 52 +++++++++++++++++++ src/Numerics/Numerics.csproj | 1 + 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs diff --git a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs index 0c273907..a2b52833 100644 --- a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs @@ -5,7 +5,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static; using MathNet.Numerics.Properties; - public class DenseColumnMajorSymmetricMatrixStorage : MatrixStorage + public class DenseColumnMajorSymmetricMatrixStorage : SymmetricMatrixStorage where T : struct, IEquatable, IFormattable { // [ruegg] public fields are OK here @@ -15,14 +15,14 @@ namespace MathNet.Numerics.LinearAlgebra.Storage public readonly PackedStorageIndexerUpper Indexer; internal DenseColumnMajorSymmetricMatrixStorage(int order) - : base(order, order) + : base(order) { Indexer = new PackedStorageIndexerUpper(order); Data = new T[Indexer.DataLength]; } internal DenseColumnMajorSymmetricMatrixStorage(int order, T[] data) - : base(order, order) + : base(order) { if (data == null) { diff --git a/src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs new file mode 100644 index 00000000..8ff1a641 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MathNet.Numerics.LinearAlgebra.Storage +{ + using MathNet.Numerics.Properties; + + public abstract class SymmetricMatrixStorage : MatrixStorage + where T : struct, IEquatable, IFormattable + { + // [ruegg] public fields are OK here + + protected SymmetricMatrixStorage(int order) + : base(order, order) + { + } + + public override bool IsFullyMutable + { + get { return false; } + } + + public override bool IsMutable(int row, int column) + { + return row <= column; + } + + public override void Clear() + { + for (var i = 0; i < RowCount; i++) + { + for (var j = i; j < ColumnCount; j++) + { + At(i, j, default(T)); + } + } + } + + public override void Clear(int rowIndex, int rowCount, int columnIndex, int columnCount) + { + for (var i = rowIndex; i < rowIndex + rowCount; i++) + { + for (var j = Math.Max(columnIndex, i); j < columnIndex + columnCount; j++) + { + At(i, j, default(T)); + } + } + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index a744dbca..12d2ad78 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -359,6 +359,7 @@ + From e774bf4be4b2ded5838d383d09b78b043c0c4e33 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 21 Nov 2012 17:32:48 +0200 Subject: [PATCH 08/33] Add new abstract class: SquareMatrix Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Generic/SquareMatrix.cs | 39 +++++++++++++++++++ src/Numerics/Numerics.csproj | 1 + 2 files changed, 40 insertions(+) create mode 100644 src/Numerics/LinearAlgebra/Generic/SquareMatrix.cs diff --git a/src/Numerics/LinearAlgebra/Generic/SquareMatrix.cs b/src/Numerics/LinearAlgebra/Generic/SquareMatrix.cs new file mode 100644 index 00000000..ca4ba3e2 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Generic/SquareMatrix.cs @@ -0,0 +1,39 @@ +namespace MathNet.Numerics.LinearAlgebra.Generic +{ + using System; + + using MathNet.Numerics.LinearAlgebra.Storage; + + using Properties; + + /// + /// Abstract class for square matrices. + /// + /// Supported data types are double, single, , and . + [Serializable] + public abstract class SquareMatrix : Matrix + where T : struct, IEquatable, IFormattable + { + /// + /// Number of rows or columns. + /// + protected readonly int Order; + + /// + /// Initializes a new instance of the class. + /// + /// + /// If the matrix is not square. + /// + protected SquareMatrix(MatrixStorage storage) + : base(storage) + { + if (storage.RowCount != storage.ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + Order = storage.RowCount; + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 12d2ad78..64c39dbd 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -140,6 +140,7 @@ + From 58d5b00883b6686647f2f98a18e5fd291b5ccb29 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Wed, 21 Nov 2012 17:43:43 +0200 Subject: [PATCH 09/33] Add new abstract matrix: SymmetricMatrix. Also move Square matrix to Double Signed-off-by: Alexander Karatarakis --- .../{Generic => Double}/SquareMatrix.cs | 13 +- .../LinearAlgebra/Double/SymmetricMatrix.cs | 380 ++++++++++++++++++ src/Numerics/Numerics.csproj | 3 +- 3 files changed, 387 insertions(+), 9 deletions(-) rename src/Numerics/LinearAlgebra/{Generic => Double}/SquareMatrix.cs (65%) create mode 100644 src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs diff --git a/src/Numerics/LinearAlgebra/Generic/SquareMatrix.cs b/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs similarity index 65% rename from src/Numerics/LinearAlgebra/Generic/SquareMatrix.cs rename to src/Numerics/LinearAlgebra/Double/SquareMatrix.cs index ca4ba3e2..fc856e6f 100644 --- a/src/Numerics/LinearAlgebra/Generic/SquareMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs @@ -1,18 +1,15 @@ -namespace MathNet.Numerics.LinearAlgebra.Generic +namespace MathNet.Numerics.LinearAlgebra.Double { using System; using MathNet.Numerics.LinearAlgebra.Storage; - - using Properties; + using MathNet.Numerics.Properties; /// /// Abstract class for square matrices. /// - /// Supported data types are double, single, , and . [Serializable] - public abstract class SquareMatrix : Matrix - where T : struct, IEquatable, IFormattable + public abstract class SquareMatrix : Matrix { /// /// Number of rows or columns. @@ -20,12 +17,12 @@ protected readonly int Order; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// If the matrix is not square. /// - protected SquareMatrix(MatrixStorage storage) + protected SquareMatrix(MatrixStorage storage) : base(storage) { if (storage.RowCount != storage.ColumnCount) diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs new file mode 100644 index 00000000..c6c94332 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs @@ -0,0 +1,380 @@ +namespace MathNet.Numerics.LinearAlgebra.Double +{ + using System; + + using MathNet.Numerics.Distributions; + using MathNet.Numerics.LinearAlgebra.Generic; + using MathNet.Numerics.LinearAlgebra.Storage; + + /// + /// Abstract class for symmetric matrices. + /// + [Serializable] + public abstract class SymmetricMatrix : SquareMatrix + { + /// + /// Initializes a new instance of the class. + /// + protected SymmetricMatrix(MatrixStorage storage) + : base(storage) + { + } + + /// + /// Returns a value indicating whether the array is symmetric. + /// + /// + /// The array to check for symmetry. + /// + /// + /// True is array is symmetric, false if not symmetric. + /// + public static bool CheckIfSymmetric(double[,] array) + { + var rows = array.GetLength(0); + var columns = array.GetLength(1); + + if (rows != columns) + { + return false; + } + + for (var row = 0; row < rows; row++) + { + for (var column = 0; column < columns; column++) + { + if (column >= row) + { + continue; + } + + if (!array[row, column].Equals(array[column, row])) + { + return false; + } + } + } + + return true; + } + + /// + /// Gets a value indicating whether this matrix is symmetric. + /// + public override sealed bool IsSymmetric + { + get + { + return true; + } + } + + /// + /// Returns the transpose of this matrix. The transpose is equal and this method returns a reference to this matrix. + /// + /// + /// The transpose of this matrix. + /// + public override sealed Matrix Transpose() + { + return this; + } + + /// + /// Adds another matrix to this matrix. + /// + /// + /// The matrix to add to this matrix. + /// + /// + /// The matrix to store the result of the addition. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoAdd(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + if (symmetricOther == null || symmetricResult == null) + { + base.DoAdd(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) + symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// + /// The matrix to subtract to this matrix. + /// + /// + /// The matrix to store the result of subtraction. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoSubtract(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + if (symmetricOther == null || symmetricResult == null) + { + base.DoSubtract(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) - symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// + /// The scalar to multiply the matrix with. + /// + /// + /// The matrix to store the result of the multiplication. + /// + protected override void DoMultiply(double scalar, Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoMultiply(scalar, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) * scalar); + } + } + } + } + + /// + /// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix. + /// + /// + /// The matrix to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Matrix other, Matrix result) + { + DoMultiply(other, result); + } + + /// + /// Multiplies the transpose of this matrix with a vector and places the results into the result vector. + /// + /// + /// The vector to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Vector rightSide, Vector result) + { + DoMultiply(rightSide, result); + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// + /// The result of the negation. + /// + protected override void DoNegate(Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoNegate(result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column != ColumnCount; column++) + { + symmetricResult[row, column] = -At(row, column); + } + } + } + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise multiply with this one. + /// + /// + /// The matrix to store the result of the pointwise multiplication. + /// + protected override void DoPointwiseMultiply(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + if (symmetricOther == null || symmetricResult == null) + { + base.DoPointwiseMultiply(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) * symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise divide this one by. + /// + /// + /// The matrix to store the result of the pointwise division. + /// + protected override void DoPointwiseDivide(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + if (symmetricOther == null || symmetricResult == null) + { + base.DoPointwiseDivide(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) / symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Computes the modulus for each element of the matrix. + /// + /// + /// The divisor to use. + /// + /// + /// Matrix to store the results in. + /// + protected override void DoModulus(double divisor, Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoModulus(divisor, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) % divisor); + } + } + } + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix matrix, IContinuousDistribution distribution) + { + var symmetricMatrix = matrix as SymmetricMatrix; + + if (symmetricMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var row = 0; row < matrix.RowCount; row++) + { + for (var column = row; column < matrix.ColumnCount; column++) + { + symmetricMatrix.At(row, column, distribution.Sample()); + } + } + } + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix matrix, IDiscreteDistribution distribution) + { + var symmetricMatrix = matrix as SymmetricMatrix; + if (symmetricMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var row = 0; row < matrix.RowCount; row++) + { + for (var column = row; column < matrix.ColumnCount; column++) + { + symmetricMatrix.At(row, column, distribution.Sample()); + } + } + } + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 64c39dbd..531cbd69 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -140,7 +140,8 @@ - + + From 1793a674ff7731b5b30c29c5344016eac75e0916 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sat, 24 Nov 2012 19:01:02 +0200 Subject: [PATCH 10/33] Add SymmetricDenseMatrix and tweak the storage Signed-off-by: Alexander Karatarakis --- .../Double/SymmetricDenseMatrix.cs | 820 ++++++++++++++++++ .../DenseColumnMajorSymmetricMatrixStorage.cs | 9 +- src/Numerics/Numerics.csproj | 1 + 3 files changed, 829 insertions(+), 1 deletion(-) create mode 100644 src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs new file mode 100644 index 00000000..e34219f5 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs @@ -0,0 +1,820 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Double +{ + using System; + using Distributions; + using Generic; + + using MathNet.Numerics.LinearAlgebra.Storage; + using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static; + + using Properties; + using Threading; + + /// + /// A Symmetric Matrix class with dense storage. + /// + /// The underlying storage is a one dimensional array in column-major order. + /// The Upper Triangle is stored(it is equal to the Lower Triangle) + [Serializable] + public class SymmetricDenseMatrix : SymmetricMatrix + { + readonly DenseColumnMajorSymmetricMatrixStorage _storage; + + /// + /// Number of rows. + /// + /// Using this instead of the RowCount property to speed up calculating + /// a matrix index in the data array. + readonly int _rowCount; + + /// + /// Number of columns. + /// + /// Using this instead of the ColumnCount property to speed up calculating + /// a matrix index in the data array. + readonly int _columnCount; + + /// + /// Gets the matrix's data. + /// + /// The matrix's data. + readonly double[] _data; + + internal SymmetricDenseMatrix(DenseColumnMajorSymmetricMatrixStorage storage) + : base(storage) + { + _storage = storage; + _rowCount = _storage.RowCount; + _columnCount = _storage.ColumnCount; + _data = _storage.Data; + } + + /// + /// Initializes a new instance of the class. This matrix is square with a given size. + /// + /// The order of the matrix. + /// + /// If is less than one. + /// + public SymmetricDenseMatrix(int order) + : this(new DenseColumnMajorSymmetricMatrixStorage(order)) + { + } + + /// + /// Initializes a new instance of the class with all entries set to a particular value. + /// + /// + /// The order of the matrix. + /// + /// The value which we assign to each element of the matrix. + /// Forcing user to input (int, int, double) because only asking (int, double) would + /// create a signature easily confused with (int, int) which is already used + public SymmetricDenseMatrix(int order, double value) + : this(order) + { + for (var i = 0; i < Data.Length; i++) + { + Data[i] = value; + } + } + + /// + /// Initializes a new instance of the class from a one dimensional array. This constructor + /// will reference the one dimensional array and not copy it. + /// + /// The size of the square matrix. + /// + /// The one dimensional array to create this matrix from. Column-major and row-major order is identical on a symmetric matrix: http://en.wikipedia.org/wiki/Row-major_order + /// + /// + /// If does not represent a packed array. + /// + public SymmetricDenseMatrix(int order, double[] array) + : this(new DenseColumnMajorSymmetricMatrixStorage(order, array)) + { + } + + /// + /// Initializes a new instance of the class from a 2D array. This constructor + /// will allocate a completely new memory block for storing the symmetric dense matrix. + /// + /// The 2D array to create this matrix from. + /// + /// If is not a square array. + /// + /// + /// If is not a symmetric array. + /// + public SymmetricDenseMatrix(double[,] array) + : this(array.GetLength(0)) + { + if (!CheckIfSymmetric(array)) + { + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + } + + var indexer = new PackedStorageIndexerUpper(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + Data[indexer.Of(row, column)] = array[row, column]; + } + } + } + + /// + /// Initializes a new instance of the class, copying + /// the values from the given matrix. Matrix must be Symmetric. + /// + /// The matrix to copy. + /// + /// If is not a square matrix. + /// + /// + /// If is not a symmetric matrix. + /// + public SymmetricDenseMatrix(Matrix matrix) + : this(matrix.RowCount) + { + var symmetricMatrix = matrix as SymmetricDenseMatrix; + + if (!matrix.IsSymmetric) + { + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + } + + if (symmetricMatrix == null) + { + var indexer = new PackedStorageIndexerUpper(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + Data[indexer.Of(row, column)] = matrix[row, column]; + } + } + } + else + { + matrix.CopyTo(this); + } + } + + /// + /// Gets the matrix's data in array format. + /// + /// The matrix's raw data. + public double[] Data + { + get; + private set; + } + + /// + /// Creates a SymmetricDenseMatrix for the given number of rows and columns. + /// If rows and columns are not equal, returns a DenseMatrix instead. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// True if all fields must be mutable (e.g. not a diagonal matrix). + /// + /// A DenseMatrix or SymmetricDenseMatrix with the given dimensions. + /// + /// /// + /// If is not equal to . + /// Symmetric arrays are always square + /// + public override Matrix CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false) + { + if (numberOfRows != numberOfColumns || fullyMutable) + { + return new DenseMatrix(numberOfRows, numberOfColumns); + } + + return new SymmetricDenseMatrix(numberOfRows, numberOfColumns); + } + + /// + /// Creates a with a the given dimension. + /// + /// The size of the vector. + /// True if all fields must be mutable. + /// + /// A with the given dimension. + /// + public override Vector CreateVector(int size, bool fullyMutable = false) + { + return new DenseVector(size); + } + + #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 symmetric dense identity matrix. + /// + /// If is less than one. + /// + public static SymmetricDenseMatrix Identity(int order) + { + var m = new SymmetricDenseMatrix(order); + for (var i = 0; i < order; i++) + { + m.At(i, i, 1.0); + } + + return m; + } + + #endregion + + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The matrix to store the result of add + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + protected override void DoAdd(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + if (denseOther == null || denseResult == null) + { + base.DoAdd(other, result); + } + else + { + Control.LinearAlgebraProvider.AddArrays(Data, denseOther.Data, denseResult.Data); + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The matrix to store the result of the subtraction. + protected override void DoSubtract(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + if (denseOther == null || denseResult == null) + { + base.DoSubtract(other, result); + } + else + { + Control.LinearAlgebraProvider.SubtractArrays(Data, denseOther.Data, denseResult.Data); + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// The scalar to multiply the matrix with. + /// The matrix to store the result of the multiplication. + protected override void DoMultiply(double scalar, Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + if (denseResult == null) + { + base.DoMultiply(scalar, result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(scalar, Data, denseResult.Data); + } + } + + /// + /// Multiplies this matrix with a vector and places the results into the result vector. + /// + /// The vector to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Vector rightSide, Vector result) + { + var denseRight = rightSide as DenseVector; + var denseResult = result as DenseVector; + + if (denseRight == null || denseResult == null) + { + base.DoMultiply(rightSide, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoMultiply(rightSide, result); + } + } + + /// + /// Multiplies this matrix with another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoMultiply(other, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoMultiply(other, result); + } + } + + /// + /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoTransposeAndMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoTransposeAndMultiply(other, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoTransposeAndMultiply(other, result); + } + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// The result of the negation. + protected override void DoNegate(Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + + if (denseResult == null) + { + base.DoNegate(result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(-1, Data, denseResult.Data); + } + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise multiply with this one. + /// The matrix to store the result of the pointwise multiplication. + protected override void DoPointwiseMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoPointwiseMultiply(other, result); + } + else + { + Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, denseOther.Data, denseResult.Data); + } + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise divide this one by. + /// The matrix to store the result of the pointwise division. + protected override void DoPointwiseDivide(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoPointwiseDivide(other, result); + } + else + { + Control.LinearAlgebraProvider.PointWiseDivideArrays(Data, denseOther.Data, denseResult.Data); + } + } + + /// + /// Returns a new matrix containing the lower triangle of this matrix. + /// + /// The lower triangle of this matrix. + public override Matrix LowerTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = 0; column <= row; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// 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 override Matrix StrictlyLowerTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = 0; column < row; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// Returns a new matrix containing the upper triangle of this matrix. + /// + /// The upper triangle of this matrix. + public override Matrix UpperTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// 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 override Matrix StrictlyUpperTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row + 1; column < Order; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// Computes the modulus for each element of the matrix. + /// + /// The divisor to use. + /// Matrix to store the results in. + protected override void DoModulus(double divisor, Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + + if (denseResult == null) + { + base.DoModulus(divisor, result); + } + else + { + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + + CommonParallel.For( + 0, + Data.Length, + index => denseResult.Data[index] %= divisor); + } + } + + /// + /// Computes the trace of this matrix. + /// + /// The trace of this matrix + /// If the matrix is not square + public override double Trace() + { + if (RowCount != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + var sum = 0.0; + for (var i = 0; i < RowCount; i++) + { + sum += At(i, i); + } + + return sum; + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix matrix, IContinuousDistribution distribution) + { + var denseMatrix = matrix as SymmetricDenseMatrix; + + if (denseMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var i = 0; i < denseMatrix.Data.Length; i++) + { + denseMatrix.Data[i] = distribution.Sample(); + } + } + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix matrix, IDiscreteDistribution distribution) + { + var denseMatrix = matrix as SymmetricDenseMatrix; + + if (denseMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var i = 0; i < denseMatrix.Data.Length; i++) + { + denseMatrix.Data[i] = distribution.Sample(); + } + } + } + + /// + /// 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 SymmetricDenseMatrix operator +(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Add(rightSide); + } + + /// + /// Returns a Matrix containing the same values of . + /// + /// The matrix to get the values from. + /// A matrix containing a the same values as . + /// If is . + public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Clone(); + } + + /// + /// 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 SymmetricDenseMatrix operator -(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Subtract(rightSide); + } + + /// + /// Negates each element of the matrix. + /// + /// The matrix to negate. + /// A matrix containing the negated values. + /// If is . + public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Negate(); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, double rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(double leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Multiply(leftSide); + } + + /// + /// Multiplies two matrices. + /// + /// 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 multiply. + /// The right matrix to multiply. + /// The result of multiplication. + /// If or is . + /// If the dimensions of or don't conform. + public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide.ColumnCount != rightSide.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Matrix and a Vector. + /// + /// The matrix to multiply. + /// The vector to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(SymmetricDenseMatrix leftSide, DenseVector rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (DenseVector)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Vector and a Matrix. + /// + /// The vector to multiply. + /// The matrix to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(DenseVector leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (DenseVector)rightSide.LeftMultiply(leftSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator %(SymmetricDenseMatrix leftSide, double rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Modulus(rightSide); + } + } +} \ No newline at end of file diff --git a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs index a2b52833..3d0ee7f7 100644 --- a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs @@ -54,7 +54,9 @@ namespace MathNet.Numerics.LinearAlgebra.Storage /// Not range-checked. public override T At(int row, int column) { - return Data[Indexer.Of(row, column)]; + var r = Math.Min(row, column); + var c = Math.Max(row, column); + return Data[Indexer.Of(r, c)]; } /// @@ -66,6 +68,11 @@ namespace MathNet.Numerics.LinearAlgebra.Storage /// WARNING: This method is not thread safe. Use "lock" with it and be sure to avoid deadlocks. public override void At(int row, int column, T value) { + if (row > column) + { + throw new IndexOutOfRangeException("Setting an element in the strictly lower triangle of a symmetric matrix is disabled to avoid errors"); + } + Data[Indexer.Of(row, column)] = value; } diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 531cbd69..035cb821 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -141,6 +141,7 @@ + From 36fe86a1f502db6b889915fd4de5e47565e861e8 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sat, 24 Nov 2012 19:05:55 +0200 Subject: [PATCH 11/33] Add SymmetricMatrixTests Signed-off-by: Alexander Karatarakis --- .../Double/SymmetricMatrixTests.Arithmetic.cs | 191 ++++++++++++++++++ .../Double/SymmetricMatrixTests.cs | 123 +++++++++++ src/UnitTests/UnitTests.csproj | 2 + 3 files changed, 316 insertions(+) create mode 100644 src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.Arithmetic.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.cs diff --git a/src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.Arithmetic.cs new file mode 100644 index 00000000..cb7accb7 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.Arithmetic.cs @@ -0,0 +1,191 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double +{ + using System.Collections.Generic; + using LinearAlgebra.Double; + using NUnit.Framework; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices + /// + public abstract partial class SymmetricMatrixTests + { + /// + /// Setup test matrices. + /// Singular and Square matrices are overridden here with symmetric ones so that calls to base methods work as intended. + /// Additional NonSymmetric matrices are defined for some tests. + /// + [SetUp] + public override void SetupMatrices() + { + TestData2D = new Dictionary + { + { "Singular3x3", new[,] { { 1.0, 2.0, 3.0 }, { 2.0, 0.0, 0.0 }, { 3.0, 0.0, 0.0 } } }, + { "Square3x3", new[,] { { -1.1, 2.0, 3.0 }, { 2.0, 1.1, 0.0 }, { 3.0, 0.0, 6.6 } } }, + { "Square4x4", new[,] { { 1.1, 2.0, -3.0, 4.4 }, { 2.0, 5.0, -6.0, 7.0 }, { -3.0, -6.0, 8.0, 9.0 }, { 4.4, 7.0, 9.0, 10.0 } } }, + { "Singular4x4", new[,] { { 1.0, 2.0, 0.0, 4.0 }, { 2.0, 5.0, 0.0, 7.0 }, { 0.0, 0.0, 0.0, 0.0 }, { 4.0, 7.0, 0.0, 10.0 } } }, + { "Tall3x2", new[,] { { -1.1, -2.2 }, { 0.0, 1.1 }, { -4.4, 5.5 } } }, + { "Wide2x3", new[,] { { -1.1, -2.2, -3.3 }, { 0.0, 1.1, 2.2 } } }, + { "Symmetric3x3", new[,] { { 1.0, 2.0, 3.0 }, { 2.0, 2.0, 0.0 }, { 3.0, 0.0, 3.0 } } }, + { "NonSymmetric3x3", new[,] { { -1.1, -2.2, -3.3 }, { 0.0, 1.1, 2.2 }, { -4.4, 5.5, 6.6 } } }, + { "NonSymmetric4x4", new[,] { { -1.1, -2.2, -3.3, -4.4 }, { 0.0, 1.1, 2.2, 3.3 }, { 1.0, 2.1, 6.2, 4.3 }, { -4.4, 5.5, 6.6, -7.7 } } }, + { "IndexTester4x4", new double[,] { { 0, 1, 3, 6 }, { 1, 2, 4, 7 }, { 3, 4, 5, 8 }, { 6, 7, 8, 9 } } } + }; + + TestMatrices = new Dictionary(); + + foreach (var name in TestData2D.Keys) + { + TestMatrices.Add(name, CreateMatrix(TestData2D[name])); + } + } + + /// + /// Can add a non-symmetric matrix to this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanAddNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Add(matrixB); + + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] + matrixB[i, j]); + } + } + } + + /// + /// Can subtract a non-symmetric matrix from this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanSubtractNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Subtract(matrixB); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] - matrixB[i, j]); + } + } + } + + /// + /// Can compute Frobenius norm. + /// + public override void CanComputeFrobeniusNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + } + + + + /// + /// Can compute Infinity norm. + /// + public override void CanComputeInfinityNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + } + + + + /// + /// Can compute L1 norm. + /// + public override void CanComputeL1Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + } + + + + /// + /// Can compute L2 norm. + /// + public override void CanComputeL2Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.cs new file mode 100644 index 00000000..d95359f0 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.cs @@ -0,0 +1,123 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double +{ + using MathNet.Numerics.LinearAlgebra.Double; + using NUnit.Framework; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices. + /// + public abstract partial class SymmetricMatrixTests : MatrixTests + { + /// + /// Can check if a matrix is symmetric. + /// + [Test] + public override void CanCheckIfMatrixIsSymmetric() + { + var matrix = TestMatrices["Square3x3"]; + Assert.IsTrue(matrix.IsSymmetric); + + matrix = TestMatrices["NonSymmetric3x3"]; + Assert.IsFalse(matrix.IsSymmetric); + } + + /// + /// Can check if a [,] array is symmetric. + /// + [Test] + public void CanCheckIfArrayIsSymmetric() + { + Assert.IsTrue(SymmetricMatrix.CheckIfSymmetric(TestData2D["Square3x3"])); + Assert.IsFalse(SymmetricMatrix.CheckIfSymmetric(TestData2D["NonSymmetric3x3"])); + } + + /// + /// Test whether the index enumerator returns the correct values. + /// + [Test] + public void CanUseIndexedEnumerator() + { + var matrix = TestMatrices["Singular3x3"]; + var enumerator = matrix.IndexedEnumerator().GetEnumerator(); + enumerator.MoveNext(); + var item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(1.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(2.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(3.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(2.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(0.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(0.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(3.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(0.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(0.0, item.Item3); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index 6ca40e38..9a71e1b5 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -568,6 +568,8 @@ Code + + Code From 7cebb6ea79d10c8147d39c172bacba856442244a Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sat, 24 Nov 2012 19:16:40 +0200 Subject: [PATCH 12/33] Add SymmetricDenseMatrixTests Signed-off-by: Alexander Karatarakis --- .../Double/SymmetricDenseMatrixTests.cs | 99 +++++++++++++++++++ src/UnitTests/UnitTests.csproj | 1 + 2 files changed, 100 insertions(+) create mode 100644 src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs diff --git a/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs new file mode 100644 index 00000000..53896f67 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs @@ -0,0 +1,99 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double +{ + using MathNet.Numerics.LinearAlgebra.Double; + + using NUnit.Framework; + + /// + /// Symmetric Dense matrix tests. + /// + public class SymmetricDenseMatrixTests : SymmetricMatrixTests + { + /// + /// Creates a matrix for the given number of rows and columns. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// + /// A matrix with the given dimensions. + /// + protected override Matrix CreateMatrix(int rows, int columns) + { + return new DenseMatrix(rows, columns); + } + + /// + /// Creates a matrix from a 2D array. + /// + /// + /// The 2D array to create this matrix from. + /// + /// + /// A matrix with the given values. + /// + protected override Matrix CreateMatrix(double[,] data) + { + return SymmetricMatrix.CheckIfSymmetric(data) + ? (Matrix)new SymmetricDenseMatrix(data) + : new DenseMatrix(data); + } + + /// + /// Creates a vector of the given size. + /// + /// + /// The size of the vector to create. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(int size) + { + return new DenseVector(size); + } + + /// + /// Creates a vector from an array. + /// + /// + /// The array to create this vector from. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(double[] data) + { + return new DenseVector(data); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index 9a71e1b5..e8b5f237 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -568,6 +568,7 @@ Code + From 02526e814d571ba45899ca75d16167989eea7c1f Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sat, 24 Nov 2012 20:54:24 +0200 Subject: [PATCH 13/33] Fixes from Unit Tests Signed-off-by: Alexander Karatarakis --- .../Double/SymmetricDenseMatrix.cs | 55 +++++++------------ .../Storage/SymmetricMatrixStorage.cs | 12 ++++ .../Double/SymmetricDenseMatrixTests.cs | 33 ++++++++++- 3 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs index e34219f5..2dc98577 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs @@ -46,20 +46,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double { readonly DenseColumnMajorSymmetricMatrixStorage _storage; - /// - /// Number of rows. - /// - /// Using this instead of the RowCount property to speed up calculating - /// a matrix index in the data array. - readonly int _rowCount; - - /// - /// Number of columns. - /// - /// Using this instead of the ColumnCount property to speed up calculating - /// a matrix index in the data array. - readonly int _columnCount; - /// /// Gets the matrix's data. /// @@ -70,8 +56,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double : base(storage) { _storage = storage; - _rowCount = _storage.RowCount; - _columnCount = _storage.ColumnCount; _data = _storage.Data; } @@ -99,9 +83,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double public SymmetricDenseMatrix(int order, double value) : this(order) { - for (var i = 0; i < Data.Length; i++) + for (var i = 0; i < _data.Length; i++) { - Data[i] = value; + _data[i] = value; } } @@ -145,7 +129,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double { for (var column = row; column < Order; column++) { - Data[indexer.Of(row, column)] = array[row, column]; + _data[indexer.Of(row, column)] = array[row, column]; } } } @@ -178,7 +162,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double { for (var column = row; column < Order; column++) { - Data[indexer.Of(row, column)] = matrix[row, column]; + _data[indexer.Of(row, column)] = matrix[row, column]; } } } @@ -189,13 +173,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double } /// - /// Gets the matrix's data in array format. + /// Gets the matrix's data. /// - /// The matrix's raw data. + /// The matrix's data. public double[] Data { - get; - private set; + get { return _data; } } /// @@ -279,7 +262,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - Control.LinearAlgebraProvider.AddArrays(Data, denseOther.Data, denseResult.Data); + Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data); } } @@ -298,7 +281,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - Control.LinearAlgebraProvider.SubtractArrays(Data, denseOther.Data, denseResult.Data); + Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data); } } @@ -316,7 +299,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - Control.LinearAlgebraProvider.ScaleArray(scalar, Data, denseResult.Data); + Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data); } } @@ -397,7 +380,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - Control.LinearAlgebraProvider.ScaleArray(-1, Data, denseResult.Data); + Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data); } } @@ -417,7 +400,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, denseOther.Data, denseResult.Data); + Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data); } } @@ -437,7 +420,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - Control.LinearAlgebraProvider.PointWiseDivideArrays(Data, denseOther.Data, denseResult.Data); + Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data); } } @@ -537,8 +520,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double CommonParallel.For( 0, - Data.Length, - index => denseResult.Data[index] %= divisor); + _data.Length, + index => denseResult._data[index] %= divisor); } } @@ -578,9 +561,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - for (var i = 0; i < denseMatrix.Data.Length; i++) + for (var i = 0; i < denseMatrix._data.Length; i++) { - denseMatrix.Data[i] = distribution.Sample(); + denseMatrix._data[i] = distribution.Sample(); } } } @@ -600,9 +583,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double } else { - for (var i = 0; i < denseMatrix.Data.Length; i++) + for (var i = 0; i < denseMatrix._data.Length; i++) { - denseMatrix.Data[i] = distribution.Sample(); + denseMatrix._data[i] = distribution.Sample(); } } } diff --git a/src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs index 8ff1a641..744c286b 100644 --- a/src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs @@ -48,5 +48,17 @@ namespace MathNet.Numerics.LinearAlgebra.Storage } } } + + /// Parameters assumed to be validated already. + public override void CopyTo(MatrixStorage target, bool skipClearing = false) + { + for (int j = 0; j < ColumnCount; j++) + { + for (int i = 0; i <= j; i++) + { + target.At(i, j, At(i, j)); + } + } + } } } diff --git a/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs index 53896f67..50bd316b 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs @@ -26,6 +26,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double { + using System.Collections.Generic; + using MathNet.Numerics.LinearAlgebra.Double; using NUnit.Framework; @@ -63,9 +65,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double /// protected override Matrix CreateMatrix(double[,] data) { - return SymmetricMatrix.CheckIfSymmetric(data) - ? (Matrix)new SymmetricDenseMatrix(data) - : new DenseMatrix(data); + if (SymmetricMatrix.CheckIfSymmetric(data)) + { + return new SymmetricDenseMatrix(data); + } + + return new DenseMatrix(data); } /// @@ -95,5 +100,27 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double { return new DenseVector(data); } + + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom2DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(new[,] { { 1.0, 2.0, 3.0 }, { 2.0, 0.0, 0.0 }, { 3.0, 0.0, 0.0 } }) }, + { "Square3x3", new SymmetricDenseMatrix(new[,] { { -1.1, 2.0, 3.0 }, { 2.0, 1.1, 0.0 }, { 3.0, 0.0, 6.6 } }) }, + { "Square4x4", new SymmetricDenseMatrix(new[,] { { 1.1, 2.0, -3.0, 4.4 }, { 2.0, 5.0, -6.0, 7.0 }, { -3.0, -6.0, 8.0, 9.0 }, { 4.4, 7.0, 9.0, 10.0 } }) }, + { "Singular4x4", new SymmetricDenseMatrix(new[,] { { 1.0, 2.0, 0.0, 4.0 }, { 2.0, 5.0, 0.0, 7.0 }, { 0.0, 0.0, 0.0, 0.0 }, { 4.0, 7.0, 0.0, 10.0 } }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(new[,] { { 1.0, 2.0, 3.0 }, { 2.0, 2.0, 0.0 }, { 3.0, 0.0, 3.0 } }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(new double[,] { { 0, 1, 3, 6 }, { 1, 2, 4, 7 }, { 3, 4, 5, 8 }, { 6, 7, 8, 9 } }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } } } \ No newline at end of file From 815c0e795d23c423c34e5f10a5bfa567d632a56b Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sat, 24 Nov 2012 22:29:37 +0200 Subject: [PATCH 14/33] Add tests Signed-off-by: Alexander Karatarakis --- .../Double/SymmetricDenseMatrixTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs index 50bd316b..4e0f6e02 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs @@ -101,6 +101,28 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double return new DenseVector(data); } + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom1DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(3, new[] { 1.0, 2.0, 0.0, 3.0, 0.0, 0.0 }) }, + { "Square3x3", new SymmetricDenseMatrix(3, new[] { -1.1, 2.0, 1.1, 3.0, 0.0, 6.6 }) }, + { "Square4x4", new SymmetricDenseMatrix(4, new[] { 1.1, 2.0, 5.0, -3.0, -6.0, 8.0, 4.4, 7.0, 9.0, 10.0 }) }, + { "Singular4x4", new SymmetricDenseMatrix(4, new[] { 1.0, 2.0, 5.0, 0.0, 0.0, 0.0, 4.0, 7.0, 0.0, 10.0 }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(3, new[] { 1.0, 2.0, 2.0, 3.0, 0.0, 3.0 }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(4, new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } + /// /// Can create a matrix form array. /// From 3a31d49309c55236644560e4b180e5a6cc8b2dcf Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sun, 25 Nov 2012 04:12:02 +0200 Subject: [PATCH 15/33] Add more tests Signed-off-by: Alexander Karatarakis --- .../Double/SymmetricDenseMatrixTests.cs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs index 4e0f6e02..b0078994 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs @@ -26,6 +26,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double { + using System; using System.Collections.Generic; using MathNet.Numerics.LinearAlgebra.Double; @@ -123,6 +124,18 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } } + /// + /// Matrix from array is a reference. + /// + [Test] + public void MatrixFrom1DArrayIsReference() + { + var data = new double[] { 1, 1, 1, 1, 1, 1 }; + var matrix = new SymmetricDenseMatrix(3, data); + matrix[0, 0] = 10.0; + Assert.AreEqual(10.0, data[0]); + } + /// /// Can create a matrix form array. /// @@ -144,5 +157,59 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double Assert.AreEqual(TestMatrices[name], testData[name]); } } + + /// + /// Matrix from two-dimensional array is a copy. + /// + [Test] + public void MatrixFrom2DArrayIsCopy() + { + var matrix = new DenseMatrix(TestData2D["Singular3x3"]); + matrix[0, 0] = 10.0; + Assert.AreEqual(1.0, TestData2D["Singular3x3"][0, 0]); + } + + /// + /// Can create a matrix with uniform values. + /// + [Test] + public void CanCreateMatrixWithUniformValues() + { + var matrix = new SymmetricDenseMatrix(10, 10.0); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], 10.0); + } + } + } + + /// + /// Can create an identity matrix. + /// + [Test] + public void CanCreateIdentity() + { + var matrix = SymmetricDenseMatrix.Identity(5); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(i == j ? 1.0 : 0.0, matrix[i, j]); + } + } + } + + /// + /// Identity with wrong order throws ArgumentOutOfRangeException. + /// + /// The size of the square matrix + [TestCase(0)] + [TestCase(-1)] + public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException(int order) + { + Assert.Throws(() => SymmetricDenseMatrix.Identity(order)); + } } } \ No newline at end of file From 12bd8e88271085c086c2fdca321058053c6da04f Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sun, 25 Nov 2012 04:32:11 +0200 Subject: [PATCH 16/33] Fix bug in SymmetricDenseMatrix.CreateMatrix() Signed-off-by: Alexander Karatarakis --- src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs index 2dc98577..d989a081 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs @@ -206,7 +206,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double return new DenseMatrix(numberOfRows, numberOfColumns); } - return new SymmetricDenseMatrix(numberOfRows, numberOfColumns); + return new SymmetricDenseMatrix(numberOfRows); } /// From 62d7e357f454522792c5c4fe26ff9753f301c830 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sun, 25 Nov 2012 05:19:40 +0200 Subject: [PATCH 17/33] [SymmetricMatrix] Override Insert/SetRow/Column Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Double/SymmetricMatrix.cs | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs index c6c94332..33dea414 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs @@ -5,6 +5,7 @@ using MathNet.Numerics.Distributions; using MathNet.Numerics.LinearAlgebra.Generic; using MathNet.Numerics.LinearAlgebra.Storage; + using MathNet.Numerics.Properties; /// /// Abstract class for symmetric matrices. @@ -376,5 +377,167 @@ } } } + + /// + /// 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 override Matrix InsertColumn(int columnIndex, Vector column) + { + throw new InvalidOperationException("Inserting a column is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given array to the specified column. The changes retain the symmetry of the matrix. + /// + /// 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 override 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"); + } + + for (var i = 0; i < columnIndex; i++) + { + At(i, columnIndex, column[i]); + } + } + + /// + /// Copies the values of the given Vector to the specified column. The changes retain the symmetry of the matrix. + /// + /// 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 override 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"); + } + + for (var i = 0; i < columnIndex; i++) + { + 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 override Matrix InsertRow(int rowIndex, Vector row) + { + throw new InvalidOperationException("Inserting a row is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given Vector 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 override 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"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } + + /// + /// Copies the values of the given array to the specified row. + /// + /// 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 override void SetRow(int rowIndex, double[] row) + { + if (rowIndex < 0 || rowIndex >= RowCount) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (row == null) + { + throw new ArgumentNullException("row"); + } + + if (row.Length != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } } } From f55e0b847c6fa5c985fa5d1471c7b68d185a1edf Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sun, 25 Nov 2012 05:50:12 +0200 Subject: [PATCH 18/33] [SymmetricMatrix] Change Transpose() to return "this.Clone()" instead of "this" Signed-off-by: Alexander Karatarakis --- src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs index 33dea414..6bb58965 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs @@ -78,7 +78,7 @@ /// public override sealed Matrix Transpose() { - return this; + return this.Clone(); } /// From 99b710a57d11d296975fb68c31a8a2d85e699f95 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sun, 25 Nov 2012 05:50:45 +0200 Subject: [PATCH 19/33] [Matrix.Arithmetic] Matrix-Matrix operations that CreateMatrix() request a fullyMutable matrix Signed-off-by: Alexander Karatarakis --- src/Numerics/LinearAlgebra/Generic/Matrix.Arithmetic.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Generic/Matrix.Arithmetic.cs b/src/Numerics/LinearAlgebra/Generic/Matrix.Arithmetic.cs index 58180ebc..1abf7c81 100644 --- a/src/Numerics/LinearAlgebra/Generic/Matrix.Arithmetic.cs +++ b/src/Numerics/LinearAlgebra/Generic/Matrix.Arithmetic.cs @@ -481,7 +481,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic throw DimensionsDontMatch(this, other); } - var result = CreateMatrix(RowCount, other.ColumnCount); + var result = CreateMatrix(RowCount, other.ColumnCount, true); Multiply(other, result); return result; } @@ -550,7 +550,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic throw DimensionsDontMatch(this, other); } - var result = CreateMatrix(RowCount, other.RowCount); + var result = CreateMatrix(RowCount, other.RowCount, true); TransposeAndMultiply(other, result); return result; } @@ -683,7 +683,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic throw DimensionsDontMatch(this, other); } - var result = CreateMatrix(ColumnCount, other.ColumnCount); + var result = CreateMatrix(ColumnCount, other.ColumnCount, true); TransposeThisAndMultiply(other, result); return result; } From 94747be5f6cefe29cb38db639ddffc53eecc09f7 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sun, 25 Nov 2012 05:57:37 +0200 Subject: [PATCH 20/33] [MatrixTests.Arithmetic] Fix reversed CanKroneckerProduct() test method names Signed-off-by: Alexander Karatarakis --- .../LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs index a2bedd61..e0d884ee 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs @@ -948,10 +948,10 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } /// - /// Can calculate Kronecker product. + /// Can calculate Kronecker product into a result matrix. /// [Test] - public void CanKroneckerProduct() + public void CanKroneckerProductIntoResult() { var matrixA = TestMatrices["Wide2x3"]; var matrixB = TestMatrices["Square3x3"]; @@ -972,11 +972,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } } + /// - /// Can calculate Kronecker product into a result matrix. + /// Can calculate Kronecker product. /// [Test] - public void CanKroneckerProductIntoResult() + public void CanKroneckerProduct() { var matrixA = TestMatrices["Wide2x3"]; var matrixB = TestMatrices["Square3x3"]; From b2aa32c872ced281abd2626da0790505aa55219a Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sun, 25 Nov 2012 06:13:08 +0200 Subject: [PATCH 21/33] [SymmetricMatrix] Throw exception when attempting to point-wise operate symmetric+non-symmetric into symmetric Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Double/SymmetricMatrix.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs index 6bb58965..a4629b1f 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs @@ -100,6 +100,12 @@ { var symmetricOther = other as SymmetricMatrix; var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric + non-symmetric matrix cannot be a symmetric matrix"); + } + if (symmetricOther == null || symmetricResult == null) { base.DoAdd(other, result); @@ -135,6 +141,12 @@ { var symmetricOther = other as SymmetricMatrix; var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric - non-symmetric matrix cannot be a symmetric matrix"); + } + if (symmetricOther == null || symmetricResult == null) { base.DoSubtract(other, result); @@ -247,6 +259,12 @@ { var symmetricOther = other as SymmetricMatrix; var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric pointwise* non-symmetric matrix cannot be a symmetric matrix"); + } + if (symmetricOther == null || symmetricResult == null) { base.DoPointwiseMultiply(other, result); @@ -276,6 +294,12 @@ { var symmetricOther = other as SymmetricMatrix; var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric pointwise/ non-symmetric matrix cannot be a symmetric matrix"); + } + if (symmetricOther == null || symmetricResult == null) { base.DoPointwiseDivide(other, result); From 3071d77337c9e4d6b21a5aef49b775b1ebd84a46 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Sun, 25 Nov 2012 06:30:29 +0200 Subject: [PATCH 22/33] [SymmetricMatrix] Override pointwise operations to special case "other" as SymmetricMatrix Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Double/SymmetricMatrix.cs | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs index a4629b1f..feffe82f 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs @@ -81,6 +81,39 @@ return this.Clone(); } + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The result of the addition. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Add(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoAdd(other, result); + return result; + } + /// /// Adds another matrix to this matrix. /// @@ -122,6 +155,40 @@ } } + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The result of the subtraction. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Subtract(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoSubtract(other, result); + return result; + } + + /// /// Subtracts another matrix from this matrix. /// @@ -246,6 +313,39 @@ } } + /// + /// Pointwise multiplies this matrix with another matrix. + /// + /// 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 override Matrix PointwiseMultiply(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other, "other"); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseMultiply(other, result); + return result; + } + /// /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. /// @@ -281,6 +381,39 @@ } } + /// + /// Pointwise divide this matrix by another matrix. + /// + /// 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 override Matrix PointwiseDivide(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseDivide(other, result); + return result; + } + /// /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. /// From ba2665b7bfcbc19427c9ed460b402e15c0e6d99e Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 14:31:12 +0200 Subject: [PATCH 23/33] Add file header Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Double/SquareMatrix.cs | 28 ++++++++++++++++++- .../LinearAlgebra/Double/SymmetricMatrix.cs | 28 ++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs b/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs index fc856e6f..32c61ef3 100644 --- a/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs @@ -1,4 +1,30 @@ -namespace MathNet.Numerics.LinearAlgebra.Double +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Double { using System; diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs index feffe82f..a7beffd6 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs @@ -1,4 +1,30 @@ -namespace MathNet.Numerics.LinearAlgebra.Double +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Double { using System; From 938df8b5947e8781920dda93bf69846678f52201 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 14:36:45 +0200 Subject: [PATCH 24/33] Add Single precision version of Symmetric matrix Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Single/SquareMatrix.cs | 62 ++ .../Single/SymmetricDenseMatrix.cs | 803 ++++++++++++++++++ .../LinearAlgebra/Single/SymmetricMatrix.cs | 726 ++++++++++++++++ src/Numerics/Numerics.csproj | 3 + 4 files changed, 1594 insertions(+) create mode 100644 src/Numerics/LinearAlgebra/Single/SquareMatrix.cs create mode 100644 src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs create mode 100644 src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs diff --git a/src/Numerics/LinearAlgebra/Single/SquareMatrix.cs b/src/Numerics/LinearAlgebra/Single/SquareMatrix.cs new file mode 100644 index 00000000..6e4aa990 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Single/SquareMatrix.cs @@ -0,0 +1,62 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Single +{ + using System; + + using MathNet.Numerics.LinearAlgebra.Storage; + using MathNet.Numerics.Properties; + + /// + /// Abstract class for square matrices. + /// + [Serializable] + public abstract class SquareMatrix : Matrix + { + /// + /// Number of rows or columns. + /// + protected readonly int Order; + + /// + /// Initializes a new instance of the class. + /// + /// + /// If the matrix is not square. + /// + protected SquareMatrix(MatrixStorage storage) + : base(storage) + { + if (storage.RowCount != storage.ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + Order = storage.RowCount; + } + } +} diff --git a/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs new file mode 100644 index 00000000..2f9d7251 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs @@ -0,0 +1,803 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Single +{ + using System; + using Distributions; + using Generic; + + using MathNet.Numerics.LinearAlgebra.Storage; + using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static; + + using Properties; + using Threading; + + /// + /// A Symmetric Matrix class with dense storage. + /// + /// The underlying storage is a one dimensional array in column-major order. + /// The Upper Triangle is stored(it is equal to the Lower Triangle) + [Serializable] + public class SymmetricDenseMatrix : SymmetricMatrix + { + readonly DenseColumnMajorSymmetricMatrixStorage _storage; + + /// + /// Gets the matrix's data. + /// + /// The matrix's data. + readonly float[] _data; + + internal SymmetricDenseMatrix(DenseColumnMajorSymmetricMatrixStorage storage) + : base(storage) + { + _storage = storage; + _data = _storage.Data; + } + + /// + /// Initializes a new instance of the class. This matrix is square with a given size. + /// + /// The order of the matrix. + /// + /// If is less than one. + /// + public SymmetricDenseMatrix(int order) + : this(new DenseColumnMajorSymmetricMatrixStorage(order)) + { + } + + /// + /// Initializes a new instance of the class with all entries set to a particular value. + /// + /// + /// The order of the matrix. + /// + /// The value which we assign to each element of the matrix. + /// Forcing user to input (int, int, double) because only asking (int, double) would + /// create a signature easily confused with (int, int) which is already used + public SymmetricDenseMatrix(int order, float value) + : this(order) + { + for (var i = 0; i < _data.Length; i++) + { + _data[i] = value; + } + } + + /// + /// Initializes a new instance of the class from a one dimensional array. This constructor + /// will reference the one dimensional array and not copy it. + /// + /// The size of the square matrix. + /// + /// The one dimensional array to create this matrix from. Column-major and row-major order is identical on a symmetric matrix: http://en.wikipedia.org/wiki/Row-major_order + /// + /// + /// If does not represent a packed array. + /// + public SymmetricDenseMatrix(int order, float[] array) + : this(new DenseColumnMajorSymmetricMatrixStorage(order, array)) + { + } + + /// + /// Initializes a new instance of the class from a 2D array. This constructor + /// will allocate a completely new memory block for storing the symmetric dense matrix. + /// + /// The 2D array to create this matrix from. + /// + /// If is not a square array. + /// + /// + /// If is not a symmetric array. + /// + public SymmetricDenseMatrix(float[,] array) + : this(array.GetLength(0)) + { + if (!CheckIfSymmetric(array)) + { + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + } + + var indexer = new PackedStorageIndexerUpper(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + _data[indexer.Of(row, column)] = array[row, column]; + } + } + } + + /// + /// Initializes a new instance of the class, copying + /// the values from the given matrix. Matrix must be Symmetric. + /// + /// The matrix to copy. + /// + /// If is not a square matrix. + /// + /// + /// If is not a symmetric matrix. + /// + public SymmetricDenseMatrix(Matrix matrix) + : this(matrix.RowCount) + { + var symmetricMatrix = matrix as SymmetricDenseMatrix; + + if (!matrix.IsSymmetric) + { + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + } + + if (symmetricMatrix == null) + { + var indexer = new PackedStorageIndexerUpper(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + _data[indexer.Of(row, column)] = matrix[row, column]; + } + } + } + else + { + matrix.CopyTo(this); + } + } + + /// + /// Gets the matrix's data. + /// + /// The matrix's data. + public float[] Data + { + get { return _data; } + } + + /// + /// Creates a SymmetricDenseMatrix for the given number of rows and columns. + /// If rows and columns are not equal, returns a DenseMatrix instead. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// True if all fields must be mutable (e.g. not a diagonal matrix). + /// + /// A DenseMatrix or SymmetricDenseMatrix with the given dimensions. + /// + /// /// + /// If is not equal to . + /// Symmetric arrays are always square + /// + public override Matrix CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false) + { + if (numberOfRows != numberOfColumns || fullyMutable) + { + return new DenseMatrix(numberOfRows, numberOfColumns); + } + + return new SymmetricDenseMatrix(numberOfRows); + } + + /// + /// Creates a with a the given dimension. + /// + /// The size of the vector. + /// True if all fields must be mutable. + /// + /// A with the given dimension. + /// + public override Vector CreateVector(int size, bool fullyMutable = false) + { + return new DenseVector(size); + } + + #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 symmetric dense identity matrix. + /// + /// If is less than one. + /// + public static SymmetricDenseMatrix Identity(int order) + { + var m = new SymmetricDenseMatrix(order); + for (var i = 0; i < order; i++) + { + m.At(i, i, 1.0f); + } + + return m; + } + + #endregion + + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The matrix to store the result of add + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + protected override void DoAdd(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + if (denseOther == null || denseResult == null) + { + base.DoAdd(other, result); + } + else + { + Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The matrix to store the result of the subtraction. + protected override void DoSubtract(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + if (denseOther == null || denseResult == null) + { + base.DoSubtract(other, result); + } + else + { + Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// The scalar to multiply the matrix with. + /// The matrix to store the result of the multiplication. + protected override void DoMultiply(float scalar, Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + if (denseResult == null) + { + base.DoMultiply(scalar, result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data); + } + } + + /// + /// Multiplies this matrix with a vector and places the results into the result vector. + /// + /// The vector to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Vector rightSide, Vector result) + { + var denseRight = rightSide as DenseVector; + var denseResult = result as DenseVector; + + if (denseRight == null || denseResult == null) + { + base.DoMultiply(rightSide, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoMultiply(rightSide, result); + } + } + + /// + /// Multiplies this matrix with another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoMultiply(other, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoMultiply(other, result); + } + } + + /// + /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoTransposeAndMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoTransposeAndMultiply(other, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoTransposeAndMultiply(other, result); + } + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// The result of the negation. + protected override void DoNegate(Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + + if (denseResult == null) + { + base.DoNegate(result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data); + } + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise multiply with this one. + /// The matrix to store the result of the pointwise multiplication. + protected override void DoPointwiseMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoPointwiseMultiply(other, result); + } + else + { + Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise divide this one by. + /// The matrix to store the result of the pointwise division. + protected override void DoPointwiseDivide(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoPointwiseDivide(other, result); + } + else + { + Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Returns a new matrix containing the lower triangle of this matrix. + /// + /// The lower triangle of this matrix. + public override Matrix LowerTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = 0; column <= row; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// 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 override Matrix StrictlyLowerTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = 0; column < row; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// Returns a new matrix containing the upper triangle of this matrix. + /// + /// The upper triangle of this matrix. + public override Matrix UpperTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// 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 override Matrix StrictlyUpperTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row + 1; column < Order; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// Computes the modulus for each element of the matrix. + /// + /// The divisor to use. + /// Matrix to store the results in. + protected override void DoModulus(float divisor, Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + + if (denseResult == null) + { + base.DoModulus(divisor, result); + } + else + { + if (!ReferenceEquals(this, result)) + { + CopyTo(result); + } + + CommonParallel.For( + 0, + _data.Length, + index => denseResult._data[index] %= divisor); + } + } + + /// + /// Computes the trace of this matrix. + /// + /// The trace of this matrix + /// If the matrix is not square + public override float Trace() + { + if (RowCount != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + var sum = 0.0f; + for (var i = 0; i < RowCount; i++) + { + sum += At(i, i); + } + + return sum; + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix matrix, IContinuousDistribution distribution) + { + var denseMatrix = matrix as SymmetricDenseMatrix; + + if (denseMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var i = 0; i < denseMatrix._data.Length; i++) + { + denseMatrix._data[i] = Convert.ToSingle(distribution.Sample()); + } + } + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix matrix, IDiscreteDistribution distribution) + { + var denseMatrix = matrix as SymmetricDenseMatrix; + + if (denseMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var i = 0; i < denseMatrix._data.Length; i++) + { + denseMatrix._data[i] = distribution.Sample(); + } + } + } + + /// + /// 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 SymmetricDenseMatrix operator +(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Add(rightSide); + } + + /// + /// Returns a Matrix containing the same values of . + /// + /// The matrix to get the values from. + /// A matrix containing a the same values as . + /// If is . + public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Clone(); + } + + /// + /// 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 SymmetricDenseMatrix operator -(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Subtract(rightSide); + } + + /// + /// Negates each element of the matrix. + /// + /// The matrix to negate. + /// A matrix containing the negated values. + /// If is . + public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Negate(); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, float rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(float leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Multiply(leftSide); + } + + /// + /// Multiplies two matrices. + /// + /// 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 multiply. + /// The right matrix to multiply. + /// The result of multiplication. + /// If or is . + /// If the dimensions of or don't conform. + public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide.ColumnCount != rightSide.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Matrix and a Vector. + /// + /// The matrix to multiply. + /// The vector to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(SymmetricDenseMatrix leftSide, DenseVector rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (DenseVector)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Vector and a Matrix. + /// + /// The vector to multiply. + /// The matrix to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(DenseVector leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (DenseVector)rightSide.LeftMultiply(leftSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator %(SymmetricDenseMatrix leftSide, float rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Modulus(rightSide); + } + } +} \ No newline at end of file diff --git a/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs new file mode 100644 index 00000000..0183fc0a --- /dev/null +++ b/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs @@ -0,0 +1,726 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Single +{ + using System; + + using MathNet.Numerics.Distributions; + using MathNet.Numerics.LinearAlgebra.Generic; + using MathNet.Numerics.LinearAlgebra.Storage; + using MathNet.Numerics.Properties; + + /// + /// Abstract class for symmetric matrices. + /// + [Serializable] + public abstract class SymmetricMatrix : SquareMatrix + { + /// + /// Initializes a new instance of the class. + /// + protected SymmetricMatrix(MatrixStorage storage) + : base(storage) + { + } + + /// + /// Returns a value indicating whether the array is symmetric. + /// + /// + /// The array to check for symmetry. + /// + /// + /// True is array is symmetric, false if not symmetric. + /// + public static bool CheckIfSymmetric(float[,] array) + { + var rows = array.GetLength(0); + var columns = array.GetLength(1); + + if (rows != columns) + { + return false; + } + + for (var row = 0; row < rows; row++) + { + for (var column = 0; column < columns; column++) + { + if (column >= row) + { + continue; + } + + if (!array[row, column].Equals(array[column, row])) + { + return false; + } + } + } + + return true; + } + + /// + /// Gets a value indicating whether this matrix is symmetric. + /// + public override sealed bool IsSymmetric + { + get + { + return true; + } + } + + /// + /// Returns the transpose of this matrix. The transpose is equal and this method returns a reference to this matrix. + /// + /// + /// The transpose of this matrix. + /// + public override sealed Matrix Transpose() + { + return this.Clone(); + } + + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The result of the addition. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Add(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoAdd(other, result); + return result; + } + + /// + /// Adds another matrix to this matrix. + /// + /// + /// The matrix to add to this matrix. + /// + /// + /// The matrix to store the result of the addition. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoAdd(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric + non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoAdd(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) + symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The result of the subtraction. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Subtract(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoSubtract(other, result); + return result; + } + + + /// + /// Subtracts another matrix from this matrix. + /// + /// + /// The matrix to subtract to this matrix. + /// + /// + /// The matrix to store the result of subtraction. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoSubtract(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric - non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoSubtract(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) - symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// + /// The scalar to multiply the matrix with. + /// + /// + /// The matrix to store the result of the multiplication. + /// + protected override void DoMultiply(float scalar, Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoMultiply(scalar, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) * scalar); + } + } + } + } + + /// + /// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix. + /// + /// + /// The matrix to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Matrix other, Matrix result) + { + DoMultiply(other, result); + } + + /// + /// Multiplies the transpose of this matrix with a vector and places the results into the result vector. + /// + /// + /// The vector to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Vector rightSide, Vector result) + { + DoMultiply(rightSide, result); + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// + /// The result of the negation. + /// + protected override void DoNegate(Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoNegate(result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column != ColumnCount; column++) + { + symmetricResult[row, column] = -At(row, column); + } + } + } + } + + /// + /// Pointwise multiplies this matrix with another matrix. + /// + /// 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 override Matrix PointwiseMultiply(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other, "other"); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseMultiply(other, result); + return result; + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise multiply with this one. + /// + /// + /// The matrix to store the result of the pointwise multiplication. + /// + protected override void DoPointwiseMultiply(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric pointwise* non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoPointwiseMultiply(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) * symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Pointwise divide this matrix by another matrix. + /// + /// 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 override Matrix PointwiseDivide(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseDivide(other, result); + return result; + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise divide this one by. + /// + /// + /// The matrix to store the result of the pointwise division. + /// + protected override void DoPointwiseDivide(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric pointwise/ non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoPointwiseDivide(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) / symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Computes the modulus for each element of the matrix. + /// + /// + /// The divisor to use. + /// + /// + /// Matrix to store the results in. + /// + protected override void DoModulus(float divisor, Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoModulus(divisor, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) % divisor); + } + } + } + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix matrix, IContinuousDistribution distribution) + { + var symmetricMatrix = matrix as SymmetricMatrix; + + if (symmetricMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var row = 0; row < matrix.RowCount; row++) + { + for (var column = row; column < matrix.ColumnCount; column++) + { + symmetricMatrix.At(row, column, Convert.ToSingle(distribution.Sample())); + } + } + } + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix matrix, IDiscreteDistribution distribution) + { + var symmetricMatrix = matrix as SymmetricMatrix; + if (symmetricMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var row = 0; row < matrix.RowCount; row++) + { + for (var column = row; column < matrix.ColumnCount; column++) + { + symmetricMatrix.At(row, column, distribution.Sample()); + } + } + } + } + + /// + /// 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 override Matrix InsertColumn(int columnIndex, Vector column) + { + throw new InvalidOperationException("Inserting a column is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given array to the specified column. The changes retain the symmetry of the matrix. + /// + /// 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 override void SetColumn(int columnIndex, float[] 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"); + } + + for (var i = 0; i < columnIndex; i++) + { + At(i, columnIndex, column[i]); + } + } + + /// + /// Copies the values of the given Vector to the specified column. The changes retain the symmetry of the matrix. + /// + /// 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 override 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"); + } + + for (var i = 0; i < columnIndex; i++) + { + 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 override Matrix InsertRow(int rowIndex, Vector row) + { + throw new InvalidOperationException("Inserting a row is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given Vector 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 override 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"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } + + /// + /// Copies the values of the given array to the specified row. + /// + /// 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 override void SetRow(int rowIndex, float[] row) + { + if (rowIndex < 0 || rowIndex >= RowCount) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (row == null) + { + throw new ArgumentNullException("row"); + } + + if (row.Length != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 035cb821..65423828 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -143,6 +143,9 @@ + + + From 07f563d7e43c42060f6161ad2aed4bb71d1da437 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 14:37:45 +0200 Subject: [PATCH 25/33] [SymmetricDenseMatrix] Trace(): remove redundant check for square matrix since symm matrices are always square Signed-off-by: Alexander Karatarakis --- src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs | 7 +------ src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs index d989a081..f5624d1e 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs @@ -529,14 +529,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// Computes the trace of this matrix. /// /// The trace of this matrix - /// If the matrix is not square public override double Trace() { - if (RowCount != ColumnCount) - { - throw new ArgumentException(Resources.ArgumentMatrixSquare); - } - + // Matrix is always square. var sum = 0.0; for (var i = 0; i < RowCount; i++) { diff --git a/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs index 2f9d7251..7b6068c4 100644 --- a/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs @@ -529,14 +529,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// Computes the trace of this matrix. /// /// The trace of this matrix - /// If the matrix is not square public override float Trace() { - if (RowCount != ColumnCount) - { - throw new ArgumentException(Resources.ArgumentMatrixSquare); - } - + // Matrix is always square. var sum = 0.0f; for (var i = 0; i < RowCount; i++) { From d0b140accec849f57ffeb992d97b84912a6bd1f4 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 14:55:37 +0200 Subject: [PATCH 26/33] Add Complex version of Symmetric matrix Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Complex/SquareMatrix.cs | 62 ++ .../Complex/SymmetricDenseMatrix.cs | 769 ++++++++++++++++++ .../LinearAlgebra/Complex/SymmetricMatrix.cs | 712 ++++++++++++++++ src/Numerics/Numerics.csproj | 3 + 4 files changed, 1546 insertions(+) create mode 100644 src/Numerics/LinearAlgebra/Complex/SquareMatrix.cs create mode 100644 src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs create mode 100644 src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs diff --git a/src/Numerics/LinearAlgebra/Complex/SquareMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SquareMatrix.cs new file mode 100644 index 00000000..2e95ea27 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex/SquareMatrix.cs @@ -0,0 +1,62 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex +{ + using System; + using System.Numerics; + using Properties; + using Storage; + + /// + /// Abstract class for square matrices. + /// + [Serializable] + public abstract class SquareMatrix : Matrix + { + /// + /// Number of rows or columns. + /// + protected readonly int Order; + + /// + /// Initializes a new instance of the class. + /// + /// + /// If the matrix is not square. + /// + protected SquareMatrix(MatrixStorage storage) + : base(storage) + { + if (storage.RowCount != storage.ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + Order = storage.RowCount; + } + } +} diff --git a/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs new file mode 100644 index 00000000..311cdbd1 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs @@ -0,0 +1,769 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex +{ + using System; + using System.Numerics; + using Generic; + using MathNet.Numerics.Distributions; + using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static; + using Properties; + using Storage; + + /// + /// A Symmetric Matrix class with dense storage. + /// + /// The underlying storage is a one dimensional array in column-major order. + /// The Upper Triangle is stored(it is equal to the Lower Triangle) + [Serializable] + public class SymmetricDenseMatrix : SymmetricMatrix + { + readonly DenseColumnMajorSymmetricMatrixStorage _storage; + + /// + /// Gets the matrix's data. + /// + /// The matrix's data. + readonly Complex[] _data; + + internal SymmetricDenseMatrix(DenseColumnMajorSymmetricMatrixStorage storage) + : base(storage) + { + _storage = storage; + _data = _storage.Data; + } + + /// + /// Initializes a new instance of the class. This matrix is square with a given size. + /// + /// The order of the matrix. + /// + /// If is less than one. + /// + public SymmetricDenseMatrix(int order) + : this(new DenseColumnMajorSymmetricMatrixStorage(order)) + { + } + + /// + /// Initializes a new instance of the class with all entries set to a particular value. + /// + /// + /// The order of the matrix. + /// + /// The value which we assign to each element of the matrix. + /// Forcing user to input (int, int, Complex) because only asking (int, Complex) would + /// create a signature easily confused with (int, int) which is already used + public SymmetricDenseMatrix(int order, Complex value) + : this(order) + { + for (var i = 0; i < _data.Length; i++) + { + _data[i] = value; + } + } + + /// + /// Initializes a new instance of the class from a one dimensional array. This constructor + /// will reference the one dimensional array and not copy it. + /// + /// The size of the square matrix. + /// + /// The one dimensional array to create this matrix from. Column-major and row-major order is identical on a symmetric matrix: http://en.wikipedia.org/wiki/Row-major_order + /// + /// + /// If does not represent a packed array. + /// + public SymmetricDenseMatrix(int order, Complex[] array) + : this(new DenseColumnMajorSymmetricMatrixStorage(order, array)) + { + } + + /// + /// Initializes a new instance of the class from a 2D array. This constructor + /// will allocate a completely new memory block for storing the symmetric dense matrix. + /// + /// The 2D array to create this matrix from. + /// + /// If is not a square array. + /// + /// + /// If is not a symmetric array. + /// + public SymmetricDenseMatrix(Complex[,] array) + : this(array.GetLength(0)) + { + if (!CheckIfSymmetric(array)) + { + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + } + + var indexer = new PackedStorageIndexerUpper(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + _data[indexer.Of(row, column)] = array[row, column]; + } + } + } + + /// + /// Initializes a new instance of the class, copying + /// the values from the given matrix. Matrix must be Symmetric. + /// + /// The matrix to copy. + /// + /// If is not a square matrix. + /// + /// + /// If is not a symmetric matrix. + /// + public SymmetricDenseMatrix(Matrix matrix) + : this(matrix.RowCount) + { + var symmetricMatrix = matrix as SymmetricDenseMatrix; + + if (!matrix.IsSymmetric) + { + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + } + + if (symmetricMatrix == null) + { + var indexer = new PackedStorageIndexerUpper(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + _data[indexer.Of(row, column)] = matrix[row, column]; + } + } + } + else + { + matrix.CopyTo(this); + } + } + + /// + /// Gets the matrix's data. + /// + /// The matrix's data. + public Complex[] Data + { + get { return _data; } + } + + /// + /// Creates a SymmetricDenseMatrix for the given number of rows and columns. + /// If rows and columns are not equal, returns a DenseMatrix instead. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// True if all fields must be mutable (e.g. not a diagonal matrix). + /// + /// A DenseMatrix or SymmetricDenseMatrix with the given dimensions. + /// + /// /// + /// If is not equal to . + /// Symmetric arrays are always square + /// + public override Matrix CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false) + { + if (numberOfRows != numberOfColumns || fullyMutable) + { + return new DenseMatrix(numberOfRows, numberOfColumns); + } + + return new SymmetricDenseMatrix(numberOfRows); + } + + /// + /// Creates a with a the given dimension. + /// + /// The size of the vector. + /// True if all fields must be mutable. + /// + /// A with the given dimension. + /// + public override Vector CreateVector(int size, bool fullyMutable = false) + { + return new DenseVector(size); + } + + #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 symmetric dense identity matrix. + /// + /// If is less than one. + /// + public static SymmetricDenseMatrix Identity(int order) + { + var m = new SymmetricDenseMatrix(order); + for (var i = 0; i < order; i++) + { + m.At(i, i, 1.0); + } + + return m; + } + + #endregion + + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The matrix to store the result of add + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + protected override void DoAdd(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + if (denseOther == null || denseResult == null) + { + base.DoAdd(other, result); + } + else + { + Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The matrix to store the result of the subtraction. + protected override void DoSubtract(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + if (denseOther == null || denseResult == null) + { + base.DoSubtract(other, result); + } + else + { + Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// The scalar to multiply the matrix with. + /// The matrix to store the result of the multiplication. + protected override void DoMultiply(Complex scalar, Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + if (denseResult == null) + { + base.DoMultiply(scalar, result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data); + } + } + + /// + /// Multiplies this matrix with a vector and places the results into the result vector. + /// + /// The vector to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Vector rightSide, Vector result) + { + var denseRight = rightSide as DenseVector; + var denseResult = result as DenseVector; + + if (denseRight == null || denseResult == null) + { + base.DoMultiply(rightSide, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoMultiply(rightSide, result); + } + } + + /// + /// Multiplies this matrix with another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoMultiply(other, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoMultiply(other, result); + } + } + + /// + /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoTransposeAndMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoTransposeAndMultiply(other, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoTransposeAndMultiply(other, result); + } + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// The result of the negation. + protected override void DoNegate(Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + + if (denseResult == null) + { + base.DoNegate(result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data); + } + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise multiply with this one. + /// The matrix to store the result of the pointwise multiplication. + protected override void DoPointwiseMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoPointwiseMultiply(other, result); + } + else + { + Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise divide this one by. + /// The matrix to store the result of the pointwise division. + protected override void DoPointwiseDivide(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoPointwiseDivide(other, result); + } + else + { + Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Returns a new matrix containing the lower triangle of this matrix. + /// + /// The lower triangle of this matrix. + public override Matrix LowerTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = 0; column <= row; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// 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 override Matrix StrictlyLowerTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = 0; column < row; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// Returns a new matrix containing the upper triangle of this matrix. + /// + /// The upper triangle of this matrix. + public override Matrix UpperTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// 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 override Matrix StrictlyUpperTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row + 1; column < Order; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// Computes the trace of this matrix. + /// + /// The trace of this matrix + public override Complex Trace() + { + // Matrix is always square. + var sum = Complex.Zero; + for (var i = 0; i < RowCount; i++) + { + sum += At(i, i); + } + + return sum; + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix matrix, IContinuousDistribution distribution) + { + var denseMatrix = matrix as SymmetricDenseMatrix; + + if (denseMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var i = 0; i < denseMatrix._data.Length; i++) + { + denseMatrix._data[i] = distribution.Sample(); + } + } + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix matrix, IDiscreteDistribution distribution) + { + var denseMatrix = matrix as SymmetricDenseMatrix; + + if (denseMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var i = 0; i < denseMatrix._data.Length; i++) + { + denseMatrix._data[i] = distribution.Sample(); + } + } + } + + /// + /// 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 SymmetricDenseMatrix operator +(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Add(rightSide); + } + + /// + /// Returns a Matrix containing the same values of . + /// + /// The matrix to get the values from. + /// A matrix containing a the same values as . + /// If is . + public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Clone(); + } + + /// + /// 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 SymmetricDenseMatrix operator -(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Subtract(rightSide); + } + + /// + /// Negates each element of the matrix. + /// + /// The matrix to negate. + /// A matrix containing the negated values. + /// If is . + public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Negate(); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, Complex rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(Complex leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Multiply(leftSide); + } + + /// + /// Multiplies two matrices. + /// + /// 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 multiply. + /// The right matrix to multiply. + /// The result of multiplication. + /// If or is . + /// If the dimensions of or don't conform. + public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide.ColumnCount != rightSide.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Matrix and a Vector. + /// + /// The matrix to multiply. + /// The vector to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(SymmetricDenseMatrix leftSide, DenseVector rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (DenseVector)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Vector and a Matrix. + /// + /// The vector to multiply. + /// The matrix to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(DenseVector leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (DenseVector)rightSide.LeftMultiply(leftSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator %(SymmetricDenseMatrix leftSide, Complex rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Modulus(rightSide); + } + } +} \ No newline at end of file diff --git a/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs new file mode 100644 index 00000000..2b29f837 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs @@ -0,0 +1,712 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex +{ + using System; + using System.Numerics; + using Generic; + using Distributions; + using Properties; + using Storage; + + + /// + /// Abstract class for symmetric matrices. + /// + [Serializable] + public abstract class SymmetricMatrix : SquareMatrix + { + /// + /// Initializes a new instance of the class. + /// + protected SymmetricMatrix(MatrixStorage storage) + : base(storage) + { + } + + /// + /// Returns a value indicating whether the array is symmetric. + /// + /// + /// The array to check for symmetry. + /// + /// + /// True is array is symmetric, false if not symmetric. + /// + public static bool CheckIfSymmetric(Complex[,] array) + { + var rows = array.GetLength(0); + var columns = array.GetLength(1); + + if (rows != columns) + { + return false; + } + + for (var row = 0; row < rows; row++) + { + for (var column = 0; column < columns; column++) + { + if (column >= row) + { + continue; + } + + if (!array[row, column].Equals(array[column, row])) + { + return false; + } + } + } + + return true; + } + + /// + /// Gets a value indicating whether this matrix is symmetric. + /// + public override sealed bool IsSymmetric + { + get + { + return true; + } + } + + /// + /// Returns the transpose of this matrix. The transpose is equal and this method returns a reference to this matrix. + /// + /// + /// The transpose of this matrix. + /// + public override sealed Matrix Transpose() + { + return this.Clone(); + } + + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The result of the addition. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Add(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoAdd(other, result); + return result; + } + + /// + /// Adds another matrix to this matrix. + /// + /// + /// The matrix to add to this matrix. + /// + /// + /// The matrix to store the result of the addition. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoAdd(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric + non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoAdd(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) + symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The result of the subtraction. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Subtract(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoSubtract(other, result); + return result; + } + + + /// + /// Subtracts another matrix from this matrix. + /// + /// + /// The matrix to subtract to this matrix. + /// + /// + /// The matrix to store the result of subtraction. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoSubtract(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric - non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoSubtract(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) - symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// + /// The scalar to multiply the matrix with. + /// + /// + /// The matrix to store the result of the multiplication. + /// + protected override void DoMultiply(Complex scalar, Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoMultiply(scalar, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) * scalar); + } + } + } + } + + /// + /// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix. + /// + /// + /// The matrix to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Matrix other, Matrix result) + { + DoMultiply(other, result); + } + + /// + /// Multiplies the transpose of this matrix with a vector and places the results into the result vector. + /// + /// + /// The vector to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Vector rightSide, Vector result) + { + DoMultiply(rightSide, result); + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// + /// The result of the negation. + /// + protected override void DoNegate(Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoNegate(result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column != ColumnCount; column++) + { + symmetricResult[row, column] = -At(row, column); + } + } + } + } + + /// + /// Pointwise multiplies this matrix with another matrix. + /// + /// 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 override Matrix PointwiseMultiply(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other, "other"); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseMultiply(other, result); + return result; + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise multiply with this one. + /// + /// + /// The matrix to store the result of the pointwise multiplication. + /// + protected override void DoPointwiseMultiply(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric pointwise* non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoPointwiseMultiply(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) * symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Pointwise divide this matrix by another matrix. + /// + /// 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 override Matrix PointwiseDivide(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseDivide(other, result); + return result; + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise divide this one by. + /// + /// + /// The matrix to store the result of the pointwise division. + /// + protected override void DoPointwiseDivide(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric pointwise/ non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoPointwiseDivide(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) / symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Computes the modulus for each element of the matrix. + /// + /// + /// The divisor to use. + /// + /// + /// Matrix to store the results in. + /// + protected override void DoModulus(Complex divisor, Matrix result) + { + throw new NotImplementedException(); + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix matrix, IContinuousDistribution distribution) + { + var symmetricMatrix = matrix as SymmetricMatrix; + + if (symmetricMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var row = 0; row < matrix.RowCount; row++) + { + for (var column = row; column < matrix.ColumnCount; column++) + { + symmetricMatrix.At(row, column, distribution.Sample()); + } + } + } + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix matrix, IDiscreteDistribution distribution) + { + var symmetricMatrix = matrix as SymmetricMatrix; + if (symmetricMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var row = 0; row < matrix.RowCount; row++) + { + for (var column = row; column < matrix.ColumnCount; column++) + { + symmetricMatrix.At(row, column, distribution.Sample()); + } + } + } + } + + /// + /// 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 override Matrix InsertColumn(int columnIndex, Vector column) + { + throw new InvalidOperationException("Inserting a column is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given array to the specified column. The changes retain the symmetry of the matrix. + /// + /// 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 override void SetColumn(int columnIndex, Complex[] 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"); + } + + for (var i = 0; i < columnIndex; i++) + { + At(i, columnIndex, column[i]); + } + } + + /// + /// Copies the values of the given Vector to the specified column. The changes retain the symmetry of the matrix. + /// + /// 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 override 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"); + } + + for (var i = 0; i < columnIndex; i++) + { + 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 override Matrix InsertRow(int rowIndex, Vector row) + { + throw new InvalidOperationException("Inserting a row is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given Vector 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 override 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"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } + + /// + /// Copies the values of the given array to the specified row. + /// + /// 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 override void SetRow(int rowIndex, Complex[] row) + { + if (rowIndex < 0 || rowIndex >= RowCount) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (row == null) + { + throw new ArgumentNullException("row"); + } + + if (row.Length != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 65423828..b0666824 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -140,6 +140,9 @@ + + + From 11ceb277b0c7291cea58a0e708d2781f1553920f Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 14:57:19 +0200 Subject: [PATCH 27/33] Normalize using statements Signed-off-by: Alexander Karatarakis --- src/Numerics/LinearAlgebra/Double/SquareMatrix.cs | 5 ++--- .../LinearAlgebra/Double/SymmetricDenseMatrix.cs | 8 +++----- src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs | 9 ++++----- src/Numerics/LinearAlgebra/Single/SquareMatrix.cs | 5 ++--- .../LinearAlgebra/Single/SymmetricDenseMatrix.cs | 8 +++----- src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs | 9 ++++----- 6 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs b/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs index 32c61ef3..f7a72e8c 100644 --- a/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SquareMatrix.cs @@ -27,9 +27,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double { using System; - - using MathNet.Numerics.LinearAlgebra.Storage; - using MathNet.Numerics.Properties; + using Properties; + using Storage; /// /// Abstract class for square matrices. diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs index f5624d1e..fcb06c32 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs @@ -27,14 +27,12 @@ namespace MathNet.Numerics.LinearAlgebra.Double { using System; - using Distributions; using Generic; - - using MathNet.Numerics.LinearAlgebra.Storage; + using MathNet.Numerics.Distributions; using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static; - + using MathNet.Numerics.Threading; using Properties; - using Threading; + using Storage; /// /// A Symmetric Matrix class with dense storage. diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs index a7beffd6..eabc0072 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs @@ -27,11 +27,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double { using System; - - using MathNet.Numerics.Distributions; - using MathNet.Numerics.LinearAlgebra.Generic; - using MathNet.Numerics.LinearAlgebra.Storage; - using MathNet.Numerics.Properties; + using Generic; + using Distributions; + using Properties; + using Storage; /// /// Abstract class for symmetric matrices. diff --git a/src/Numerics/LinearAlgebra/Single/SquareMatrix.cs b/src/Numerics/LinearAlgebra/Single/SquareMatrix.cs index 6e4aa990..c51efdfb 100644 --- a/src/Numerics/LinearAlgebra/Single/SquareMatrix.cs +++ b/src/Numerics/LinearAlgebra/Single/SquareMatrix.cs @@ -27,9 +27,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single { using System; - - using MathNet.Numerics.LinearAlgebra.Storage; - using MathNet.Numerics.Properties; + using Properties; + using Storage; /// /// Abstract class for square matrices. diff --git a/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs index 7b6068c4..cd4dfaae 100644 --- a/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs @@ -27,14 +27,12 @@ namespace MathNet.Numerics.LinearAlgebra.Single { using System; - using Distributions; using Generic; - - using MathNet.Numerics.LinearAlgebra.Storage; + using MathNet.Numerics.Distributions; using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static; - + using MathNet.Numerics.Threading; using Properties; - using Threading; + using Storage; /// /// A Symmetric Matrix class with dense storage. diff --git a/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs index 0183fc0a..8cb1bc70 100644 --- a/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs @@ -27,11 +27,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single { using System; - - using MathNet.Numerics.Distributions; - using MathNet.Numerics.LinearAlgebra.Generic; - using MathNet.Numerics.LinearAlgebra.Storage; - using MathNet.Numerics.Properties; + using Generic; + using Distributions; + using Properties; + using Storage; /// /// Abstract class for symmetric matrices. From 3654f3b3f0c1876f01adc52d8621b43930710e7c Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 14:58:05 +0200 Subject: [PATCH 28/33] Remove obsolete remark Signed-off-by: Alexander Karatarakis --- src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs | 2 -- src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs | 2 -- src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs index 311cdbd1..4929e555 100644 --- a/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs @@ -76,8 +76,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// The order of the matrix. /// /// The value which we assign to each element of the matrix. - /// Forcing user to input (int, int, Complex) because only asking (int, Complex) would - /// create a signature easily confused with (int, int) which is already used public SymmetricDenseMatrix(int order, Complex value) : this(order) { diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs index fcb06c32..1a952572 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs @@ -76,8 +76,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// The order of the matrix. /// /// The value which we assign to each element of the matrix. - /// Forcing user to input (int, int, double) because only asking (int, double) would - /// create a signature easily confused with (int, int) which is already used public SymmetricDenseMatrix(int order, double value) : this(order) { diff --git a/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs index cd4dfaae..cef55387 100644 --- a/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs @@ -76,8 +76,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// The order of the matrix. /// /// The value which we assign to each element of the matrix. - /// Forcing user to input (int, int, double) because only asking (int, double) would - /// create a signature easily confused with (int, int) which is already used public SymmetricDenseMatrix(int order, float value) : this(order) { From a5b9e7eabc3865feb4eae1bb38cf467cf3c7d34b Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 15:11:10 +0200 Subject: [PATCH 29/33] Add Complex32 version of Symmetric matrix Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Complex/SymmetricMatrix.cs | 1 - .../LinearAlgebra/Complex32/SquareMatrix.cs | 62 ++ .../Complex32/SymmetricDenseMatrix.cs | 767 ++++++++++++++++++ .../Complex32/SymmetricMatrix.cs | 711 ++++++++++++++++ src/Numerics/Numerics.csproj | 3 + 5 files changed, 1543 insertions(+), 1 deletion(-) create mode 100644 src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs create mode 100644 src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs create mode 100644 src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs diff --git a/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs index 2b29f837..ba6d712f 100644 --- a/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs @@ -33,7 +33,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex using Properties; using Storage; - /// /// Abstract class for symmetric matrices. /// diff --git a/src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs new file mode 100644 index 00000000..337a5118 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs @@ -0,0 +1,62 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex32 +{ + using System; + using Numerics; + using Properties; + using Storage; + + /// + /// Abstract class for square matrices. + /// + [Serializable] + public abstract class SquareMatrix : Matrix + { + /// + /// Number of rows or columns. + /// + protected readonly int Order; + + /// + /// Initializes a new instance of the class. + /// + /// + /// If the matrix is not square. + /// + protected SquareMatrix(MatrixStorage storage) + : base(storage) + { + if (storage.RowCount != storage.ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + Order = storage.RowCount; + } + } +} diff --git a/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs new file mode 100644 index 00000000..7e62c4d7 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs @@ -0,0 +1,767 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex32 +{ + using System; + using Numerics; + using Generic; + using MathNet.Numerics.Distributions; + using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static; + using Properties; + using Storage; + + /// + /// A Symmetric Matrix class with dense storage. + /// + /// The underlying storage is a one dimensional array in column-major order. + /// The Upper Triangle is stored(it is equal to the Lower Triangle) + [Serializable] + public class SymmetricDenseMatrix : SymmetricMatrix + { + readonly DenseColumnMajorSymmetricMatrixStorage _storage; + + /// + /// Gets the matrix's data. + /// + /// The matrix's data. + readonly Complex32[] _data; + + internal SymmetricDenseMatrix(DenseColumnMajorSymmetricMatrixStorage storage) + : base(storage) + { + _storage = storage; + _data = _storage.Data; + } + + /// + /// Initializes a new instance of the class. This matrix is square with a given size. + /// + /// The order of the matrix. + /// + /// If is less than one. + /// + public SymmetricDenseMatrix(int order) + : this(new DenseColumnMajorSymmetricMatrixStorage(order)) + { + } + + /// + /// Initializes a new instance of the class with all entries set to a particular value. + /// + /// + /// The order of the matrix. + /// + /// The value which we assign to each element of the matrix. + public SymmetricDenseMatrix(int order, Complex32 value) + : this(order) + { + for (var i = 0; i < _data.Length; i++) + { + _data[i] = value; + } + } + + /// + /// Initializes a new instance of the class from a one dimensional array. This constructor + /// will reference the one dimensional array and not copy it. + /// + /// The size of the square matrix. + /// + /// The one dimensional array to create this matrix from. Column-major and row-major order is identical on a symmetric matrix: http://en.wikipedia.org/wiki/Row-major_order + /// + /// + /// If does not represent a packed array. + /// + public SymmetricDenseMatrix(int order, Complex32[] array) + : this(new DenseColumnMajorSymmetricMatrixStorage(order, array)) + { + } + + /// + /// Initializes a new instance of the class from a 2D array. This constructor + /// will allocate a completely new memory block for storing the symmetric dense matrix. + /// + /// The 2D array to create this matrix from. + /// + /// If is not a square array. + /// + /// + /// If is not a symmetric array. + /// + public SymmetricDenseMatrix(Complex32[,] array) + : this(array.GetLength(0)) + { + if (!CheckIfSymmetric(array)) + { + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + } + + var indexer = new PackedStorageIndexerUpper(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + _data[indexer.Of(row, column)] = array[row, column]; + } + } + } + + /// + /// Initializes a new instance of the class, copying + /// the values from the given matrix. Matrix must be Symmetric. + /// + /// The matrix to copy. + /// + /// If is not a square matrix. + /// + /// + /// If is not a symmetric matrix. + /// + public SymmetricDenseMatrix(Matrix matrix) + : this(matrix.RowCount) + { + var symmetricMatrix = matrix as SymmetricDenseMatrix; + + if (!matrix.IsSymmetric) + { + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + } + + if (symmetricMatrix == null) + { + var indexer = new PackedStorageIndexerUpper(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + _data[indexer.Of(row, column)] = matrix[row, column]; + } + } + } + else + { + matrix.CopyTo(this); + } + } + + /// + /// Gets the matrix's data. + /// + /// The matrix's data. + public Complex32[] Data + { + get { return _data; } + } + + /// + /// Creates a SymmetricDenseMatrix for the given number of rows and columns. + /// If rows and columns are not equal, returns a DenseMatrix instead. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// True if all fields must be mutable (e.g. not a diagonal matrix). + /// + /// A DenseMatrix or SymmetricDenseMatrix with the given dimensions. + /// + /// /// + /// If is not equal to . + /// Symmetric arrays are always square + /// + public override Matrix CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false) + { + if (numberOfRows != numberOfColumns || fullyMutable) + { + return new DenseMatrix(numberOfRows, numberOfColumns); + } + + return new SymmetricDenseMatrix(numberOfRows); + } + + /// + /// Creates a with a the given dimension. + /// + /// The size of the vector. + /// True if all fields must be mutable. + /// + /// A with the given dimension. + /// + public override Vector CreateVector(int size, bool fullyMutable = false) + { + return new DenseVector(size); + } + + #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 symmetric dense identity matrix. + /// + /// If is less than one. + /// + public static SymmetricDenseMatrix Identity(int order) + { + var m = new SymmetricDenseMatrix(order); + for (var i = 0; i < order; i++) + { + m.At(i, i, 1.0f); + } + + return m; + } + + #endregion + + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The matrix to store the result of add + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + protected override void DoAdd(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + if (denseOther == null || denseResult == null) + { + base.DoAdd(other, result); + } + else + { + Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The matrix to store the result of the subtraction. + protected override void DoSubtract(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + if (denseOther == null || denseResult == null) + { + base.DoSubtract(other, result); + } + else + { + Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// The scalar to multiply the matrix with. + /// The matrix to store the result of the multiplication. + protected override void DoMultiply(Complex32 scalar, Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + if (denseResult == null) + { + base.DoMultiply(scalar, result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data); + } + } + + /// + /// Multiplies this matrix with a vector and places the results into the result vector. + /// + /// The vector to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Vector rightSide, Vector result) + { + var denseRight = rightSide as DenseVector; + var denseResult = result as DenseVector; + + if (denseRight == null || denseResult == null) + { + base.DoMultiply(rightSide, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoMultiply(rightSide, result); + } + } + + /// + /// Multiplies this matrix with another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoMultiply(other, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoMultiply(other, result); + } + } + + /// + /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoTransposeAndMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoTransposeAndMultiply(other, result); + } + else + { + // TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers. + base.DoTransposeAndMultiply(other, result); + } + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// The result of the negation. + protected override void DoNegate(Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + + if (denseResult == null) + { + base.DoNegate(result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data); + } + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise multiply with this one. + /// The matrix to store the result of the pointwise multiplication. + protected override void DoPointwiseMultiply(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoPointwiseMultiply(other, result); + } + else + { + Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise divide this one by. + /// The matrix to store the result of the pointwise division. + protected override void DoPointwiseDivide(Matrix other, Matrix result) + { + var denseOther = other as SymmetricDenseMatrix; + var denseResult = result as SymmetricDenseMatrix; + + if (denseOther == null || denseResult == null) + { + base.DoPointwiseDivide(other, result); + } + else + { + Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data); + } + } + + /// + /// Returns a new matrix containing the lower triangle of this matrix. + /// + /// The lower triangle of this matrix. + public override Matrix LowerTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = 0; column <= row; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// 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 override Matrix StrictlyLowerTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = 0; column < row; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// Returns a new matrix containing the upper triangle of this matrix. + /// + /// The upper triangle of this matrix. + public override Matrix UpperTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row; column < Order; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// 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 override Matrix StrictlyUpperTriangle() + { + var ret = new DenseMatrix(Order); + for (var row = 0; row < Order; row++) + { + for (var column = row + 1; column < Order; column++) + { + ret[row, column] = At(row, column); + } + } + + return ret; + } + + /// + /// Computes the trace of this matrix. + /// + /// The trace of this matrix + public override Complex32 Trace() + { + // Matrix is always square. + var sum = Complex32.Zero; + for (var i = 0; i < RowCount; i++) + { + sum += At(i, i); + } + + return sum; + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix matrix, IContinuousDistribution distribution) + { + var denseMatrix = matrix as SymmetricDenseMatrix; + + if (denseMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var i = 0; i < denseMatrix._data.Length; i++) + { + denseMatrix._data[i] = Convert.ToSingle(distribution.Sample()); + } + } + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix matrix, IDiscreteDistribution distribution) + { + var denseMatrix = matrix as SymmetricDenseMatrix; + + if (denseMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var i = 0; i < denseMatrix._data.Length; i++) + { + denseMatrix._data[i] = distribution.Sample(); + } + } + } + + /// + /// 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 SymmetricDenseMatrix operator +(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Add(rightSide); + } + + /// + /// Returns a Matrix containing the same values of . + /// + /// The matrix to get the values from. + /// A matrix containing a the same values as . + /// If is . + public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Clone(); + } + + /// + /// 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 SymmetricDenseMatrix operator -(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (leftSide.RowCount != rightSide.RowCount) + { + throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Subtract(rightSide); + } + + /// + /// Negates each element of the matrix. + /// + /// The matrix to negate. + /// A matrix containing the negated values. + /// If is . + public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Negate(); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, Complex32 rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(Complex32 leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Multiply(leftSide); + } + + /// + /// Multiplies two matrices. + /// + /// 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 multiply. + /// The right matrix to multiply. + /// The result of multiplication. + /// If or is . + /// If the dimensions of or don't conform. + public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + if (leftSide.ColumnCount != rightSide.RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixDimensions); + } + + return (SymmetricDenseMatrix)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Matrix and a Vector. + /// + /// The matrix to multiply. + /// The vector to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(SymmetricDenseMatrix leftSide, DenseVector rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (DenseVector)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Vector and a Matrix. + /// + /// The vector to multiply. + /// The matrix to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(DenseVector leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (DenseVector)rightSide.LeftMultiply(leftSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator %(SymmetricDenseMatrix leftSide, Complex32 rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Modulus(rightSide); + } + } +} \ No newline at end of file diff --git a/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs new file mode 100644 index 00000000..099df458 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs @@ -0,0 +1,711 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex32 +{ + using System; + using Numerics; + using Generic; + using Distributions; + using Properties; + using Storage; + + /// + /// Abstract class for symmetric matrices. + /// + [Serializable] + public abstract class SymmetricMatrix : SquareMatrix + { + /// + /// Initializes a new instance of the class. + /// + protected SymmetricMatrix(MatrixStorage storage) + : base(storage) + { + } + + /// + /// Returns a value indicating whether the array is symmetric. + /// + /// + /// The array to check for symmetry. + /// + /// + /// True is array is symmetric, false if not symmetric. + /// + public static bool CheckIfSymmetric(Complex32[,] array) + { + var rows = array.GetLength(0); + var columns = array.GetLength(1); + + if (rows != columns) + { + return false; + } + + for (var row = 0; row < rows; row++) + { + for (var column = 0; column < columns; column++) + { + if (column >= row) + { + continue; + } + + if (!array[row, column].Equals(array[column, row])) + { + return false; + } + } + } + + return true; + } + + /// + /// Gets a value indicating whether this matrix is symmetric. + /// + public override sealed bool IsSymmetric + { + get + { + return true; + } + } + + /// + /// Returns the transpose of this matrix. The transpose is equal and this method returns a reference to this matrix. + /// + /// + /// The transpose of this matrix. + /// + public override sealed Matrix Transpose() + { + return this.Clone(); + } + + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The result of the addition. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Add(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoAdd(other, result); + return result; + } + + /// + /// Adds another matrix to this matrix. + /// + /// + /// The matrix to add to this matrix. + /// + /// + /// The matrix to store the result of the addition. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoAdd(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric + non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoAdd(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) + symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The result of the subtraction. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Subtract(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoSubtract(other, result); + return result; + } + + + /// + /// Subtracts another matrix from this matrix. + /// + /// + /// The matrix to subtract to this matrix. + /// + /// + /// The matrix to store the result of subtraction. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoSubtract(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric - non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoSubtract(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) - symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// + /// The scalar to multiply the matrix with. + /// + /// + /// The matrix to store the result of the multiplication. + /// + protected override void DoMultiply(Complex32 scalar, Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoMultiply(scalar, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) * scalar); + } + } + } + } + + /// + /// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix. + /// + /// + /// The matrix to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Matrix other, Matrix result) + { + DoMultiply(other, result); + } + + /// + /// Multiplies the transpose of this matrix with a vector and places the results into the result vector. + /// + /// + /// The vector to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Vector rightSide, Vector result) + { + DoMultiply(rightSide, result); + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// + /// The result of the negation. + /// + protected override void DoNegate(Matrix result) + { + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult == null) + { + base.DoNegate(result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column != ColumnCount; column++) + { + symmetricResult[row, column] = -At(row, column); + } + } + } + } + + /// + /// Pointwise multiplies this matrix with another matrix. + /// + /// 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 override Matrix PointwiseMultiply(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other, "other"); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseMultiply(other, result); + return result; + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise multiply with this one. + /// + /// + /// The matrix to store the result of the pointwise multiplication. + /// + protected override void DoPointwiseMultiply(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric pointwise* non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoPointwiseMultiply(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) * symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Pointwise divide this matrix by another matrix. + /// + /// 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 override Matrix PointwiseDivide(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseDivide(other, result); + return result; + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise divide this one by. + /// + /// + /// The matrix to store the result of the pointwise division. + /// + protected override void DoPointwiseDivide(Matrix other, Matrix result) + { + var symmetricOther = other as SymmetricMatrix; + var symmetricResult = result as SymmetricMatrix; + + if (symmetricResult != null && !other.IsSymmetric) + { + throw new InvalidOperationException("Symmetric pointwise/ non-symmetric matrix cannot be a symmetric matrix"); + } + + if (symmetricOther == null || symmetricResult == null) + { + base.DoPointwiseDivide(other, result); + } + else + { + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + symmetricResult.At(row, column, At(row, column) / symmetricOther.At(row, column)); + } + } + } + } + + /// + /// Computes the modulus for each element of the matrix. + /// + /// + /// The divisor to use. + /// + /// + /// Matrix to store the results in. + /// + protected override void DoModulus(Complex32 divisor, Matrix result) + { + throw new NotImplementedException(); + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix matrix, IContinuousDistribution distribution) + { + var symmetricMatrix = matrix as SymmetricMatrix; + + if (symmetricMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var row = 0; row < matrix.RowCount; row++) + { + for (var column = row; column < matrix.ColumnCount; column++) + { + symmetricMatrix.At(row, column, Convert.ToSingle(distribution.Sample())); + } + } + } + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix matrix, IDiscreteDistribution distribution) + { + var symmetricMatrix = matrix as SymmetricMatrix; + if (symmetricMatrix == null) + { + base.DoRandom(matrix, distribution); + } + else + { + for (var row = 0; row < matrix.RowCount; row++) + { + for (var column = row; column < matrix.ColumnCount; column++) + { + symmetricMatrix.At(row, column, distribution.Sample()); + } + } + } + } + + /// + /// 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 override Matrix InsertColumn(int columnIndex, Vector column) + { + throw new InvalidOperationException("Inserting a column is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given array to the specified column. The changes retain the symmetry of the matrix. + /// + /// 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 override void SetColumn(int columnIndex, Complex32[] 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"); + } + + for (var i = 0; i < columnIndex; i++) + { + At(i, columnIndex, column[i]); + } + } + + /// + /// Copies the values of the given Vector to the specified column. The changes retain the symmetry of the matrix. + /// + /// 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 override 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"); + } + + for (var i = 0; i < columnIndex; i++) + { + 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 override Matrix InsertRow(int rowIndex, Vector row) + { + throw new InvalidOperationException("Inserting a row is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given Vector 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 override 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"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } + + /// + /// Copies the values of the given array to the specified row. + /// + /// 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 override void SetRow(int rowIndex, Complex32[] row) + { + if (rowIndex < 0 || rowIndex >= RowCount) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (row == null) + { + throw new ArgumentNullException("row"); + } + + if (row.Length != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index b0666824..6ea108fb 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -140,6 +140,9 @@ + + + From 4cd1c829c5a7adfbf3218222ecc7fc01de11a62b Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 15:51:16 +0200 Subject: [PATCH 30/33] Add Unit tests for Single version of Symmetric matrix Signed-off-by: Alexander Karatarakis --- .../Single/SymmetricDenseMatrixTests.cs | 215 ++++++++++++++++++ .../Single/SymmetricMatrixTests.Arithmetic.cs | 191 ++++++++++++++++ .../Single/SymmetricMatrixTests.cs | 123 ++++++++++ src/UnitTests/UnitTests.csproj | 3 + 4 files changed, 532 insertions(+) create mode 100644 src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs diff --git a/src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs new file mode 100644 index 00000000..5ec190c2 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs @@ -0,0 +1,215 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single +{ + using System; + using System.Collections.Generic; + + using MathNet.Numerics.LinearAlgebra.Single; + + using NUnit.Framework; + + /// + /// Symmetric Dense matrix tests. + /// + public class SymmetricDenseMatrixTests : SymmetricMatrixTests + { + /// + /// Creates a matrix for the given number of rows and columns. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// + /// A matrix with the given dimensions. + /// + protected override Matrix CreateMatrix(int rows, int columns) + { + return new DenseMatrix(rows, columns); + } + + /// + /// Creates a matrix from a 2D array. + /// + /// + /// The 2D array to create this matrix from. + /// + /// + /// A matrix with the given values. + /// + protected override Matrix CreateMatrix(float[,] data) + { + if (SymmetricMatrix.CheckIfSymmetric(data)) + { + return new SymmetricDenseMatrix(data); + } + + return new DenseMatrix(data); + } + + /// + /// Creates a vector of the given size. + /// + /// + /// The size of the vector to create. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(int size) + { + return new DenseVector(size); + } + + /// + /// Creates a vector from an array. + /// + /// + /// The array to create this vector from. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(float[] data) + { + return new DenseVector(data); + } + + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom1DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(3, new[] { 1.0f, 2.0f, 0.0f, 3.0f, 0.0f, 0.0f }) }, + { "Square3x3", new SymmetricDenseMatrix(3, new[] { -1.1f, 2.0f, 1.1f, 3.0f, 0.0f, 6.6f }) }, + { "Square4x4", new SymmetricDenseMatrix(4, new[] { 1.1f, 2.0f, 5.0f, -3.0f, -6.0f, 8.0f, 4.4f, 7.0f, 9.0f, 10.0f }) }, + { "Singular4x4", new SymmetricDenseMatrix(4, new[] { 1.0f, 2.0f, 5.0f, 0.0f, 0.0f, 0.0f, 4.0f, 7.0f, 0.0f, 10.0f }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(3, new[] { 1.0f, 2.0f, 2.0f, 3.0f, 0.0f, 3.0f }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(4, new [] { 0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } + + /// + /// Matrix from array is a reference. + /// + [Test] + public void MatrixFrom1DArrayIsReference() + { + var data = new float[] { 1, 1, 1, 1, 1, 1 }; + var matrix = new SymmetricDenseMatrix(3, data); + matrix[0, 0] = 10.0f; + Assert.AreEqual(10.0f, data[0]); + } + + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom2DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(new[,] { { 1.0f, 2.0f, 3.0f }, { 2.0f, 0.0f, 0.0f }, { 3.0f, 0.0f, 0.0f } }) }, + { "Square3x3", new SymmetricDenseMatrix(new[,] { { -1.1f, 2.0f, 3.0f }, { 2.0f, 1.1f, 0.0f }, { 3.0f, 0.0f, 6.6f } }) }, + { "Square4x4", new SymmetricDenseMatrix(new[,] { { 1.1f, 2.0f, -3.0f, 4.4f }, { 2.0f, 5.0f, -6.0f, 7.0f }, { -3.0f, -6.0f, 8.0f, 9.0f }, { 4.4f, 7.0f, 9.0f, 10.0f } }) }, + { "Singular4x4", new SymmetricDenseMatrix(new[,] { { 1.0f, 2.0f, 0.0f, 4.0f }, { 2.0f, 5.0f, 0.0f, 7.0f }, { 0.0f, 0.0f, 0.0f, 0.0f }, { 4.0f, 7.0f, 0.0f, 10.0f } }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(new[,] { { 1.0f, 2.0f, 3.0f }, { 2.0f, 2.0f, 0.0f }, { 3.0f, 0.0f, 3.0f } }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(new [,] { { 0f, 1f, 3f, 6f }, { 1f, 2f, 4f, 7f }, { 3f, 4f, 5f, 8f }, { 6f, 7f, 8f, 9f } }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } + + /// + /// Matrix from two-dimensional array is a copy. + /// + [Test] + public void MatrixFrom2DArrayIsCopy() + { + var matrix = new DenseMatrix(TestData2D["Singular3x3"]); + matrix[0, 0] = 10.0f; + Assert.AreEqual(1.0f, TestData2D["Singular3x3"][0, 0]); + } + + /// + /// Can create a matrix with uniform values. + /// + [Test] + public void CanCreateMatrixWithUniformValues() + { + var matrix = new SymmetricDenseMatrix(10, 10.0f); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], 10.0f); + } + } + } + + /// + /// Can create an identity matrix. + /// + [Test] + public void CanCreateIdentity() + { + var matrix = SymmetricDenseMatrix.Identity(5); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(i == j ? 1.0f : 0.0f, matrix[i, j]); + } + } + } + + /// + /// Identity with wrong order throws ArgumentOutOfRangeException. + /// + /// The size of the square matrix + [TestCase(0)] + [TestCase(-1)] + public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException(int order) + { + Assert.Throws(() => SymmetricDenseMatrix.Identity(order)); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs new file mode 100644 index 00000000..331ac876 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs @@ -0,0 +1,191 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single +{ + using System.Collections.Generic; + using LinearAlgebra.Single; + using NUnit.Framework; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices + /// + public abstract partial class SymmetricMatrixTests + { + /// + /// Setup test matrices. + /// Singular and Square matrices are overridden here with symmetric ones so that calls to base methods work as intended. + /// Additional NonSymmetric matrices are defined for some tests. + /// + [SetUp] + public override void SetupMatrices() + { + TestData2D = new Dictionary + { + { "Singular3x3", new[,] { { 1.0f, 2.0f, 3.0f }, { 2.0f, 0.0f, 0.0f }, { 3.0f, 0.0f, 0.0f } } }, + { "Square3x3", new[,] { { -1.1f, 2.0f, 3.0f }, { 2.0f, 1.1f, 0.0f }, { 3.0f, 0.0f, 6.6f } } }, + { "Square4x4", new[,] { { 1.1f, 2.0f, -3.0f, 4.4f }, { 2.0f, 5.0f, -6.0f, 7.0f }, { -3.0f, -6.0f, 8.0f, 9.0f }, { 4.4f, 7.0f, 9.0f, 10.0f } } }, + { "Singular4x4", new[,] { { 1.0f, 2.0f, 0.0f, 4.0f }, { 2.0f, 5.0f, 0.0f, 7.0f }, { 0.0f, 0.0f, 0.0f, 0.0f }, { 4.0f, 7.0f, 0.0f, 10.0f } } }, + { "Tall3x2", new[,] { { -1.1f, -2.2f }, { 0.0f, 1.1f }, { -4.4f, 5.5f } } }, + { "Wide2x3", new[,] { { -1.1f, -2.2f, -3.3f }, { 0.0f, 1.1f, 2.2f } } }, + { "Symmetric3x3", new[,] { { 1.0f, 2.0f, 3.0f }, { 2.0f, 2.0f, 0.0f }, { 3.0f, 0.0f, 3.0f } } }, + { "NonSymmetric3x3", new[,] { { -1.1f, -2.2f, -3.3f }, { 0.0f, 1.1f, 2.2f }, { -4.4f, 5.5f, 6.6f } } }, + { "NonSymmetric4x4", new[,] { { -1.1f, -2.2f, -3.3f, -4.4f }, { 0.0f, 1.1f, 2.2f, 3.3f }, { 1.0f, 2.1f, 6.2f, 4.3f }, { -4.4f, 5.5f, 6.6f, -7.7f } } }, + { "IndexTester4x4", new [,] { { 0f, 1f, 3f, 6f }, { 1f, 2f, 4f, 7f }, { 3f, 4f, 5f, 8f }, { 6f, 7f, 8f, 9f } } } + }; + + TestMatrices = new Dictionary(); + + foreach (var name in TestData2D.Keys) + { + TestMatrices.Add(name, CreateMatrix(TestData2D[name])); + } + } + + /// + /// Can add a non-symmetric matrix to this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanAddNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Add(matrixB); + + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] + matrixB[i, j]); + } + } + } + + /// + /// Can subtract a non-symmetric matrix from this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanSubtractNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Subtract(matrixB); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] - matrixB[i, j]); + } + } + } + + /// + /// Can compute Frobenius norm. + /// + public override void CanComputeFrobeniusNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + } + + + + /// + /// Can compute Infinity norm. + /// + public override void CanComputeInfinityNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + } + + + + /// + /// Can compute L1 norm. + /// + public override void CanComputeL1Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + } + + + + /// + /// Can compute L2 norm. + /// + public override void CanComputeL2Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs new file mode 100644 index 00000000..a0b9d4e5 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs @@ -0,0 +1,123 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single +{ + using MathNet.Numerics.LinearAlgebra.Single; + using NUnit.Framework; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices. + /// + public abstract partial class SymmetricMatrixTests : MatrixTests + { + /// + /// Can check if a matrix is symmetric. + /// + [Test] + public override void CanCheckIfMatrixIsSymmetric() + { + var matrix = TestMatrices["Square3x3"]; + Assert.IsTrue(matrix.IsSymmetric); + + matrix = TestMatrices["NonSymmetric3x3"]; + Assert.IsFalse(matrix.IsSymmetric); + } + + /// + /// Can check if a [,] array is symmetric. + /// + [Test] + public void CanCheckIfArrayIsSymmetric() + { + Assert.IsTrue(SymmetricMatrix.CheckIfSymmetric(TestData2D["Square3x3"])); + Assert.IsFalse(SymmetricMatrix.CheckIfSymmetric(TestData2D["NonSymmetric3x3"])); + } + + /// + /// Test whether the index enumerator returns the correct values. + /// + [Test] + public void CanUseIndexedEnumerator() + { + var matrix = TestMatrices["Singular3x3"]; + var enumerator = matrix.IndexedEnumerator().GetEnumerator(); + enumerator.MoveNext(); + var item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(1.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(2.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(3.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(2.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(0.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(0.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(3.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(0.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(0.0, item.Item3); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index e8b5f237..aa47b7eb 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -721,6 +721,9 @@ Code + + + Code From 38a8b1f01b610a8d25effcf35088c1bbea73cd51 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 20:55:13 +0200 Subject: [PATCH 31/33] [SymmetricMatrix] Disable SetRow/Column() for symmetric matrices Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Complex/SymmetricMatrix.cs | 80 +------------------ .../Complex32/SymmetricMatrix.cs | 80 +------------------ .../LinearAlgebra/Double/SymmetricMatrix.cs | 80 +------------------ .../LinearAlgebra/Single/SymmetricMatrix.cs | 80 +------------------ 4 files changed, 16 insertions(+), 304 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs index ba6d712f..9b996511 100644 --- a/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs @@ -574,25 +574,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// equal the number of rows of this Matrix. public override void SetColumn(int columnIndex, Complex[] 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"); - } - - for (var i = 0; i < columnIndex; i++) - { - At(i, columnIndex, column[i]); - } + throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -607,25 +589,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// equal the number of rows of this Matrix. public override 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"); - } - - for (var i = 0; i < columnIndex; i++) - { - At(i, columnIndex, column[i]); - } + throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -654,25 +618,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// equal the number of columns of this Matrix. public override 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"); - } - - for (var i = rowIndex; i < ColumnCount; i++) - { - At(rowIndex, i, row[i]); - } + throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -687,25 +633,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex /// equal the number of columns of this Matrix. public override void SetRow(int rowIndex, Complex[] row) { - if (rowIndex < 0 || rowIndex >= RowCount) - { - throw new ArgumentOutOfRangeException("rowIndex"); - } - - if (row == null) - { - throw new ArgumentNullException("row"); - } - - if (row.Length != ColumnCount) - { - throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); - } - - for (var i = rowIndex; i < ColumnCount; i++) - { - At(rowIndex, i, row[i]); - } + throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry"); } } } diff --git a/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs index 099df458..6d84785b 100644 --- a/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs @@ -574,25 +574,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// equal the number of rows of this Matrix. public override void SetColumn(int columnIndex, Complex32[] 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"); - } - - for (var i = 0; i < columnIndex; i++) - { - At(i, columnIndex, column[i]); - } + throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -607,25 +589,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// equal the number of rows of this Matrix. public override 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"); - } - - for (var i = 0; i < columnIndex; i++) - { - At(i, columnIndex, column[i]); - } + throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -654,25 +618,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// equal the number of columns of this Matrix. public override 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"); - } - - for (var i = rowIndex; i < ColumnCount; i++) - { - At(rowIndex, i, row[i]); - } + throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -687,25 +633,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 /// equal the number of columns of this Matrix. public override void SetRow(int rowIndex, Complex32[] row) { - if (rowIndex < 0 || rowIndex >= RowCount) - { - throw new ArgumentOutOfRangeException("rowIndex"); - } - - if (row == null) - { - throw new ArgumentNullException("row"); - } - - if (row.Length != ColumnCount) - { - throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); - } - - for (var i = rowIndex; i < ColumnCount; i++) - { - At(rowIndex, i, row[i]); - } + throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry"); } } } diff --git a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs index eabc0072..a00a0206 100644 --- a/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs @@ -588,25 +588,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// equal the number of rows of this Matrix. public override 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"); - } - - for (var i = 0; i < columnIndex; i++) - { - At(i, columnIndex, column[i]); - } + throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -621,25 +603,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// equal the number of rows of this Matrix. public override 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"); - } - - for (var i = 0; i < columnIndex; i++) - { - At(i, columnIndex, column[i]); - } + throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -668,25 +632,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// equal the number of columns of this Matrix. public override 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"); - } - - for (var i = rowIndex; i < ColumnCount; i++) - { - At(rowIndex, i, row[i]); - } + throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -701,25 +647,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double /// equal the number of columns of this Matrix. public override void SetRow(int rowIndex, double[] row) { - if (rowIndex < 0 || rowIndex >= RowCount) - { - throw new ArgumentOutOfRangeException("rowIndex"); - } - - if (row == null) - { - throw new ArgumentNullException("row"); - } - - if (row.Length != ColumnCount) - { - throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); - } - - for (var i = rowIndex; i < ColumnCount; i++) - { - At(rowIndex, i, row[i]); - } + throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry"); } } } diff --git a/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs index 8cb1bc70..1ec1d112 100644 --- a/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs @@ -588,25 +588,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// equal the number of rows of this Matrix. public override void SetColumn(int columnIndex, float[] 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"); - } - - for (var i = 0; i < columnIndex; i++) - { - At(i, columnIndex, column[i]); - } + throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -621,25 +603,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// equal the number of rows of this Matrix. public override 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"); - } - - for (var i = 0; i < columnIndex; i++) - { - At(i, columnIndex, column[i]); - } + throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -668,25 +632,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// equal the number of columns of this Matrix. public override 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"); - } - - for (var i = rowIndex; i < ColumnCount; i++) - { - At(rowIndex, i, row[i]); - } + throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry"); } /// @@ -701,25 +647,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single /// equal the number of columns of this Matrix. public override void SetRow(int rowIndex, float[] row) { - if (rowIndex < 0 || rowIndex >= RowCount) - { - throw new ArgumentOutOfRangeException("rowIndex"); - } - - if (row == null) - { - throw new ArgumentNullException("row"); - } - - if (row.Length != ColumnCount) - { - throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); - } - - for (var i = rowIndex; i < ColumnCount; i++) - { - At(rowIndex, i, row[i]); - } + throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry"); } } } From e55400ef41fd132704fbc12f8dec369245837468 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 21:29:13 +0200 Subject: [PATCH 32/33] Add Unit tests for Comples version of Symmetric matrix and fix bugs Signed-off-by: Alexander Karatarakis --- .../Complex/SymmetricDenseMatrix.cs | 2 +- .../LinearAlgebra/Complex/SymmetricMatrix.cs | 18 ++ .../Complex/SymmetricDenseMatrixTests.cs | 217 ++++++++++++++++++ .../SymmetricMatrixTests.Arithmetic.cs | 192 ++++++++++++++++ .../Complex/SymmetricMatrixTests.cs | 124 ++++++++++ src/UnitTests/UnitTests.csproj | 3 + 6 files changed, 555 insertions(+), 1 deletion(-) create mode 100644 src/UnitTests/LinearAlgebraTests/Complex/SymmetricDenseMatrixTests.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.Arithmetic.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.cs diff --git a/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs index 4929e555..df3305a0 100644 --- a/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs @@ -233,7 +233,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex var m = new SymmetricDenseMatrix(order); for (var i = 0; i < order; i++) { - m.At(i, i, 1.0); + m.At(i, i, Complex.One); } return m; diff --git a/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs index 9b996511..6f1b5975 100644 --- a/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs @@ -107,6 +107,24 @@ namespace MathNet.Numerics.LinearAlgebra.Complex return this.Clone(); } + /// + /// Returns the conjugate transpose of this matrix. + /// + /// The conjugate transpose of this matrix. + public override Matrix ConjugateTranspose() + { + var ret = CreateMatrix(ColumnCount, RowCount); + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + ret.At(row, column, At(column, row).Conjugate()); + } + } + + return ret; + } + /// /// Adds another matrix to this matrix. /// diff --git a/src/UnitTests/LinearAlgebraTests/Complex/SymmetricDenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/SymmetricDenseMatrixTests.cs new file mode 100644 index 00000000..08d8b3f1 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Complex/SymmetricDenseMatrixTests.cs @@ -0,0 +1,217 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex +{ + using System; + using System.Collections.Generic; + using System.Numerics; + + using MathNet.Numerics.LinearAlgebra.Complex; + + using NUnit.Framework; + + /// + /// Symmetric Dense matrix tests. + /// + public class SymmetricDenseMatrixTests : SymmetricMatrixTests + { + /// + /// Creates a matrix for the given number of rows and columns. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// + /// A matrix with the given dimensions. + /// + protected override Matrix CreateMatrix(int rows, int columns) + { + return new DenseMatrix(rows, columns); + } + + /// + /// Creates a matrix from a 2D array. + /// + /// + /// The 2D array to create this matrix from. + /// + /// + /// A matrix with the given values. + /// + protected override Matrix CreateMatrix(Complex[,] data) + { + if (SymmetricMatrix.CheckIfSymmetric(data)) + { + return new SymmetricDenseMatrix(data); + } + + return new DenseMatrix(data); + } + + /// + /// Creates a vector of the given size. + /// + /// + /// The size of the vector to create. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(int size) + { + return new DenseVector(size); + } + + /// + /// Creates a vector from an array. + /// + /// + /// The array to create this vector from. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(Complex[] data) + { + return new DenseVector(data); + } + + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom1DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(3, new[] { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(0.0, 1), new Complex(3.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }) }, + { "Square3x3", new SymmetricDenseMatrix(3, new[] { new Complex(-1.1, 1), new Complex(2.0, 1), new Complex(1.1, 1), new Complex(3.0, 1), new Complex(0.0, 1), new Complex(6.6, 1) }) }, + { "Square4x4", new SymmetricDenseMatrix(4, new[] { new Complex(1.1, 1), new Complex(2.0, 1), new Complex(5.0, 1), new Complex(-3.0, 1), new Complex(-6.0, 1), new Complex(8.0, 1), new Complex(4.4, 1), new Complex(7.0, 1), new Complex(9.0, 1), new Complex(10.0, 1) }) }, + { "Singular4x4", new SymmetricDenseMatrix(4, new[] { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(5.0, 1), new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1), new Complex(4.0, 1), new Complex(7.0, 1), new Complex(0.0, 1), new Complex(10.0, 1) }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(3, new[] { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(2.0, 1), new Complex(3.0, 1), new Complex(0.0, 1), new Complex(3.0, 1) }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(4, new [] { new Complex(0, 1), new Complex(1, 1), new Complex(2, 1), new Complex(3, 1), new Complex(4, 1), new Complex(5, 1), new Complex(6, 1), new Complex(7, 1), new Complex(8, 1), new Complex(9, 1) }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } + + /// + /// Matrix from array is a reference. + /// + [Test] + public void MatrixFrom1DArrayIsReference() + { + var data = new Complex[] { new Complex(1, 1), new Complex(1, 1), new Complex(1, 1), new Complex(1, 1), new Complex(1, 1), new Complex(1, 1) }; + var matrix = new SymmetricDenseMatrix(3, data); + matrix[0, 0] = new Complex(10.0, 2); + Assert.AreEqual(new Complex(10.0, 2), data[0]); + } + + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom2DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) } }) }, + { "Square3x3", new SymmetricDenseMatrix(new[,] { { new Complex(-1.1, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(1.1, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(6.6, 1) } }) }, + { "Square4x4", new SymmetricDenseMatrix(new[,] { { new Complex(1.1, 1), new Complex(2.0, 1), new Complex(-3.0, 1), new Complex(4.4, 1) }, { new Complex(2.0, 1), new Complex(5.0, 1), new Complex(-6.0, 1), new Complex(7.0, 1) }, { new Complex(-3.0, 1), new Complex(-6.0, 1), new Complex(8.0, 1), new Complex(9.0, 1) }, { new Complex(4.4, 1), new Complex(7.0, 1), new Complex(9.0, 1), new Complex(10.0, 1) } }) }, + { "Singular4x4", new SymmetricDenseMatrix(new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(0.0, 1), new Complex(4.0, 1) }, { new Complex(2.0, 1), new Complex(5.0, 1), new Complex(0.0, 1), new Complex(7.0, 1) }, { new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }, { new Complex(4.0, 1), new Complex(7.0, 1), new Complex(0.0, 1), new Complex(10.0, 1) } }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(2.0, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(3.0, 1) } }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(new [,] { { new Complex(0, 1), new Complex(1, 1), new Complex(3, 1), new Complex(6, 1) }, { new Complex(1, 1), new Complex(2, 1), new Complex(4, 1), new Complex(7, 1) }, { new Complex(3, 1), new Complex(4, 1), new Complex(5, 1), new Complex(8, 1) }, { new Complex(6, 1), new Complex(7, 1), new Complex(8, 1), new Complex(9, 1) } }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } + + /// + /// Matrix from two-dimensional array is a copy. + /// + [Test] + public void MatrixFrom2DArrayIsCopy() + { + var matrix = new DenseMatrix(TestData2D["Singular3x3"]); + matrix[0, 0] = new Complex(10.0, 2); + Assert.AreEqual(new Complex(1.0, 1), TestData2D["Singular3x3"][0, 0]); + } + + /// + /// Can create a matrix with uniform values. + /// + [Test] + public void CanCreateMatrixWithUniformValues() + { + var matrix = new SymmetricDenseMatrix(10, new Complex(10.0, 2)); + var value = new Complex(10.0, 2); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], value); + } + } + } + + /// + /// Can create an identity matrix. + /// + [Test] + public void CanCreateIdentity() + { + var matrix = SymmetricDenseMatrix.Identity(5); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(i == j ? Complex.One : Complex.Zero, matrix[i, j]); + } + } + } + + /// + /// Identity with wrong order throws ArgumentOutOfRangeException. + /// + /// The size of the square matrix + [TestCase(0)] + [TestCase(-1)] + public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException(int order) + { + Assert.Throws(() => SymmetricDenseMatrix.Identity(order)); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.Arithmetic.cs new file mode 100644 index 00000000..d3c59ac3 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.Arithmetic.cs @@ -0,0 +1,192 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex +{ + using System.Collections.Generic; + using LinearAlgebra.Complex; + using NUnit.Framework; + using System.Numerics; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices + /// + public abstract partial class SymmetricMatrixTests + { + /// + /// Setup test matrices. + /// Singular and Square matrices are overridden here with symmetric ones so that calls to base methods work as intended. + /// Additional NonSymmetric matrices are defined for some tests. + /// + [SetUp] + public override void SetupMatrices() + { + TestData2D = new Dictionary + { + { "Singular3x3", new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) } } }, + { "Square3x3", new[,] { { new Complex(-1.1, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(1.1, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(6.6, 1) } } }, + { "Square4x4", new[,] { { new Complex(1.1, 1), new Complex(2.0, 1), new Complex(-3.0, 1), new Complex(4.4, 1) }, { new Complex(2.0, 1), new Complex(5.0, 1), new Complex(-6.0, 1), new Complex(7.0, 1) }, { new Complex(-3.0, 1), new Complex(-6.0, 1), new Complex(8.0, 1), new Complex(9.0, 1) }, { new Complex(4.4, 1), new Complex(7.0, 1), new Complex(9.0, 1), new Complex(10.0, 1) } } }, + { "Singular4x4", new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(0.0, 1), new Complex(4.0, 1) }, { new Complex(2.0, 1), new Complex(5.0, 1), new Complex(0.0, 1), new Complex(7.0, 1) }, { new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }, { new Complex(4.0, 1), new Complex(7.0, 1), new Complex(0.0, 1), new Complex(10.0, 1) } } }, + { "Tall3x2", new[,] { { new Complex(-1.1, 1), new Complex(-2.2, 1) }, { new Complex(0.0, 1), new Complex(1.1, 1) }, { new Complex(-4.4, 1), new Complex(5.5, 1) } } }, + { "Wide2x3", new[,] { { new Complex(-1.1, 1), new Complex(-2.2, 1), new Complex(-3.3, 1) }, { new Complex(0.0, 1), new Complex(1.1, 1), new Complex(2.2, 1) } } }, + { "Symmetric3x3", new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(2.0, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(3.0, 1) } } }, + { "NonSymmetric3x3", new[,] { { new Complex(-1.1, 1), new Complex(-2.2, 1), new Complex(-3.3, 1) }, { new Complex(0.0, 1), new Complex(1.1, 1), new Complex(2.2, 1) }, { new Complex(-4.4, 1), new Complex(5.5, 1), new Complex(6.6, 1) } } }, + { "NonSymmetric4x4", new[,] { { new Complex(-1.1, 1), new Complex(-2.2, 1), new Complex(-3.3, 1), new Complex(-4.4, 1) }, { new Complex(0.0, 1), new Complex(1.1, 1), new Complex(2.2, 1), new Complex(3.3, 1) }, { new Complex(1.0, 1), new Complex(2.1, 1), new Complex(6.2, 1), new Complex(4.3, 1) }, { new Complex(-4.4, 1), new Complex(5.5, 1), new Complex(6.6, 1), new Complex(-7.7, 1) } } }, + { "IndexTester4x4", new [,] { { new Complex(0, 1), new Complex(1, 1), new Complex(3, 1), new Complex(6, 1) }, { new Complex(1, 1), new Complex(2, 1), new Complex(4, 1), new Complex(7, 1) }, { new Complex(3, 1), new Complex(4, 1), new Complex(5, 1), new Complex(8, 1) }, { new Complex(6, 1), new Complex(7, 1), new Complex(8, 1), new Complex(9, 1) } } } + }; + + TestMatrices = new Dictionary(); + + foreach (var name in TestData2D.Keys) + { + TestMatrices.Add(name, CreateMatrix(TestData2D[name])); + } + } + + /// + /// Can add a non-symmetric matrix to this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanAddNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Add(matrixB); + + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] + matrixB[i, j]); + } + } + } + + /// + /// Can subtract a non-symmetric matrix from this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanSubtractNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Subtract(matrixB); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] - matrixB[i, j]); + } + } + } + + /// + /// Can compute Frobenius norm. + /// + public override void CanComputeFrobeniusNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + } + + + + /// + /// Can compute Infinity norm. + /// + public override void CanComputeInfinityNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + } + + + + /// + /// Can compute L1 norm. + /// + public override void CanComputeL1Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + } + + + + /// + /// Can compute L2 norm. + /// + public override void CanComputeL2Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.cs new file mode 100644 index 00000000..3121e9b8 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.cs @@ -0,0 +1,124 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex +{ + using System.Numerics; + using MathNet.Numerics.LinearAlgebra.Complex; + using NUnit.Framework; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices. + /// + public abstract partial class SymmetricMatrixTests : MatrixTests + { + /// + /// Can check if a matrix is symmetric. + /// + [Test] + public override void CanCheckIfMatrixIsSymmetric() + { + var matrix = TestMatrices["Square3x3"]; + Assert.IsTrue(matrix.IsSymmetric); + + matrix = TestMatrices["NonSymmetric3x3"]; + Assert.IsFalse(matrix.IsSymmetric); + } + + /// + /// Can check if a [,] array is symmetric. + /// + [Test] + public void CanCheckIfArrayIsSymmetric() + { + Assert.IsTrue(SymmetricMatrix.CheckIfSymmetric(TestData2D["Square3x3"])); + Assert.IsFalse(SymmetricMatrix.CheckIfSymmetric(TestData2D["NonSymmetric3x3"])); + } + + /// + /// Test whether the index enumerator returns the correct values. + /// + [Test] + public void CanUseIndexedEnumerator() + { + var matrix = TestMatrices["Singular3x3"]; + var enumerator = matrix.IndexedEnumerator().GetEnumerator(); + enumerator.MoveNext(); + var item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(new Complex(1.0, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(new Complex(2.0, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(new Complex(3.0, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(new Complex(2.0, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(new Complex(0.0, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(new Complex(0.0, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(new Complex(3.0, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(new Complex(0.0, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(new Complex(0.0, 1), item.Item3); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index aa47b7eb..7ce13c00 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -420,6 +420,9 @@ Code + + + Code From 148ac01b6f4d698d99ced565eb8ac26c45030935 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 21:50:06 +0200 Subject: [PATCH 33/33] Add Unit tests for Complex32 version of Symmetric matrix and fix bugs Signed-off-by: Alexander Karatarakis --- .../Complex32/SymmetricDenseMatrix.cs | 2 +- .../Complex32/SymmetricMatrix.cs | 18 ++ .../Complex32/SymmetricDenseMatrixTests.cs | 217 ++++++++++++++++++ .../SymmetricMatrixTests.Arithmetic.cs | 192 ++++++++++++++++ .../Complex32/SymmetricMatrixTests.cs | 125 ++++++++++ src/UnitTests/UnitTests.csproj | 3 + 6 files changed, 556 insertions(+), 1 deletion(-) create mode 100644 src/UnitTests/LinearAlgebraTests/Complex32/SymmetricDenseMatrixTests.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.Arithmetic.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.cs diff --git a/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs index 7e62c4d7..38cbc136 100644 --- a/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs @@ -233,7 +233,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 var m = new SymmetricDenseMatrix(order); for (var i = 0; i < order; i++) { - m.At(i, i, 1.0f); + m.At(i, i, Complex32.One); } return m; diff --git a/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs index 6d84785b..e283fd63 100644 --- a/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs @@ -107,6 +107,24 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 return this.Clone(); } + /// + /// Returns the conjugate transpose of this matrix. + /// + /// The conjugate transpose of this matrix. + public override Matrix ConjugateTranspose() + { + var ret = CreateMatrix(ColumnCount, RowCount); + for (var row = 0; row < RowCount; row++) + { + for (var column = row; column < ColumnCount; column++) + { + ret.At(row, column, At(column, row).Conjugate()); + } + } + + return ret; + } + /// /// Adds another matrix to this matrix. /// diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/SymmetricDenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/SymmetricDenseMatrixTests.cs new file mode 100644 index 00000000..75747b33 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Complex32/SymmetricDenseMatrixTests.cs @@ -0,0 +1,217 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 +{ + using System; + using System.Collections.Generic; + using Numerics; + + using MathNet.Numerics.LinearAlgebra.Complex32; + + using NUnit.Framework; + + /// + /// Symmetric Dense matrix tests. + /// + public class SymmetricDenseMatrixTests : SymmetricMatrixTests + { + /// + /// Creates a matrix for the given number of rows and columns. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// + /// A matrix with the given dimensions. + /// + protected override Matrix CreateMatrix(int rows, int columns) + { + return new DenseMatrix(rows, columns); + } + + /// + /// Creates a matrix from a 2D array. + /// + /// + /// The 2D array to create this matrix from. + /// + /// + /// A matrix with the given values. + /// + protected override Matrix CreateMatrix(Complex32[,] data) + { + if (SymmetricMatrix.CheckIfSymmetric(data)) + { + return new SymmetricDenseMatrix(data); + } + + return new DenseMatrix(data); + } + + /// + /// Creates a vector of the given size. + /// + /// + /// The size of the vector to create. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(int size) + { + return new DenseVector(size); + } + + /// + /// Creates a vector from an array. + /// + /// + /// The array to create this vector from. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(Complex32[] data) + { + return new DenseVector(data); + } + + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom1DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(3, new[] { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }) }, + { "Square3x3", new SymmetricDenseMatrix(3, new[] { new Complex32(-1.1f, 1), new Complex32(2.0f, 1), new Complex32(1.1f, 1), new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(6.6f, 1) }) }, + { "Square4x4", new SymmetricDenseMatrix(4, new[] { new Complex32(1.1f, 1), new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(-3.0f, 1), new Complex32(-6.0f, 1), new Complex32(8.0f, 1), new Complex32(4.4f, 1), new Complex32(7.0f, 1), new Complex32(9.0f, 1), new Complex32(10.0f, 1) }) }, + { "Singular4x4", new SymmetricDenseMatrix(4, new[] { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(4.0f, 1), new Complex32(7.0f, 1), new Complex32(0.0f, 1), new Complex32(10.0f, 1) }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(3, new[] { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(3.0f, 1) }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(4, new [] { new Complex32(0, 1), new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1), new Complex32(6, 1), new Complex32(7, 1), new Complex32(8, 1), new Complex32(9, 1) }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } + + /// + /// Matrix from array is a reference. + /// + [Test] + public void MatrixFrom1DArrayIsReference() + { + var data = new Complex32[] { new Complex32(1, 1), new Complex32(1, 1), new Complex32(1, 1), new Complex32(1, 1), new Complex32(1, 1), new Complex32(1, 1) }; + var matrix = new SymmetricDenseMatrix(3, data); + matrix[0, 0] = new Complex32(10.0f, 2); + Assert.AreEqual(new Complex32(10.0f, 2), data[0]); + } + + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom2DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) } }) }, + { "Square3x3", new SymmetricDenseMatrix(new[,] { { new Complex32(-1.1f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(1.1f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(6.6f, 1) } }) }, + { "Square4x4", new SymmetricDenseMatrix(new[,] { { new Complex32(1.1f, 1), new Complex32(2.0f, 1), new Complex32(-3.0f, 1), new Complex32(4.4f, 1) }, { new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(-6.0f, 1), new Complex32(7.0f, 1) }, { new Complex32(-3.0f, 1), new Complex32(-6.0f, 1), new Complex32(8.0f, 1), new Complex32(9.0f, 1) }, { new Complex32(4.4f, 1), new Complex32(7.0f, 1), new Complex32(9.0f, 1), new Complex32(10.0f, 1) } }) }, + { "Singular4x4", new SymmetricDenseMatrix(new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(4.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(0.0f, 1), new Complex32(7.0f, 1) }, { new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(4.0f, 1), new Complex32(7.0f, 1), new Complex32(0.0f, 1), new Complex32(10.0f, 1) } }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(3.0f, 1) } }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(new [,] { { new Complex32(0, 1), new Complex32(1, 1), new Complex32(3, 1), new Complex32(6, 1) }, { new Complex32(1, 1), new Complex32(2, 1), new Complex32(4, 1), new Complex32(7, 1) }, { new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1), new Complex32(8, 1) }, { new Complex32(6, 1), new Complex32(7, 1), new Complex32(8, 1), new Complex32(9, 1) } }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } + + /// + /// Matrix from two-dimensional array is a copy. + /// + [Test] + public void MatrixFrom2DArrayIsCopy() + { + var matrix = new DenseMatrix(TestData2D["Singular3x3"]); + matrix[0, 0] = new Complex32(10.0f, 2); + Assert.AreEqual(new Complex32(1.0f, 1), TestData2D["Singular3x3"][0, 0]); + } + + /// + /// Can create a matrix with uniform values. + /// + [Test] + public void CanCreateMatrixWithUniformValues() + { + var matrix = new SymmetricDenseMatrix(10, new Complex32(10.0f, 2)); + var value = new Complex32(10.0f, 2); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], value); + } + } + } + + /// + /// Can create an identity matrix. + /// + [Test] + public void CanCreateIdentity() + { + var matrix = SymmetricDenseMatrix.Identity(5); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(i == j ? Complex32.One : Complex32.Zero, matrix[i, j]); + } + } + } + + /// + /// Identity with wrong order throws ArgumentOutOfRangeException. + /// + /// The size of the square matrix + [TestCase(0)] + [TestCase(-1)] + public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException(int order) + { + Assert.Throws(() => SymmetricDenseMatrix.Identity(order)); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.Arithmetic.cs new file mode 100644 index 00000000..3d924a53 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.Arithmetic.cs @@ -0,0 +1,192 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 +{ + using System.Collections.Generic; + using LinearAlgebra.Complex32; + using NUnit.Framework; + using Numerics; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices + /// + public abstract partial class SymmetricMatrixTests + { + /// + /// Setup test matrices. + /// Singular and Square matrices are overridden here with symmetric ones so that calls to base methods work as intended. + /// Additional NonSymmetric matrices are defined for some tests. + /// + [SetUp] + public override void SetupMatrices() + { + TestData2D = new Dictionary + { + { "Singular3x3", new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) } } }, + { "Square3x3", new[,] { { new Complex32(-1.1f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(1.1f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(6.6f, 1) } } }, + { "Square4x4", new[,] { { new Complex32(1.1f, 1), new Complex32(2.0f, 1), new Complex32(-3.0f, 1), new Complex32(4.4f, 1) }, { new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(-6.0f, 1), new Complex32(7.0f, 1) }, { new Complex32(-3.0f, 1), new Complex32(-6.0f, 1), new Complex32(8.0f, 1), new Complex32(9.0f, 1) }, { new Complex32(4.4f, 1), new Complex32(7.0f, 1), new Complex32(9.0f, 1), new Complex32(10.0f, 1) } } }, + { "Singular4x4", new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(4.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(0.0f, 1), new Complex32(7.0f, 1) }, { new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(4.0f, 1), new Complex32(7.0f, 1), new Complex32(0.0f, 1), new Complex32(10.0f, 1) } } }, + { "Tall3x2", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1) }, { new Complex32(0.0f, 1), new Complex32(1.1f, 1) }, { new Complex32(-4.4f, 1), new Complex32(5.5f, 1) } } }, + { "Wide2x3", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1) }, { new Complex32(0.0f, 1), new Complex32(1.1f, 1), new Complex32(2.2f, 1) } } }, + { "Symmetric3x3", new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(3.0f, 1) } } }, + { "NonSymmetric3x3", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1) }, { new Complex32(0.0f, 1), new Complex32(1.1f, 1), new Complex32(2.2f, 1) }, { new Complex32(-4.4f, 1), new Complex32(5.5f, 1), new Complex32(6.6f, 1) } } }, + { "NonSymmetric4x4", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1), new Complex32(-4.4f, 1) }, { new Complex32(0.0f, 1), new Complex32(1.1f, 1), new Complex32(2.2f, 1), new Complex32(3.3f, 1) }, { new Complex32(1.0f, 1), new Complex32(2.1f, 1), new Complex32(6.2f, 1), new Complex32(4.3f, 1) }, { new Complex32(-4.4f, 1), new Complex32(5.5f, 1), new Complex32(6.6f, 1), new Complex32(-7.7f, 1) } } }, + { "IndexTester4x4", new [,] { { new Complex32(0, 1), new Complex32(1, 1), new Complex32(3, 1), new Complex32(6, 1) }, { new Complex32(1, 1), new Complex32(2, 1), new Complex32(4, 1), new Complex32(7, 1) }, { new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1), new Complex32(8, 1) }, { new Complex32(6, 1), new Complex32(7, 1), new Complex32(8, 1), new Complex32(9, 1) } } } + }; + + TestMatrices = new Dictionary(); + + foreach (var name in TestData2D.Keys) + { + TestMatrices.Add(name, CreateMatrix(TestData2D[name])); + } + } + + /// + /// Can add a non-symmetric matrix to this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanAddNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Add(matrixB); + + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] + matrixB[i, j]); + } + } + } + + /// + /// Can subtract a non-symmetric matrix from this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanSubtractNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Subtract(matrixB); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] - matrixB[i, j]); + } + } + } + + /// + /// Can compute Frobenius norm. + /// + public override void CanComputeFrobeniusNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + } + + + + /// + /// Can compute Infinity norm. + /// + public override void CanComputeInfinityNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + } + + + + /// + /// Can compute L1 norm. + /// + public override void CanComputeL1Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + } + + + + /// + /// Can compute L2 norm. + /// + public override void CanComputeL2Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.cs new file mode 100644 index 00000000..03b4877d --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.cs @@ -0,0 +1,125 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 +{ + using MathNet.Numerics.LinearAlgebra.Complex32; + + using Numerics; + using NUnit.Framework; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices. + /// + public abstract partial class SymmetricMatrixTests : MatrixTests + { + /// + /// Can check if a matrix is symmetric. + /// + [Test] + public override void CanCheckIfMatrixIsSymmetric() + { + var matrix = TestMatrices["Square3x3"]; + Assert.IsTrue(matrix.IsSymmetric); + + matrix = TestMatrices["NonSymmetric3x3"]; + Assert.IsFalse(matrix.IsSymmetric); + } + + /// + /// Can check if a [,] array is symmetric. + /// + [Test] + public void CanCheckIfArrayIsSymmetric() + { + Assert.IsTrue(SymmetricMatrix.CheckIfSymmetric(TestData2D["Square3x3"])); + Assert.IsFalse(SymmetricMatrix.CheckIfSymmetric(TestData2D["NonSymmetric3x3"])); + } + + /// + /// Test whether the index enumerator returns the correct values. + /// + [Test] + public void CanUseIndexedEnumerator() + { + var matrix = TestMatrices["Singular3x3"]; + var enumerator = matrix.IndexedEnumerator().GetEnumerator(); + enumerator.MoveNext(); + var item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(new Complex32(1.0f, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(new Complex32(2.0f, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(new Complex32(3.0f, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(new Complex32(2.0f, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(new Complex32(0.0f, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(new Complex32(0.0f, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(new Complex32(3.0f, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(new Complex32(0.0f, 1), item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(new Complex32(0.0f, 1), item.Item3); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index 7ce13c00..7baa4f4b 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -272,6 +272,9 @@ Code + + + Code