diff --git a/src/Numerics/LinearAlgebra/Matrix.Indexers.cs b/src/Numerics/LinearAlgebra/Matrix.Indexers.cs new file mode 100644 index 00000000..4b5007cc --- /dev/null +++ b/src/Numerics/LinearAlgebra/Matrix.Indexers.cs @@ -0,0 +1,1469 @@ +using System; +using System.Linq; + +namespace MathNet.Numerics.LinearAlgebra +{ + /*------------------------------------------------------------------------------------------------------ + * This partial class file(Matrix.Indexers.cs) is used for add some indexer for Matrix class. + * I implement these functions mainly through int, int Array, ValueTuple struct, Range struct(.NET5). + * They can change the usage of indexer function of MathNet.Numerics.LinearAlgebra.Matrix. + * I have simply indicated the use method on each indexer function. + * So everyone can use these indexers to Get or Set SubMatrix or SubVector more easily. + * Enjoy it! + * + * If you have any questions, suggestions, comments or ideas, please contact the author. + * Thanks for your feedbacks. + * Author Email: zhouxutao@163.com + * Date: 2021.08.30 + -------------------------------------------------------------------------------------------------------*/ + public abstract partial class Matrix + { + /// + /// Get or Set the SubMatrix by Row ValueTuple (start, end) struct Indexes and Column ValueTuple (start, end) struct Indexes. + /// + /// + /// + /// Row ValueTuple (start, end) struct Indexes. + /// The End Must be Larger than the Start. + /// + /// + /// Column ValueTuple (start, end) struct Indexes. + /// The End Must be Larger than the Start. + /// + /// + /// The SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[(1, 2), (2, 3)]; + /// etc. + /// + /// Set: + /// oneMatrix[(1, 2), (2, 3)] = otherMatrix[(2, 3), (5, 6)]; + /// etc. + /// + public Matrix this[ValueTuple rows, ValueTuple columns] + { + get + { + VerifyValueTuple(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + + int columnIndex = columns.Item1; + int columnCount = columns.Item2 - columns.Item1 + 1; + + var result = Build.SameAs(this, rowCount, columnCount); + Storage.CopySubMatrixTo(result.Storage, rowIndex, 0, rowCount, columnIndex, 0, columnCount, ExistingData.AssumeZeros); + return result; + } + + set + { + VerifyValueTuple(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + + int columnIndex = columns.Item1; + int columnCount = columns.Item2 - columns.Item1 + 1; + + value.Storage.CopySubMatrixTo(Storage, 0, rowIndex, rowCount, 0, columnIndex, columnCount); + } + } + + /// + /// Get the SubVector or Set the SubElement by Row ValueTuple (start, end) struct Indexes and Column int Single Index. + /// + /// + /// + /// Row ValueTuple (start, end) struct Indexes.The End Must be Larger than the Start. + /// + /// + /// Column int Single Index. + /// + /// + /// A SubVector + /// + /// + /// Get: + /// var vec = oneMatrix[(1, 2), 5]; + /// etc. + /// + /// Set: + /// oneMatrix[(1, 2), 6] = otherVector[(2, 3)]; + /// etc. + /// + public Vector this[ValueTuple rows, int columnIndex] + { + get + { + VerifyValueTuple(rows, RowCount); + VerifySingleIndex(columnIndex, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + + var result = Vector.Build.SameAs(this, rowCount); + Storage.CopySubColumnTo(result.Storage, columnIndex, rowIndex, 0, rowCount); + return result; + } + + set + { + VerifyValueTuple(rows, RowCount); + VerifySingleIndex(columnIndex, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + + value.Storage.CopyToSubColumn(Storage, columnIndex, 0, rowIndex, rowCount); + } + } + + /// + /// Get the SubVector or Set the SubElement by Row int Single Index and Column ValueTuple (start, end) struct Indexes. + /// + /// + /// + /// Row int Single Index. + /// + /// + /// Column ValueTuple (start, end) struct Indexes. + /// The End Must be Larger than the Start. + /// + /// A SubVector + /// + /// + /// Get: + /// var vec = oneMatrix[5, (2, 4)]; + /// etc. + /// Set: + /// oneMatrix[6, (2, 4)] = otherVector[(2, 4)]; + /// oneMatrix[4, (2, 4)] = otherMatrix[9, (2, 4)]; + /// etc. + /// + public Vector this[int rowIndex, ValueTuple columns] + { + get + { + VerifySingleIndex(rowIndex, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int columnIndex = columns.Item1; + int columnCount = columns.Item2 - columns.Item1 + 1; + + var result = Vector.Build.SameAs(this, columnCount); + Storage.CopySubRowTo(result.Storage, rowIndex, columnIndex, 0, columnCount); + return result; + } + + set + { + VerifySingleIndex(rowIndex, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int columnIndex = columns.Item1; + int columnCount = columns.Item2 - columns.Item1 + 1; + + value.Storage.CopyToSubRow(Storage, rowIndex, 0, columnIndex, columnCount); + } + } + + /// + /// Get the SubVector or Set the SubElement by Row int Single Index and Column ValueTuple (start, step, end) struct Indexes. + /// + /// + /// + /// Row int Single Index. + /// + /// + /// Column ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by (start, step, end). The End Must be Larger than the Start. + /// + /// + /// A SubVector + /// + /// + /// Get: + /// var vec = oneMatrix[5, (1, 3, 5)]; + /// etc. + /// Set: + /// oneMatrix[5, (1, 3, 5)] = otherVector[(1, 3, 5)]; + /// etc. + /// + public Vector this[int rowIndex, ValueTuple columns] + { + get + { + VerifySingleIndex(rowIndex, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + var result = Vector.Build.SameAs(this, columnsIndex.Length); + for (int i = 0; i < columnsIndex.Length; i++) + { + result.Storage[i] = Storage[rowIndex, columnsIndex[i]]; + } + return result; + } + + set + { + VerifySingleIndex(rowIndex, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + for (int i = 0; i < columnsIndex.Length; i++) + { + Storage[rowIndex, columnsIndex[i]] = value.Storage[i]; + } + } + } + + /// + /// Get the SubVector or Set the SubElement by Row ValueTuple (start, step, end) struct Indexes and Column int Single Index. + /// + /// + /// + /// Row ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by (start, step, end). The End Must be Larger than the start. + /// + /// + /// Column int Single Index. + /// + /// + /// A SubVector + /// + /// + /// Get: + /// var vec = oneMatrix[(1, 3, 5), 5]; + /// etc. + /// Set: + /// oneMatrix[(1, 3, 5), 5] = otherVector[(1, 3, 5)]; + /// oneMatrix[(1, 3, 5), 5] = otherMatrix[(1, 3, 5), 6]; + /// etc. + /// + public Vector this[ValueTuple rows, int columnIndex] + { + get + { + VerifyValueTuple(rows, RowCount); + VerifySingleIndex(columnIndex, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + + var result = Vector.Build.SameAs(this, rowsIndex.Length); + for (int i = 0; i < rowsIndex.Length; i++) + { + result.Storage[i] = Storage[rowsIndex[i], columnIndex]; + } + return result; + } + + set + { + VerifyValueTuple(rows, RowCount); + VerifySingleIndex(columnIndex, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + + for (int i = 0; i < rowsIndex.Length; i++) + { + Storage[rowsIndex[i], columnIndex] = value.Storage[i]; + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row ValueTuple (start, step, end) struct Indexes and Column ValueTuple (start, step, end) struct Indexes. + /// + /// + /// + /// Row ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by (start, step, end). The End Must be Larger than the Start. + /// + /// + /// Column ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by (start, step, end). The End Must be Larger than the Start. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[(1, 3, 5), (2, 4, 6)]; + /// etc. + /// Set: + /// oneMatrix[(1, 3, 5), (2, 4, 6)] = otherMatrix[(1, 3, 5), (2, 4, 6)]; + /// etc. + /// + public Matrix this[ValueTuple rows, ValueTuple columns] + { + get + { + VerifyValueTuple(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + var result = Build.SameAs(this, rowsIndex.Length, columnsIndex.Length); + for (int i = 0; i < rowsIndex.Length; i++) + { + for (int j = 0; j < columnsIndex.Length; j++) + { + result.Storage[i, j] = Storage[rowsIndex[i], columnsIndex[j]]; + } + } + return result; + } + + set + { + VerifyValueTuple(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + for (int i = 0; i < rowsIndex.Length; i++) + { + for (int j = 0; j < columnsIndex.Length; j++) + { + Storage[rowsIndex[i], columnsIndex[j]] = value.Storage[i, j]; + } + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row ValueTuple (start, end) struct Indexes and Column ValueTuple (start, step, end) struct Indexes. + /// + /// + /// + /// Row ValueTuple (start, end) struct Indexes. + /// The End Must be Larger than the Start. + /// + /// + /// Column ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by (start, step, end). The End Must be Larger than the Start. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[(1, 5), (2, 4, 6)]; + /// etc. + /// Set: + /// oneMatrix[(1, 5), (2, 4, 6)] = otherMatrix[(1, 5), (2, 4, 6)]; + /// etc. + /// + public Matrix this[ValueTuple rows, ValueTuple columns] + { + get + { + VerifyValueTuple(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + var result = Build.SameAs(this, rowCount, columnsIndex.Length); + for (int i = 0; i < columnsIndex.Length; i++) + { + result.SetColumn(i, Column(columnsIndex[i], rowIndex, rowCount)); + } + return result; + } + + set + { + VerifyValueTuple(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + for (int i = 0; i < columnsIndex.Length; i++) + { + SetColumn(columnsIndex[i], rowIndex, rowCount, value.Column(i)); + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row ValueTuple (start, step, end) struct Indexes and Column ValueTuple (start, end) struct Indexes. + /// + /// + /// + /// Row ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by (start, step, end). The End Must be Larger than the Start. + /// + /// + /// Column ValueTuple (start, end) struct Indexes. + /// The End Must be Larger than the Start. + /// + /// + /// The SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[(2, 4, 6), (1, 5)]; + /// etc. + /// Set: + /// oneMatrix[(2, 4, 6), (1, 5)] = otherMatrix[(2, 4, 6), (1, 5)]; + /// etc. + /// + public Matrix this[ValueTuple rows, ValueTuple columns] + { + get + { + VerifyValueTuple(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + int columnIndex = columns.Item1; + int columnCount = columns.Item2 - columns.Item1 + 1; + + var result = Build.SameAs(this, rowsIndex.Length, columnCount); + for (int i = 0; i < rowsIndex.Length; i++) + { + result.SetRow(i, Row(rowsIndex[i], columnIndex, columnCount)); + } + return result; + } + + set + { + VerifyValueTuple(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + int columnIndex = columns.Item1; + int columnCount = columns.Item2 - columns.Item1 + 1; + + for (int i = 0; i < rowsIndex.Length; i++) + { + SetRow(rowsIndex[i], columnIndex, columnCount, value.Row(i)); + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row int Array Indexes and Column int Array Indexes. + /// + /// + /// + /// Row int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// Column int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// The SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[new int[] { 1, 2, 3 }, new int[] { 2, 5, 6 }]; + /// etc. + /// Set: + /// oneMatrix[new int[] { 1, 2, 3 }, new int[] { 2, 5, 6 }] = otherMatrix[new int[] { 1, 2, 3 }, new int[] { 3, 6, 3 }]; + /// etc. + /// + public Matrix this[int[] rows, int[] columns] + { + get + { + VerifyArray(rows, RowCount); + VerifyArray(columns, ColumnCount); + + var result = Build.SameAs(this, rows.Length, columns.Length); + for (int i = 0; i < rows.Length; i++) + { + for (int j = 0; j < columns.Length; j++) + { + result.Storage[i, j] = Storage[rows[i], columns[j]]; + } + } + return result; + } + + set + { + VerifyArray(rows, RowCount); + VerifyArray(columns, ColumnCount); + + for (int i = 0; i < rows.Length; i++) + { + for (int j = 0; j < columns.Length; j++) + { + Storage[rows[i], columns[j]] = value.Storage[i, j]; + } + } + } + } + + /// + /// Get the SubVector or Set the SubElement by Row int Array Indexes and Column int Single Index. + /// + /// + /// + /// The Row int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// The Column int Single Index + /// + /// + /// The SubVector + /// + /// + /// Get: + /// var vec = oneMatrix[new int[] { 1, 2, 3 }, 3]; + /// etc. + /// Set: + /// oneMatrix[new int[] { 1, 2, 3 }, 3] = otherMatrix[new int[] { 5, 6, 4 }, 6]; + /// oneMatrix[new int[] { 1, 2, 3 }, 3] = otherVector[new int[] { 1, 2, 3 }]; + /// etc. + /// + public Vector this[int[] rows, int columnIndex] + { + get + { + VerifyArray(rows, RowCount); + VerifySingleIndex(columnIndex, ColumnCount); + + var result = Vector.Build.SameAs(this, rows.Length); + for (int i = 0; i < rows.Length; i++) + { + result.Storage[i] = Storage[rows[i], columnIndex]; + } + return result; + } + + set + { + VerifyArray(rows, RowCount); + VerifySingleIndex(columnIndex, ColumnCount); + + for (int i = 0; i < rows.Length; i++) + { + Storage[rows[i], columnIndex] = value.Storage[i]; + } + } + } + + /// + /// Get the SubVector or Set the SubElement by Row int Single Index and Column int Array Indexes. + /// + /// + /// + /// Row int Single Index. + /// + /// + /// Column int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// The SubVector + /// + /// + /// Get: + /// var vec = oneMatrix[ 3, new int[] { 1, 2, 3 }]; + /// etc. + /// Set: + /// oneMatrix[ 3, new int[] { 1, 2, 3 }] = otherMatrix[ 6, new int[] { 2, 5, 4 }]; + /// oneMatrix[ 3, new int[] { 1, 2, 3 }] = otherVector[new int[] { 2, 5, 4 }]; + /// etc. + /// + public Vector this[int rowIndex, int[] columns] + { + get + { + VerifySingleIndex(rowIndex, RowCount); + VerifyArray(columns, ColumnCount); + + var result = Vector.Build.SameAs(this, columns.Length); + for (int i = 0; i < columns.Length; i++) + { + result.Storage[i] = Storage[rowIndex, columns[i]]; + } + return result; + } + + set + { + VerifySingleIndex(rowIndex, RowCount); + VerifyArray(columns, ColumnCount); + + for (int i = 0; i < columns.Length; i++) + { + Storage[columns[i], rowIndex] = value.Storage[i]; + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row int Array Indexes and Column ValueTuple (start, end) struct Indexes. + /// + /// + /// + /// Row int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// Column ValueTuple (start, end) struct Indexes. + /// The End Must be Larger than the Start. + /// + /// + /// The SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[ new int[] { 1, 2, 3 }, (1, 2)]; + /// etc. + /// Set: + /// oneMatrix[ new int[] { 1, 2, 3 }, (1, 2)] = otherMatrix[ new int[] { 4, 3, 5 }, (1, 2)]; + /// etc. + /// + public Matrix this[int[] rows, ValueTuple columns] + { + get + { + VerifyArray(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2); + + var result = Build.SameAs(this, rows.Length, columnsIndex.Length); + for (int i = 0; i < rows.Length; i++) + { + for (int j = 0; j < columnsIndex.Length; j++) + { + result.Storage[i, j] = Storage[rows[i], columnsIndex[j]]; + } + } + return result; + } + + set + { + VerifyArray(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2); + + for (int i = 0; i < rows.Length; i++) + { + for (int j = 0; j < columnsIndex.Length; j++) + { + Storage[rows[i], columnsIndex[j]] = value.Storage[i, j]; + } + } + + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row int Array Indexes and Column ValueTuple (start, step, end) struct Indexes. + /// + /// + /// + /// Row int Array Indexes. + /// The Length of it count Must be Larger than One. + /// + /// + /// Column ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by(start, step, end). The End Must be Larger than the Start. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[new int[] { 1, 2, 3 }, (1, 2, 5)]; + /// etc. + /// Set: + /// oneMatrix[new int[] { 1, 2, 3 }, (1, 2, 5)] = otherMatrix[new int[] { 4, 3, 5 }, (1, 2, 5)]; + /// etc. + /// + public Matrix this[int[] rows, ValueTuple columns] + { + get + { + VerifyArray(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + var result = Build.SameAs(this, rows.Length, columnsIndex.Length); + for (int i = 0; i < rows.Length; i++) + { + for (int j = 0; j < columnsIndex.Length; j++) + { + result.Storage[i, j] = Storage[rows[i], columnsIndex[j]]; + } + } + return result; + } + + set + { + VerifyArray(rows, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + for (int i = 0; i < rows.Length; i++) + { + for (int j = 0; j < columnsIndex.Length; j++) + { + Storage[rows[i], columnsIndex[j]] = value.Storage[i, j]; + } + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row ValueTupe (start, end) struct Indexes and Column int Array Indexes. + /// + /// + /// + /// Row ValueTupe (start, end) struct Indexes. + /// The End Must be Larger than the Start. + /// + /// + /// Column int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// + /// + /// + /// Get: + /// var mat = oneMatrix[ (1, 3), new int[] { 1, 2, 3 }]; + /// etc. + /// Set: + /// oneMatrix[ (1, 3), new int[] { 1, 2, 3 }] = otherMatrix[ (1, 3), new int[] { 3, 6, 1 }]; + /// etc. + /// + public Matrix this[ValueTuple rows, int[] columns] + { + get + { + VerifyValueTuple(rows, RowCount); + VerifyArray(columns, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + + var result = Build.SameAs(this, rowCount, columns.Length); + for (int i = 0; i < columns.Length; i++) + { + result.SetColumn(i, Column(columns[i], rowIndex, rowCount)); + } + return result; + } + + set + { + VerifyValueTuple(rows, RowCount); + VerifyArray(columns, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + + for (int i = 0; i < columns.Length; i++) + { + SetColumn(columns[i], rowIndex, rowCount, value.Column(i)); + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row ValueTupe (start, step, end) struct Indexes and Column int Array Indexes. + /// + /// + /// + /// Row ValueTupe (start, step, end) struct Indexes. + /// It will be a LinearRange by(start, step, end). The End Must be Larger than the Start. + /// + /// + /// Column int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[ (1, 2, 5), new int[] { 1, 2, 3 }]; + /// etc. + /// Set: + /// oneMatrix[ (1, 2, 5), new int[] { 1, 2, 3 }] = otherMatrix[ (1, 2, 5), new int[] { 3, 6, 1 }]; + /// etc. + /// + public Matrix this[ValueTuple rows, int[] columns] + { + get + { + VerifyValueTuple(rows, RowCount); + VerifyArray(columns, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + + var result = Build.SameAs(this, rowsIndex.Length, columns.Length); + for (int i = 0; i < rowsIndex.Length; i++) + { + for (int j = 0; j < columns.Length; j++) + { + result.Storage[i, j] = Storage[rowsIndex[i], columns[j]]; + } + } + return result; + + } + + set + { + VerifyValueTuple(rows, RowCount); + VerifyArray(columns, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + + for (int i = 0; i < rowsIndex.Length; i++) + { + for (int j = 0; j < columns.Length; j++) + { + Storage[rowsIndex[i], columns[j]] = value.Storage[i, j]; + } + } + + } + } + +#if NET5_0_OR_GREATER + + /// + /// Get the SubMatrix or Set the SubElement by Row Range struct Indexes and Column Range struct Indexes. + /// + /// + /// + /// Row Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// Column Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[1..3, 3..5]; + /// var mat = oneMatrix[1..3, ..5]; + /// var mat = oneMatrix[1..3, 3..]; + /// var mat = oneMatrix[1..3, ^5..^1]; + /// var mat = oneMatrix[1..3, ..]; + /// etc. + /// Set: + /// oneMatrix[1..3, 3..5] = otherMatrix[2..4, 3..5]; + /// oneMatrix[1..3, ^5..^1] = otherMatrix[1..3, ^5..^1]; + /// etc. + /// + public Matrix this[Range rowRange, Range columnRange] + { + get + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + int columnCount = columnEndIndex - columnStartIndex + 1; + + var result = Build.SameAs(this, rowCount, columnCount); + Storage.CopySubMatrixTo(result.Storage, rowStartIndex, 0, rowCount, columnStartIndex, 0, columnCount, ExistingData.AssumeZeros); + return result; + } + + set + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + int columnCount = columnEndIndex - columnStartIndex + 1; + + value.Storage.CopySubMatrixTo(Storage, 0, rowStartIndex, rowCount, 0, columnStartIndex, columnCount); + } + } + + /// + /// Get the SubVector or Set the SubElement by Row Range struct Indexes and Column int Single Index. + /// + /// + /// + /// Row Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// Column int Single Index. + /// + /// + /// A SubVector + /// + /// + /// Get: + /// var vec = oneMatrix[1..3, 1]; + /// var vec = oneMatrix[..3, 1]; + /// var vec = oneMatrix[1.., 1]; + /// var vec = oneMatrix[^3..^1, 1]; + /// var vec = oneMatrix[.., 1]; + /// etc. + /// Set: + /// oneMatrix[1..3, 1] = otherMatrix[1..3, 1]; + /// oneMatrix[^3..^1, 1] = otherMatrix[^3..^1, 1]; + /// oneMatrix[1..3, 1] = otherVector[1..3]; + /// etc. + /// + public Vector this[Range rowRange, int columnIndex] + { + get + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + VerifySingleIndex(columnIndex, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + + var result = Vector.Build.SameAs(this, rowCount); + Storage.CopySubColumnTo(result.Storage, columnIndex, rowStartIndex, 0, rowCount); + return result; + } + + set + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + VerifySingleIndex(columnIndex, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + + value.Storage.CopyToSubColumn(Storage, columnIndex, 0, rowStartIndex, rowCount); + } + } + + /// + /// Get the SubVector or Set the SubElement by Row int Single Index and Column Range struct Indexes. + /// + /// + /// + /// Row int Single Index. + /// + /// + /// Column Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// A SubVector + /// + /// + /// Get: + /// var vec = oneMatrix[2, 1..3]; + /// var vec = oneMatrix[2, ..3]; + /// var vec = oneMatrix[2, 1..]; + /// var vec = oneMatrix[2, ^3..^1]; + /// var vec = oneMatrix[2, ..]; + /// etc. + /// Set: + /// oneMatrix[2, 1..3] = otherMatrix[2, 1..3]; + /// oneMatrix[2, ^3..^1] = otherMatrix[2, ^3..^1]; + /// oneMatrix[2, 1..3] = otherVector[1..3]; + /// etc. + /// + public Vector this[int rowIndex, Range columnRange] + { + get + { + VerifySingleIndex(rowIndex, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int columnCount = columnEndIndex - columnStartIndex + 1; + + var result = Vector.Build.SameAs(this, columnCount); + Storage.CopySubRowTo(result.Storage, rowIndex, columnStartIndex, 0, columnCount); + return result; + } + + set + { + VerifySingleIndex(rowIndex, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int columnCount = columnEndIndex - columnStartIndex + 1; + + value.Storage.CopyToSubRow(Storage, rowIndex, 0, columnStartIndex, columnCount); + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row Range struct Indexes and Column int Array Indexes. + /// + /// + /// + /// Row Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// Column int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var vec = oneMatrix[1..3, new int[]{ 1, 2, 3 }]; + /// var vec = oneMatrix[1.., new int[]{ 1, 2, 3 }]; + /// var vec = oneMatrix[..3, new int[]{ 1, 2, 3 }]; + /// var vec = oneMatrix[^3..^1, new int[]{ 1, 2, 3 }]; + /// var vec = oneMatrix[.., new int[]{ 1, 2, 3 }]; + /// etc. + /// Set: + /// oneMatrix[1..3, new int[]{ 1, 2, 3 }] = otherMatrix[1..3, new int[]{ 4, 3, 7 }]; + /// oneMatrix[^3..^1, new int[]{ 1, 2, 3 }] = otherMatrix[^3..^1, new int[]{ 5, 2, 3 }]; + /// etc. + /// + public Matrix this[Range rowRange, int[] columns] + { + get + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + VerifyArray(columns, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + + var result = Build.SameAs(this, rowCount, columns.Length); + for (int i = 0; i < columns.Length; i++) + { + result.SetColumn(i, Column(columns[i], rowStartIndex, rowCount)); + } + return result; + } + + set + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + VerifyArray(columns, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + + for (int i = 0; i < columns.Length; i++) + { + SetColumn(columns[i], rowStartIndex, rowCount, value.Column(i)); + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row Range struct Indexes and Column ValueTuple (start, end) struct Indexes. + /// + /// + /// + /// Row Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// Column ValueTuple (start, end) struct Indexes. + /// The End Must be Larger than the Start of it. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[1..3, (1, 4)]; + /// var mat = oneMatrix[1.., (1, 4)]; + /// var mat = oneMatrix[..3, (1, 4)]; + /// var mat = oneMatrix[^3..^1, (1, 4)]; + /// var mat = oneMatrix[.., (1, 4)]; + /// etc. + /// Set: + /// oneMatrix[1..3, (1, 4)] = otherMatrix[1..3, (2, 5)]; + /// oneMatrix[^3..^1, (1, 4)] = otherMatrix[^3..^1, (2, 5)]; + /// etc. + /// + public Matrix this[Range rowRange, ValueTuple columns] + { + get + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + int columnIndex = columns.Item1; + int columnCount = columns.Item2 - columns.Item1 + 1; + + var result = Build.SameAs(this, rowCount, columnCount); + Storage.CopySubMatrixTo(result.Storage, rowStartIndex, 0, rowCount, columnIndex, 0, columnCount, ExistingData.AssumeZeros); + return result; + } + + set + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + int columnIndex = columns.Item1; + int columnCount = columns.Item2 - columns.Item1 + 1; + + value.Storage.CopySubMatrixTo(Storage, 0, rowStartIndex, rowCount, 0, columnIndex, columnCount); + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row Range struct Indexes and Column ValueTuple (start, step, end) struct Indexes. + /// + /// + /// + /// Row Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// Column ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by(start, step, end). The End Must be Larger than the Start. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[1..3, (1, 2, 5)]; + /// var mat = oneMatrix[1.., (1, 2, 5)]; + /// var mat = oneMatrix[..3, (1, 2, 5)]; + /// var mat = oneMatrix[^3..^1, (1, 2, 5)]; + /// var mat = oneMatrix[.., (1, 2, 5)]; + /// etc. + /// Set: + /// oneMatrix[1..3, (1, 2, 5)] = otherMatrix[1..3, (1, 2, 5)]; + /// oneMatrix[^3..^1, (1, 2, 5)] = otherMatrix[^3..^1, (1, 2, 5)]; + /// etc. + /// + public Matrix this[Range rowRange, ValueTuple columns] + { + get + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + var result = Build.SameAs(this, rowCount, columnsIndex.Length); + for (int i = 0; i < columnsIndex.Length; i++) + { + result.SetColumn(i, Column(columnsIndex[i], rowStartIndex, rowCount)); + } + return result; + } + + set + { + var (rowStartIndex, rowEndIndex) = VerifyRange(rowRange, RowCount); + VerifyValueTuple(columns, ColumnCount); + + int rowCount = rowEndIndex - rowStartIndex + 1; + int[] columnsIndex = Generate.LinearRangeInt32(columns.Item1, columns.Item2, columns.Item3); + + for (int i = 0; i < columnsIndex.Length; i++) + { + SetColumn(columnsIndex[i], rowStartIndex, rowCount, value.Column(i)); + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row int Array Indexes and Column Range struct Indexes. + /// + /// + /// + /// Row int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// Column Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[new int[]{ 1, 2, 3}, 1..5]; + /// var mat = oneMatrix[new int[]{ 1, 2, 3}, 1..]; + /// var mat = oneMatrix[new int[]{ 1, 2, 3}, ..5]; + /// var mat = oneMatrix[new int[]{ 1, 2, 3}, ^5..^1]; + /// var mat = oneMatrix[new int[]{ 1, 2, 3}, ..]; + /// etc. + /// Set: + /// oneMatrix[new int[]{ 1, 2, 3}, 1..5] = otherMatrix[new int[]{ 1, 2, 3}, 1..5]; + /// oneMatrix[new int[]{ 1, 2, 3}, ^5..^1] = otherMatrix[new int[]{ 1, 2, 3}, ^5..^1]; + /// etc. + /// + public Matrix this[int[] rows, Range columnRange] + { + get + { + VerifyArray(rows, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int columnCount = columnEndIndex - columnStartIndex + 1; + + var result = Build.SameAs(this, rows.Length, columnCount); + for (int i = 0; i < rows.Length; i++) + { + result.SetRow(i, Row(rows[i], columnStartIndex, columnCount)); + } + return result; + } + + set + { + VerifyArray(rows, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int columnCount = columnEndIndex - columnStartIndex + 1; + + for (int i = 0; i < rows.Length; i++) + { + SetRow(rows[i], columnStartIndex, columnCount, value.Row(i)); + } + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row ValueTuple (start, end) struct Indexes and Column Range struct Indexes. + /// + /// + /// + /// Row ValueTuple (start, end) struct Indexes. + /// The End Must be Larger than the Start of it. + /// + /// + /// Column Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[(1, 3), 1..5]; + /// var mat = oneMatrix[(1, 3), 1..]; + /// var mat = oneMatrix[(1, 3), ..5]; + /// var mat = oneMatrix[(1, 3), ^5..^1]; + /// var mat = oneMatrix[(1, 3), ..]; + /// etc. + /// Set: + /// oneMatrix[(1, 3), 1..5] = otherMatrix[(1, 3), 1..5]; + /// oneMatrix[(1, 3), ^5..^1] = otherMatrix[(1, 3), ^5..^1]; + /// etc. + /// + public Matrix this[ValueTuple rows, Range columnRange] + { + get + { + VerifyValueTuple(rows, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + int columnCount = columnEndIndex - columnStartIndex + 1; + + var result = Build.SameAs(this, rowCount, columnCount); + Storage.CopySubMatrixTo(result.Storage, rowIndex, 0, rowCount, columnStartIndex, 0, columnCount, ExistingData.AssumeZeros); + return result; + } + + set + { + VerifyValueTuple(rows, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int rowIndex = rows.Item1; + int rowCount = rows.Item2 - rows.Item1 + 1; + int columnCount = columnEndIndex - columnStartIndex + 1; + + value.Storage.CopySubMatrixTo(Storage, 0, rowIndex, rowCount, 0, columnStartIndex, columnCount); + } + } + + /// + /// Get the SubMatrix or Set the SubElement by Row ValueTuple (start, step, end) struct Indexes and Column Range struct Indexes. + /// + /// + /// + /// Row ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by(start, step, end). The End Must be Larger than the Start. + /// + /// + /// Column Range struct Indexes. + /// The End Must be Larger than the Start of it. The End Range Index will be contain in the Indexes. + /// + /// + /// A SubMatrix + /// + /// + /// Get: + /// var mat = oneMatrix[(1, 2, 5), 1..5]; + /// var mat = oneMatrix[(1, 2, 5), 1..]; + /// var mat = oneMatrix[(1, 2, 5), ..5]; + /// var mat = oneMatrix[(1, 2, 5), ^5..^1]; + /// var mat = oneMatrix[(1, 2, 5), ..]; + /// etc. + /// Set: + /// oneMatrix[(1, 2, 5), 1..5] = otherMatrix[(1, 2, 5), 1..5]; + /// oneMatrix[(1, 2, 5), ^5..^1] = otherMatrix[(1, 2, 5), ^5..^1]; + /// etc. + /// + public Matrix this[ValueTuple rows, Range columnRange] + { + get + { + VerifyValueTuple(rows, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + int columnCount = columnEndIndex - columnStartIndex + 1; + + var result = Build.SameAs(this, rowsIndex.Length, columnCount); + for (int i = 0; i < rowsIndex.Length; i++) + { + result.SetRow(i, Row(rowsIndex[i], columnStartIndex, columnCount)); + } + return result; + } + + set + { + VerifyValueTuple(rows, RowCount); + var (columnStartIndex, columnEndIndex) = VerifyRange(columnRange, ColumnCount); + + int[] rowsIndex = Generate.LinearRangeInt32(rows.Item1, rows.Item2, rows.Item3); + int columnCount = columnEndIndex - columnStartIndex + 1; + + for (int i = 0; i < rowsIndex.Length; i++) + { + SetRow(rowsIndex[i], columnStartIndex, columnCount, value.Row(i)); + } + } + } +#endif + + #region Used for Verifying the availability of Indexers + +#if NET5_0_OR_GREATER + + /// + /// Used for Verifying the availability of Row or Column Range struct Indexes. + /// + /// Row or Column Range struct Indexes + /// RowCount or ColumnCount of the Matrix + /// The Start of the Range. + /// The End of the Range. + private (int startIndex, int endIndex) VerifyRange(Range range, int count) + { + int startIndex = range.Start.IsFromEnd ? count - range.Start.Value - 1 : range.Start.Value; + int endIndex = range.End.IsFromEnd ? count - range.End.Value - 1 : range.End.Value; + + if (startIndex < 0 || endIndex >= count) + { + throw new ArgumentOutOfRangeException(nameof(range)); + } + + return (startIndex, endIndex); + } +#endif + + /// + /// Used for Verifying the availability of Row or Column int Array Indexes. + /// + /// Row or Column int Array Indexes + /// RowCount or ColumnCount of the Matrix + private void VerifyArray(int[] array, int count) + { + if (array.Length <= 1) + { + throw new ArgumentException("The Length of int array must Larger than One!"); + } + + if (array.Min() < 0 || array.Max() >= count) + { + throw new ArgumentOutOfRangeException(nameof(array)); + } + } + + /// + /// Used for Verifying the availability of Row or Column ValueTuple (start, end) struct Indexes. + /// + /// Row or Column ValueTuple (strat, end) struct Indexes + /// RowCount or ColumnCount of the Matrix + private void VerifyValueTuple(ValueTuple vt, int count) + { + if (vt.Item1 < 0 || vt.Item2 >= count) + { + throw new ArgumentOutOfRangeException(nameof(vt)); + } + + if (vt.Item2 <= vt.Item1) + { + throw new ArgumentException("The Length of ValueTuple must Larger than One!"); + } + } + + /// + /// Used for Verifying the availability of Row or Column ValueTuple (start, step, end) struct Indexes. + /// + /// Row or Column ValueTuple (start, step, end) struct Indexes + /// RowCount or ColumnCount of the Matrix + private void VerifyValueTuple(ValueTuple vt, int count) + { + if (vt.Item1 < 0 || vt.Item3 >= count) + { + throw new ArgumentOutOfRangeException(nameof(vt)); + } + + if (vt.Item3 <= vt.Item1) + { + throw new ArgumentException("The Length of ValueTuple must Larger than One!"); + } + } + + /// + /// Used for Verifying the availability of Row or Column int Single Index. + /// + /// Row or Column int Single Index + /// RowCount or ColumnCount of the Matrix + private void VerifySingleIndex(int index, int count) + { + if (index < 0 || index >= count) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + } + + #endregion + + } +} diff --git a/src/Numerics/LinearAlgebra/Vector.Indexers.cs b/src/Numerics/LinearAlgebra/Vector.Indexers.cs new file mode 100644 index 00000000..4f3fc926 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Vector.Indexers.cs @@ -0,0 +1,327 @@ +using System; +using System.Linq; + +namespace MathNet.Numerics.LinearAlgebra +{ + /*------------------------------------------------------------------------------------------------------ + * This partial class file(Vector.Indexers.cs) is used for add some indexer for Vector class. + * I implement these functions mainly through int, int Array, ValueTuple struct, Range struct(.NET5). + * They can change the usage of indexer function of MathNet.Numerics.LinearAlgebra.Vector. + * I have simply indicated the use method on each indexer function. + * So everyone can use these indexers to Get or Set SubVector more easily. + * Enjoy it! + * + * If you have any questions, suggestions, comments or ideas, please contact the author. + * Thanks for your feedbacks. + * Author Email: zhouxutao@163.com + * Date: 2021.08.30 + -------------------------------------------------------------------------------------------------------*/ + public abstract partial class Vector + { + /// + /// Get the SubVector or Set the SubElement by ValueTuple (start, end) struct Indexes. + /// + /// + /// + /// ValueTuple (start, end) struct Indexes. + /// The End Must be Larger than the Start. + /// + /// + /// A SubVector. + /// + /// + /// Get: + /// var vec = oneVector[(1, 4)]; + /// etc. + /// Set: + /// oneVector[(1, 4)] = otherMatrix[(1, 4), 6]; + /// oneVector[(1, 4)] = otherVector[(2, 5)]; + /// etc. + /// + public Vector this[ValueTuple indexes] + { + get + { + VerifyValueTuple(indexes, Count); + + int sourceIndex = indexes.Item1; + int length = indexes.Item2 - indexes.Item1 + 1; + + var result = Build.SameAs(this, length); + Storage.CopySubVectorTo(result.Storage, sourceIndex, 0, length); + return result; + } + + set + { + VerifyValueTuple(indexes, Count); + + int targetIndex = indexes.Item1; + int length = indexes.Item2 - indexes.Item1 + 1; + + if (length != value.Count) + { + throw new ArgumentOutOfRangeException(nameof(indexes)); + } + + value.Storage.CopySubVectorTo(Storage, 0, targetIndex, length); + } + } + + /// + /// Get the SubVector or Set the SubElement by ValueTuple (start, step, end) struct Indexes. + /// + /// + /// + /// ValueTuple (start, step, end) struct Indexes. + /// It will be a LinearRange by (start, step, end). The End Must be Larger than the Start. + /// + /// + /// A SubVector. + /// + /// + /// Get: + /// var vec = oneVector[(1, 2, 5)]; + /// etc. + /// Set: + /// oneVector[(1, 2, 5)] = otherMatrix[ 3, (1, 2, 5)]; + /// oneVector[(1, 2, 5)] = otherVector[(2, 2, 6)]; + /// etc. + /// + public Vector this[ValueTuple indexes] + { + get + { + VerifyValueTuple(indexes, Count); + + int[] vectorIndex = Generate.LinearRangeInt32(indexes.Item1, indexes.Item2, indexes.Item3); + + var result = Build.SameAs(this, vectorIndex.Length); + for (int i = 0; i < vectorIndex.Length; i++) + { + result.Storage[i] = Storage[vectorIndex[i]]; + } + return result; + } + + set + { + VerifyValueTuple(indexes, Count); + + int[] vectorIndex = Generate.LinearRangeInt32(indexes.Item1, indexes.Item2, indexes.Item3); + + if (vectorIndex.Length != value.Count) + { + throw new ArgumentOutOfRangeException(nameof(indexes)); + } + + for (int i = 0; i < vectorIndex.Length; i++) + { + Storage[vectorIndex[i]] = value.Storage[i]; + } + } + } + + /// + /// Get the SubVector or Set the SubElement by int Array Indexes. + /// + /// + /// + /// int Array Indexes. + /// The Length of it Must be Larger than One. + /// + /// + /// A SubVector. + /// + /// + /// Get: + /// var vec = oneVector[new int[]{1, 2, 6, 2}]; + /// etc. + /// Set: + /// oneVector[new int[]{1, 2, 6, 2}] = otherVector[new int[]{2, 3, 6, 5}]; + /// etc. + /// + public Vector this[int[] indexes] + { + get + { + VerifyArray(indexes, Count); + + var result = Build.SameAs(this, indexes.Length); + for (int i = 0; i < indexes.Length; i++) + { + result.Storage[i] = Storage[indexes[i]]; + } + return result; + } + + set + { + VerifyArray(indexes, Count); + + if (indexes.Length != value.Count) + { + throw new ArgumentOutOfRangeException(nameof(indexes)); + } + + for (int i = 0; i < indexes.Length; i++) + { + Storage[indexes[i]] = value.Storage[i]; + } + } + } + +#if NET5_0_OR_GREATER + + /// + /// Get the SubVector or Set the SubElement by Range struct Indexes. + /// + /// + /// + /// Range struct Indexes. + /// he End Must be Larger than the Start. The End Range Index will be contain in the Indexes. + /// + /// + /// A SubVector. + /// + /// + /// Get: + /// var vec = oneVector[1..5]; + /// var vec = oneVector[..5]; + /// var vec = oneVector[1..] + /// var vec = oneVector[^3..^1]; + /// var vec = oneVector[..^1]; + /// etc. + /// Set: + /// oneVector[1..5] = otherVector[2..6]; + /// oneVector[^3..^1] = otherVector[^3..^1]; + /// etc. + /// + public Vector this[Range indexes] + { + get + { + var (startIndex, endIndex) = VerifyRange(indexes, Count); + + int length = endIndex - startIndex + 1; + + var result = Build.SameAs(this, length); + Storage.CopySubVectorTo(result.Storage, startIndex, 0, length); + return result; + } + + set + { + var (startIndex, endIndex) = VerifyRange(indexes, Count); + + int length = endIndex - startIndex + 1; + + if (length != value.Count) + { + throw new ArgumentException($"The argument Row Range:{indexes} is wrong!"); + } + + value.Storage.CopySubVectorTo(Storage, 0, startIndex, length); + + } + } + +#endif + + #region Used for Verifying the availability of Indexers + +#if NET5_0_OR_GREATER + + /// + /// Used for Verifying the availability of Range struct Indexes. + /// + /// Range struct Indexes. + /// The Count of the Vector. + /// The Start of the Range. + /// The End of the Range. + private (int startIndex, int endIndex) VerifyRange(Range range, int count) + { + int startIndex = range.Start.IsFromEnd ? count - range.Start.Value - 1 : range.Start.Value; + int endIndex = range.End.IsFromEnd ? count - range.End.Value - 1 : range.End.Value; + + if (startIndex < 0 || endIndex >= count) + { + throw new ArgumentOutOfRangeException(nameof(range)); + } + + return (startIndex, endIndex); + } + +#endif + + /// + /// Used for Verifying the availability of int Array Indexes. + /// + /// int Array Indexes. + /// The Count of the Vector. + private void VerifyArray(int[] array, int count) + { + if (array.Length <= 1) + { + throw new ArgumentException("The Length of int array must Larger than One!"); + } + + if (array.Min() < 0 || array.Max() >= count) + { + throw new ArgumentOutOfRangeException(nameof(array)); + } + } + + /// + /// Used for Verifying the availability of ValueTuple (start, end) struct Indexes. + /// + /// ValueTuple (start, end) struct Indexes. + /// The Count of the Vector. + private void VerifyValueTuple(ValueTuple vt, int count) + { + if (vt.Item1 < 0 || vt.Item2 >= count) + { + throw new ArgumentOutOfRangeException(nameof(vt)); + } + + if (vt.Item2 <= vt.Item1) + { + throw new ArgumentException("The Length of ValueTuple must Larger than One!"); + } + } + + /// + /// Used for Verifying the availability of ValueTuple (start, step, end) struct Indexes. + /// + /// ValueTuple (start, step, end) struct Indexes. + /// The Count of the Vector. + private void VerifyValueTuple(ValueTuple vt, int count) + { + if (vt.Item1 < 0 || vt.Item3 >= count) + { + throw new ArgumentOutOfRangeException(nameof(vt)); + } + + if (vt.Item3 <= vt.Item1) + { + throw new ArgumentException("The Length of ValueTuple must Larger than One!"); + } + } + + /// + /// Used for Verifying the availability of int Single Index. + /// + /// int Single Index. + /// The Count of the Vector. + private void VerifySingleIndex(int index, int count) + { + if (index < 0 || index >= count) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + } + + #endregion + } +} +