using System; using MathNet.Numerics.Properties; namespace MathNet.Numerics.LinearAlgebra.Storage { internal class SparseDiagonalMatrixStorage : MatrixStorage where T : struct, IEquatable, IFormattable { // [ruegg] public fields are OK here readonly T _zero; public readonly T[] Data; internal SparseDiagonalMatrixStorage(int rows, int columns, T zero) : base(rows, columns) { _zero = zero; Data = new T[Math.Min(rows, columns)]; } internal SparseDiagonalMatrixStorage(int rows, int columns, T zero, T[] data) : base(rows, columns) { _zero = zero; Data = data; } /// /// Retrieves the requested element without range checking. /// public override T At(int row, int column) { return row == column ? Data[row] : _zero; } /// /// Sets the element without range checking. /// public override void At(int row, int column, T value) { if (row == column) { Data[row] = value; } else if (!_zero.Equals(value)) { throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix."); } } public override void Clear() { Array.Clear(Data, 0, Data.Length); } public void CopyTo(MatrixStorage target, bool skipClearing = false) { var diagonalTarget = target as SparseDiagonalMatrixStorage; if (diagonalTarget != null) { CopyTo(diagonalTarget); return; } var denseTarget = target as DenseColumnMajorMatrixStorage; if (denseTarget != null) { CopyTo(denseTarget, skipClearing); return; } var sparseTarget = target as SparseCompressedRowMatrixStorage; if (sparseTarget != null) { CopyTo(sparseTarget, skipClearing); return; } // FALL BACK if (target == null) { throw new ArgumentNullException("target"); } if (RowCount != target.RowCount || ColumnCount != target.ColumnCount) { var message = string.Format(Resources.ArgumentMatrixDimensions2, RowCount + "x" + ColumnCount, target.RowCount + "x" + target.ColumnCount); throw new ArgumentException(message, "target"); } if (!skipClearing) { target.Clear(); } for (int i = 0; i < Data.Length; i++) { target.At(i, i, Data[i]); } } public void CopyTo(SparseDiagonalMatrixStorage target) { if (ReferenceEquals(this, target)) { return; } if (target == null) { throw new ArgumentNullException("target"); } if (RowCount != target.RowCount || ColumnCount != target.ColumnCount) { var message = string.Format(Resources.ArgumentMatrixDimensions2, RowCount + "x" + ColumnCount, target.RowCount + "x" + target.ColumnCount); throw new ArgumentException(message, "target"); } //Buffer.BlockCopy(Data, 0, target.Data, 0, Data.Length * System.Runtime.InteropServices.Marshal.SizeOf(typeof(T))); Array.Copy(Data, 0, target.Data, 0, Data.Length); } public void CopyTo(SparseCompressedRowMatrixStorage target, bool skipClearing = false) { if (target == null) { throw new ArgumentNullException("target"); } if (RowCount != target.RowCount || ColumnCount != target.ColumnCount) { var message = string.Format(Resources.ArgumentMatrixDimensions2, RowCount + "x" + ColumnCount, target.RowCount + "x" + target.ColumnCount); throw new ArgumentException(message, "target"); } if (!skipClearing) { target.Clear(); } for (int i = 0; i < Data.Length; i++) { target.At(i, i, Data[i]); } } public void CopyTo(DenseColumnMajorMatrixStorage target, bool skipClearing = false) { if (target == null) { throw new ArgumentNullException("target"); } if (RowCount != target.RowCount || ColumnCount != target.ColumnCount) { var message = string.Format(Resources.ArgumentMatrixDimensions2, RowCount + "x" + ColumnCount, target.RowCount + "x" + target.ColumnCount); throw new ArgumentException(message, "target"); } if (!skipClearing) { target.Clear(); } for (int i = 0; i < Data.Length; i++) { target.Data[i*(target.RowCount + 1)] = Data[i]; } } public void CopySubMatrixTo(DenseColumnMajorMatrixStorage target, int sourceRowIndex, int targetRowIndex, int rowCount, int sourceColumnIndex, int targetColumnIndex, int columnCount, bool skipClearing = false) { if (target == null) { throw new ArgumentNullException("target"); } ValidateSubMatrixRange(target, sourceRowIndex, targetRowIndex, rowCount, sourceColumnIndex, targetColumnIndex, columnCount); if (!skipClearing) { target.Clear(); } if (sourceRowIndex > sourceColumnIndex && sourceColumnIndex + columnCount > sourceRowIndex) { // column by column, but skip resulting zero columns at the beginning int columnInit = sourceRowIndex - sourceColumnIndex; int offset = (columnInit + targetColumnIndex) * target.RowCount + targetRowIndex; int step = target.RowCount + 1; int end = Math.Min(columnCount - columnInit, rowCount) + sourceRowIndex; for (int i = sourceRowIndex, j = offset; i < end; i++, j += step) { target.Data[j] = Data[i]; } } else if (sourceRowIndex < sourceColumnIndex && sourceRowIndex + rowCount > sourceColumnIndex) { // row by row, but skip resulting zero rows at the beginning int rowInit = sourceColumnIndex - sourceRowIndex; int offset = targetColumnIndex*target.RowCount + rowInit + targetRowIndex; int step = target.RowCount + 1; int end = Math.Min(columnCount, rowCount - rowInit) + sourceColumnIndex; for (int i = sourceColumnIndex, j = offset; i < end; i++, j += step) { target.Data[j] = Data[i]; } } else { int offset = targetColumnIndex*target.RowCount + targetRowIndex; int step = target.RowCount + 1; var end = Math.Min(columnCount, rowCount) + sourceRowIndex; for (int i = sourceRowIndex, j = offset; i < end; i++, j += step) { target.Data[j] = Data[i]; } } } public void CopySubMatrixTo(SparseCompressedRowMatrixStorage target, int sourceRowIndex, int targetRowIndex, int rowCount, int sourceColumnIndex, int targetColumnIndex, int columnCount, bool skipClearing = false) { if (target == null) { throw new ArgumentNullException("target"); } ValidateSubMatrixRange(target, sourceRowIndex, targetRowIndex, rowCount, sourceColumnIndex, targetColumnIndex, columnCount); if (!skipClearing) { target.Clear(); } if (sourceRowIndex > sourceColumnIndex && sourceColumnIndex + columnCount > sourceRowIndex) { // column by column, but skip resulting zero columns at the beginning int columnInit = sourceRowIndex - sourceColumnIndex; for (var i = 0; i < Math.Min(columnCount - columnInit, rowCount); i++) { target.At(i + targetRowIndex, columnInit + i + targetColumnIndex, Data[sourceRowIndex + i]); } } else if (sourceRowIndex < sourceColumnIndex && sourceRowIndex + rowCount > sourceColumnIndex) { // row by row, but skip resulting zero rows at the beginning int rowInit = sourceColumnIndex - sourceRowIndex; for (var i = 0; i < Math.Min(columnCount, rowCount - rowInit); i++) { target.At(rowInit + i + targetRowIndex, i + targetColumnIndex, Data[sourceColumnIndex + i]); } } else { for (var i = 0; i < Math.Min(columnCount, rowCount); i++) { target.At(i + targetRowIndex, i + targetColumnIndex, Data[sourceRowIndex + i]); } } } } }