diff --git a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs index 90c6bafa..0312a85a 100644 --- a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs @@ -595,6 +595,20 @@ namespace MathNet.Numerics.LinearAlgebra.Storage target.Values = values.ToArray(); } + internal override void TransposeSquareInplaceUnchecked() + { + for (var j = 0; j < ColumnCount; j++) + { + var index = j * RowCount; + for (var i = 0; i < j; i++) + { + T swap = Data[index + i]; + Data[index + i] = Data[i*ColumnCount + j]; + Data[i*ColumnCount + j] = swap; + } + } + } + // EXTRACT public override T[] ToRowMajorArray() diff --git a/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs index 05ae5191..58a315bd 100644 --- a/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs @@ -491,6 +491,11 @@ namespace MathNet.Numerics.LinearAlgebra.Storage CopyToUnchecked(target, existingData); } + internal override void TransposeSquareInplaceUnchecked() + { + // nothing to do + } + // EXTRACT public override T[] ToRowMajorArray() diff --git a/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs index 3f3f14e7..b8c65143 100644 --- a/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs @@ -467,17 +467,18 @@ namespace MathNet.Numerics.LinearAlgebra.Storage throw new ArgumentNullException("target"); } - if (ReferenceEquals(this, target)) - { - throw new NotSupportedException("In-place transpose is not supported."); - } - if (RowCount != target.ColumnCount || ColumnCount != target.RowCount) { var message = string.Format(Resources.ArgumentMatrixDimensions2, RowCount + "x" + ColumnCount, target.RowCount + "x" + target.ColumnCount); throw new ArgumentException(message, "target"); } + if (ReferenceEquals(this, target)) + { + TransposeSquareInplaceUnchecked(); + return; + } + TransposeToUnchecked(target, existingData); } @@ -492,6 +493,19 @@ namespace MathNet.Numerics.LinearAlgebra.Storage } } + internal virtual void TransposeSquareInplaceUnchecked() + { + for (int j = 0; j < ColumnCount; j++) + { + for (int i = 0; i < j; i++) + { + T swap = At(i, j); + At(i, j, At(j, i)); + At(j, i, swap); + } + } + } + // EXTRACT public virtual T[] ToRowMajorArray() diff --git a/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs index 840269e3..c5e29c31 100644 --- a/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs @@ -1154,6 +1154,46 @@ namespace MathNet.Numerics.LinearAlgebra.Storage } } + internal override void TransposeSquareInplaceUnchecked() + { + var cx = new T[ValueCount]; //target.Values; + var cp = new int[RowCount + 1]; + var ci = new int[ValueCount]; //target.ColumnIndices; + + // Column counts + int[] w = new int[ColumnCount]; + for (int p = 0; p < RowPointers[RowCount]; p++) + { + w[ColumnIndices[p]]++; + } + + // Column pointers + int nz = 0; + for (int i = 0; i < ColumnCount; i++) + { + cp[i] = nz; + nz += w[i]; + w[i] = cp[i]; + } + cp[ColumnCount] = nz; + + for (int i = 0; i < RowCount; i++) + { + for (int p = RowPointers[i]; p < RowPointers[i + 1]; p++) + { + int j = w[ColumnIndices[p]]++; + + // Place A(i,j) as entry C(j,i) + ci[j] = i; + cx[j] = Values[p]; + } + } + + Array.Copy(cx, 0, Values, 0, ValueCount); + Buffer.BlockCopy(ci, 0, ColumnIndices, 0, ValueCount * Constants.SizeOfInt); + Buffer.BlockCopy(cp, 0, RowPointers, 0, (RowCount + 1) * Constants.SizeOfInt); + } + // EXTRACT public override T[] ToRowMajorArray() diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs index 9bc51296..94b60341 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.cs @@ -27,6 +27,7 @@ // OTHER DEALINGS IN THE SOFTWARE. // +using MathNet.Numerics.LinearAlgebra; using NUnit.Framework; namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double @@ -62,6 +63,54 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } } + /// + /// Can transpose a matrix into a result. + /// + /// Matrix name. + [TestCase("Singular3x3")] + [TestCase("Square3x3")] + [TestCase("Square4x4")] + [TestCase("Tall3x2")] + [TestCase("Wide2x3")] + public void CanTransposeMatrixResult(string name) + { + var matrix = TestMatrices[name]; + var transpose = Matrix.Build.SameAs(matrix, matrix.ColumnCount, matrix.RowCount); + matrix.Transpose(transpose); + + Assert.AreNotSame(matrix, transpose); + Assert.AreEqual(matrix.RowCount, transpose.ColumnCount); + Assert.AreEqual(matrix.ColumnCount, transpose.RowCount); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], transpose[j, i]); + } + } + } + + /// + /// Can transpose a square matrix inplace. + /// + /// Matrix name. + [TestCase("Square4x4")] + public void CanTransposeSquareMatrixInplace(string name) + { + var matrix = TestMatrices[name]; + var transpose = matrix.Clone(); + transpose.Transpose(transpose); + + Assert.AreNotSame(matrix, transpose); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], transpose[j, i]); + } + } + } + /// /// Can compute Frobenius norm. ///