/// <summary> /// Multiplies a sparse matrix by a row vector. /// </summary> /// <param name="A">The matrix.</param> /// <param name="v">The row vector.</param> /// <returns>The product row vector.</returns> public static RowVector operator *(RowVector v, SparseSquareMatrix A) { if (v == null) { throw new ArgumentNullException("v"); } if (A == null) { throw new ArgumentNullException("A"); } if (v.Dimension != A.Dimension) { throw new DimensionMismatchException(); } RowVector vA = new RowVector(A.Dimension); for (int i = 0; i < A.Dimension; i++) { SparseMatrixElement element = A.columns[i]; while (element != null) { vA[i] += element.Value * v[element.Row]; element = element.NextInColumn; } } return(vA); }
/// <inheritdoc /> public override double this[int r, int c] { get { if ((r < 0) || (r >= dimension)) { throw new ArgumentOutOfRangeException("r"); } if ((c < 0) || (c >= dimension)) { throw new ArgumentOutOfRangeException("c"); } SparseMatrixElement element = GetElement(r, c); if (element == null) { return(0.0); } else { return(element.Value); } } set { if ((r < 0) || (r >= dimension)) { throw new ArgumentOutOfRangeException("r"); } if ((c < 0) || (c >= dimension)) { throw new ArgumentOutOfRangeException("c"); } SetElement(r, c, value); } }
/// <summary> /// Multiplies a column vector by a sparse matrix. /// </summary> /// <param name="A">The matrix.</param> /// <param name="v">The column vector.</param> /// <returns>The product column vector.</returns> public static ColumnVector operator *(SparseSquareMatrix A, ColumnVector v) { if (A == null) { throw new ArgumentNullException("A"); } if (v == null) { throw new ArgumentNullException("v"); } if (A.Dimension != v.Dimension) { throw new DimensionMismatchException(); } ColumnVector Av = new ColumnVector(A.Dimension); for (int i = 0; i < A.Dimension; i++) { SparseMatrixElement element = A.rows[i]; while (element != null) { Av[i] += element.Value * v[element.Column]; element = element.NextInRow; } } return(Av); }
/// <summary> /// Copies the matrix. /// </summary> /// <returns>An independent copy of the matrix.</returns> public SparseSquareMatrix Copy() { // a simple, slow solution is to create an empty sparse matrix with the same dimension and call // set element for each entry; but this moves along each linked list many times // we would like to just move along, say, each row, just once, copying the elements we find // but that isn't simple, because we need to store pointers to the next in row and next in column, // which we don't have on hand as we create the element // dealing with the next in row is easy: just keep a reference to the last one we do and // set its pointer to the next in row when we create the next element in the row // dealing with the next in column is harder; we need to know what is above it in the column, // but that was created a long time ago when we were dealing with a previous row. // to solve this problem, we use auxiluary storage: a N-element array that stores that last // element created in each column. when we create a new element, we hook it up to the previous // element stored in that array, then put the new element in the array SparseMatrixElement[] copyRows = new SparseMatrixElement[dimension]; SparseMatrixElement[] copyColumns = new SparseMatrixElement[dimension]; SparseMatrixElement[] lastInColumn = new SparseMatrixElement[dimension]; for (int r = 0; r < dimension; r++) { SparseMatrixElement element = rows[r]; SparseMatrixElement lastInRow = null; while (element != null) { // create a copy of the element SparseMatrixElement copyElement = new SparseMatrixElement(element.Row, element.Column, element.Value); // hook it up to the previous one in the row (and store it for the next one) if (lastInRow != null) { lastInRow.NextInRow = copyElement; } else { copyRows[r] = copyElement; } lastInRow = copyElement; // hook it up to the previous one in the column (and store it for the next one) if (lastInColumn[element.Column] != null) { lastInColumn[element.Column].NextInColumn = copyElement; } else { copyColumns[element.Column] = copyElement; } lastInColumn[element.Column] = copyElement; // move to the next element in the row element = element.NextInRow; } } SparseSquareMatrix copy = new SparseSquareMatrix(dimension, copyRows, copyColumns, fill); return(copy); }
internal SparseSquareMatrix(int dimension, SparseMatrixElement[] rows, SparseMatrixElement[] columns, int fill) { this.dimension = dimension; this.rows = rows; this.columns = columns; this.fill = fill; }
/// <summary> /// Initializes a new sparse, square matrix. /// </summary> /// <param name="dimension">The dimension of the matrix, which must be positive.</param> public SparseSquareMatrix(int dimension) { if (dimension < 1) { throw new ArgumentOutOfRangeException("dimension"); } this.dimension = dimension; rows = new SparseMatrixElement[dimension]; columns = new SparseMatrixElement[dimension]; fill = 0; }
private SparseMatrixElement GetElement(int r, int c) { SparseMatrixElement current = rows[r]; while (current != null) { if (current.Column == c) { return(current); } current = current.NextInRow; } return(null); }
/// <inheritdoc /> public override ColumnVector Column(int c) { if ((c < 0) || (c >= dimension)) { throw new ArgumentOutOfRangeException("c"); } double[] store = new double[dimension]; SparseMatrixElement element = columns[c]; while (element != null) { store[element.Row] = element.Value; element = element.NextInColumn; } return(new ColumnVector(store, dimension)); }
/// <inheritdoc /> public override RowVector Row(int r) { if ((r < 0) || (r >= dimension)) { throw new ArgumentOutOfRangeException("r"); } double[] store = new double[dimension]; SparseMatrixElement element = rows[r]; while (element != null) { store[element.Column] = element.Value; element = element.NextInRow; } return(new RowVector(store, dimension)); }
/// <summary> /// Multiplies a sparse matrix by a real scalar. /// </summary> /// <param name="alpha">The scalar value.</param> /// <param name="A">The sparse matrix.</param> /// <returns>The product sparse matrix.</returns> public static SparseSquareMatrix operator *(double alpha, SparseSquareMatrix A) { if (A == null) { throw new ArgumentNullException("A"); } SparseSquareMatrix aA = A.Copy(); if (alpha == 0.0) { return(aA); } for (int r = 0; r < aA.dimension; r++) { SparseMatrixElement element = aA.rows[r]; while (element != null) { element.Value = alpha * element.Value; // handle the case where alpha != 0, but alpha * element.Value underflows to zero element = element.NextInRow; } } return(aA); }
private SparseMatrixElement SetElement(int r, int c, double value) { // if the row is empty: previousInRow == null, nextInRow == null // if the new element is the leftmost in the row: previousInRow == null, nextInRow != null // if the new element is intermediate in the row: previousInRow != null, nextInRow != null // if the new element is the rightmost in the row: previousInRow != null, nextInRow == null // if the element already exists: nextInRow is the element element, previousInRow is null if it is the first in the row SparseMatrixElement previousInRow = null; SparseMatrixElement nextInRow = rows[r]; while ((nextInRow != null) && (nextInRow.Column < c)) { previousInRow = nextInRow; nextInRow = nextInRow.NextInRow; } SparseMatrixElement previousInColumn = null; SparseMatrixElement nextInColumn = columns[c]; while ((nextInColumn != null) && (nextInColumn.Row < r)) { previousInColumn = nextInColumn; nextInColumn = nextInColumn.NextInColumn; } if ((nextInRow != null) && (nextInRow.Row == r) && (nextInRow.Column == c)) { // the element already exists if (value != 0.0) { // if the value is non-zero, just update it nextInRow.Value = value; return(nextInRow); } else { // if the value is zero, delete the element if (previousInRow == null) { rows[r] = nextInRow.NextInRow; } else { previousInRow.NextInRow = nextInRow.NextInRow; } if (previousInColumn == null) { columns[c] = nextInColumn.NextInColumn; } else { previousInColumn.NextInColumn = nextInColumn.NextInColumn; } fill--; return(null); } } else { // the element does not yet exist if (value == 0.0) { // if the value is zero, we don't need to do anything return(null); } else { // otherwise, we need to create an element SparseMatrixElement element = new SparseMatrixElement(r, c, value); if (previousInRow == null) { rows[r] = element; } else { previousInRow.NextInRow = element; } element.NextInRow = nextInRow; if (previousInColumn == null) { columns[c] = element; } else { previousInColumn.NextInColumn = element; } element.NextInColumn = nextInColumn; fill++; return(element); } } }
private SparseMatrixElement SetElement(int r, int c, double value) { // if the row is empty: previousInRow == null, nextInRow == null // if the new element is the leftmost in the row: previousInRow == null, nextInRow != null // if the new element is intermediate in the row: previousInRow != null, nextInRow != null // if the new element is the rightmost in the row: previousInRow != null, nextInRow == null // if the element already exists: nextInRow is the element element, previousInRow is null if it is the first in the row SparseMatrixElement previousInRow = null; SparseMatrixElement nextInRow = rows[r]; while ((nextInRow != null) && (nextInRow.Column < c)) { previousInRow = nextInRow; nextInRow = nextInRow.NextInRow; } SparseMatrixElement previousInColumn = null; SparseMatrixElement nextInColumn = columns[c]; while ((nextInColumn != null) && (nextInColumn.Row < r)) { previousInColumn = nextInColumn; nextInColumn = nextInColumn.NextInColumn; } if ((nextInRow != null) && (nextInRow.Row == r) && (nextInRow.Column == c)) { // the element already exists if (value != 0.0) { // if the value is non-zero, just update it nextInRow.Value = value; return (nextInRow); } else { // if the value is zero, delete the element if (previousInRow == null) { rows[r] = nextInRow.NextInRow; } else { previousInRow.NextInRow = nextInRow.NextInRow; } if (previousInColumn == null) { columns[c] = nextInColumn.NextInColumn; } else { previousInColumn.NextInColumn = nextInColumn.NextInColumn; } fill--; return (null); } } else { // the element does not yet exist if (value == 0.0) { // if the value is zero, we don't need to do anything return (null); } else { // otherwise, we need to create an element SparseMatrixElement element = new SparseMatrixElement(r, c, value); if (previousInRow == null) { rows[r] = element; } else { previousInRow.NextInRow = element; } element.NextInRow = nextInRow; if (previousInColumn == null) { columns[c] = element; } else { previousInColumn.NextInColumn = element; } element.NextInColumn = nextInColumn; fill++; return (element); } } }
/// <summary> /// Copies the matrix. /// </summary> /// <returns>An independent copy of the matrix.</returns> public SparseSquareMatrix Copy() { // a simple, slow solution is to create an empty sparse matrix with the same dimension and call // set element for each entry; but this moves along each linked list many times // we would like to just move along, say, each row, just once, copying the elements we find // but that isn't simple, because we need to store pointers to the next in row and next in column, // which we don't have on hand as we create the element // dealing with the next in row is easy: just keep a reference to the last one we do and // set its pointer to the next in row when we create the next element in the row // dealing with the next in column is harder; we need to know what is above it in the column, // but that was created a long time ago when we were dealing with a previous row. // to solve this problem, we use auxiluary storage: a N-element array that stores that last // element created in each column. when we create a new element, we hook it up to the previous // element stored in that array, then put the new element in the array SparseMatrixElement[] copyRows = new SparseMatrixElement[dimension]; SparseMatrixElement[] copyColumns = new SparseMatrixElement[dimension]; SparseMatrixElement[] lastInColumn = new SparseMatrixElement[dimension]; for (int r = 0; r < dimension; r++) { SparseMatrixElement element = rows[r]; SparseMatrixElement lastInRow = null; while (element != null) { // create a copy of the element SparseMatrixElement copyElement = new SparseMatrixElement(element.Row, element.Column, element.Value); // hook it up to the previous one in the row (and store it for the next one) if (lastInRow != null) { lastInRow.NextInRow = copyElement; } else { copyRows[r] = copyElement; } lastInRow = copyElement; // hook it up to the previous one in the column (and store it for the next one) if (lastInColumn[element.Column] != null) { lastInColumn[element.Column].NextInColumn = copyElement; } else { copyColumns[element.Column] = copyElement; } lastInColumn[element.Column] = copyElement; // move to the next element in the row element = element.NextInRow; } } SparseSquareMatrix copy = new SparseSquareMatrix(dimension, copyRows, copyColumns, fill); return (copy); }