/// <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);
        }