using System; using System.Collections.Generic; using MultiWheelC.TrajectoryPlanning.Utils; namespace MultiWheelC.TrajectoryPlanning.EMPlanner; public sealed class SparseTripletBuilder { private readonly int rowCount; private readonly int columnCount; private readonly bool upperTriangleOnly; private readonly List triplets = new List(); public SparseTripletBuilder(int rowCount, int columnCount) : this(rowCount, columnCount, false) { } public SparseTripletBuilder(int rowCount, int columnCount, bool upperTriangleOnly) { if (rowCount < 0) throw new ArgumentOutOfRangeException(nameof(rowCount)); if (columnCount < 0) throw new ArgumentOutOfRangeException(nameof(columnCount)); this.rowCount = rowCount; this.columnCount = columnCount; this.upperTriangleOnly = upperTriangleOnly; } public void Add(int row, int column, double value) { if (row < 0 || row >= rowCount) throw new ArgumentOutOfRangeException(nameof(row)); if (column < 0 || column >= columnCount) throw new ArgumentOutOfRangeException(nameof(column)); if (!NumericGuard.IsFinite(value)) throw new ArgumentOutOfRangeException(nameof(value), "Sparse triplet values must be finite."); if (upperTriangleOnly && row > column) throw new ArgumentOutOfRangeException(nameof(row), "Upper-triangular storage does not accept lower-triangular entries."); triplets.Add(new Triplet(row, column, value)); } public SparseCscMatrix Build() { var ordered = new List(triplets); ordered.Sort(CompareTriplets); var values = new List(); var rows = new List(); var pointers = new List(columnCount + 1) { 0 }; int nextTriplet = 0; for (int column = 0; column < columnCount; column++) { while (nextTriplet < ordered.Count && ordered[nextTriplet].Column == column) { int row = ordered[nextTriplet].Row; double sum = 0d; do { sum += ordered[nextTriplet].Value; nextTriplet++; } while (nextTriplet < ordered.Count && ordered[nextTriplet].Column == column && ordered[nextTriplet].Row == row); if (!NumericGuard.IsFinite(sum)) throw new ArgumentOutOfRangeException(nameof(triplets), "Duplicate sparse triplets must sum to a finite value."); if (sum != 0d) { rows.Add(row); values.Add(sum); } } pointers.Add(values.Count); } return new SparseCscMatrix(rowCount, columnCount, values, rows, pointers); } private static int CompareTriplets(Triplet left, Triplet right) { int columnComparison = left.Column.CompareTo(right.Column); return columnComparison != 0 ? columnComparison : left.Row.CompareTo(right.Row); } private sealed class Triplet { public Triplet(int row, int column, double value) { Row = row; Column = column; Value = value; } public int Row { get; } public int Column { get; } public double Value { get; } } }