/// <summary> /// Links vector elements. /// </summary> /// <param name="vector">The vector.</param> /// <param name="row">The row variable.</param> private void LinkElement(ISparseVector <T> vector, Bridge <int> row) { var loc = Solver.ExternalToInternal(new MatrixLocation(row.Local, row.Local)); // Do we need to create an element? var local_elt = vector.FindElement(loc.Row); if (local_elt == null) { // Check if solving will result in an element var first = vector.GetFirstInVector(); if (first == null || first.Index > Solver.Size - Solver.Degeneracy) { return; } local_elt = vector.GetElement(loc.Row); } if (local_elt == null) { return; } var parent_elt = Parent.Solver.GetElement(row.Global); _elements.Add(new Bridge <Element <T> >(local_elt, parent_elt)); }
private void Count(ISparseMatrix <T> matrix, ISparseVector <T> rhs, int step, int max) { ISparseMatrixElement <T> element; // Get the first element in the vector var rhsElement = rhs.GetFirstInVector(); // Generate Markowitz row count for (var i = max; i >= step; i--) { // Set count to -1 initially to remove count due to pivot element var count = -1; element = matrix.GetFirstInRow(i); while (element != null && element.Column < step) { element = element.Right; } while (element != null) // We want to count the elements outside the limit as well { count++; element = element.Right; } // Include elements on the Rhs vector while (rhsElement != null && rhsElement.Index < step) { rhsElement = rhsElement.Below; } if (rhsElement != null && rhsElement.Index == i) { count++; } _markowitzRow[i] = Math.Min(count, _maxMarkowitzCount); } // Generate Markowitz column count for (var i = step; i <= max; i++) { // Set count to -1 initially to remove count due to pivot element var count = -1; element = matrix.GetFirstInColumn(i); while (element != null && element.Row < step) { element = element.Below; } while (element != null) { count++; element = element.Below; } _markowitzColumn[i] = Math.Min(count, _maxMarkowitzCount); } }
/// <summary> /// MPI-parallel 2-norm /// </summary> static public double drnm2 <TX>(int N, TX x, int incx, MPI_Comm comm) where TX : IList <double> { double locRes = 0; double[] dx = x as double[]; if (dx != null) { // double[] - implementation locRes = BLAS.dnrm2(N, dx, incx); locRes = locRes * locRes; } else { ISparseVector <double> spx = x as ISparseVector <double>; if (spx != null) { // sparse implementation foreach (var entry in spx.SparseStruct) { int m = entry.Key % incx; if (m != 0) { // entry is skipped by x-increment continue; } double xi = entry.Value; locRes += xi * xi; } } else { // default implementation for (int n = 0; n < N; n++) { double xi = x[n * incx]; locRes += xi * xi; } } } double globRes = double.NaN; unsafe { csMPI.Raw.Allreduce((IntPtr)(&locRes), (IntPtr)(&globRes), 1, csMPI.Raw._DATATYPE.DOUBLE, csMPI.Raw._OP.SUM, comm); } return(Math.Sqrt(globRes)); }
/// <summary> /// Setup the pivot strategy. /// </summary> /// <param name="matrix">The matrix.</param> /// <param name="rhs">The right-hand side vector.</param> /// <param name="eliminationStep">The current elimination step.</param> /// <param name="max">The maximum row/column index.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="matrix"/> or <paramref name="rhs"/> is <c>null</c>. /// </exception> public void Setup(ISparseMatrix <T> matrix, ISparseVector <T> rhs, int eliminationStep, int max) { matrix.ThrowIfNull(nameof(matrix)); rhs.ThrowIfNull(nameof(rhs)); // Initialize Markowitz row, column and product vectors if necessary if (_markowitzRow == null || _markowitzRow.Length != matrix.Size + 1) { Initialize(matrix); } Count(matrix, rhs, eliminationStep, max); Products(eliminationStep, max); }
/// <summary> /// blas dscal: <paramref name="X"/> = <paramref name="X"/>*<paramref name="alpha"/>; /// </summary> static public void dscal <T>(int N, double alpha, T X, int incx) where T : IList <double> { ISparseVector <double> spx = X as ISparseVector <double>; double[] arx = X as double[]; if (arx != null) { // double - array -> use BLAS // ++++++++++++++++++++++++++ BLAS.dscal(N, alpha, arx, incx); return; } if (spx != null) { // sparce vector -> compute only nonzero entries // +++++++++++++++++++++++++++++++++++++++++++++ int[] idx = new int[spx.NonZeros]; spx.SparseStruct.Keys.CopyTo(idx, 0); foreach (int i in idx) { int m = i % incx; if (m != 0) { // entry is skipped by x-increment continue; } spx[i] *= alpha; } return; } { // reference version // +++++++++++++++++ for (int i = 0; i < N; i += incx) { X[i] *= alpha; } } }
/// <summary> /// MPI - parallel scalar product /// </summary> static public double ddot <TX, TY>(int N, TX x, int incx, TY y, int incy, MPI.Wrappers.MPI_Comm comm) where TX : IList <double> where TY : IList <double> { if (incx * x.Count < N) { throw new ArgumentException("vector too short.", "x"); } if (incy * y.Count < N) { throw new ArgumentException("vector too short.", "y"); } double locRes = 0; double[] dx = x as double[]; double[] dy = y as double[]; if (dx != null && dy != null) { // use dnese BLAS locRes = BLAS.ddot(N, dx, incx, dy, incy); } else { ISparseVector <double> spx = x as ISparseVector <double>; ISparseVector <double> spy = y as ISparseVector <double>; IList <double> _y = y; if (spy != null) { if (spx == null || spy.Sparsity < spx.Sparsity) { // y is sparser than x, use y ! spx = spy; spy = null; _y = x; x = default(TX); y = default(TY); int buffy = incx; incx = incy; incy = buffy; } } if (spx != null) { // sparse implementation foreach (var entry in spx.SparseStruct) { int m = entry.Key % incx; if (m != 0) { // entry is skipped by x-increment continue; } int n = entry.Key / incx; locRes += entry.Value * _y[n * incy]; } } else { // default IList<double> - implementation for (int n = 0; n < N; n++) { locRes += x[n * incx] * y[n * incy]; } } } double globRes = double.NaN; unsafe { csMPI.Raw.Allreduce((IntPtr)(&locRes), (IntPtr)(&globRes), 1, csMPI.Raw._DATATYPE.DOUBLE, csMPI.Raw._OP.SUM, comm); } return(globRes); }
/// <summary> /// blas daxpy: <paramref name="Y"/> = <paramref name="Y"/> + <paramref name="alpha"/>*<paramref name="X"/>; /// </summary> static public void daxpy <TX, TY>(int N, double alpha, TX X, int INCX, TY Y, int INCY) where TX : IList <double> where TY : IList <double> { if (object.ReferenceEquals(X, Y)) { // while formally there is no problem that this should work, it seems much more likely // that it's a bug. throw new ArgumentException("Illegal use: reference-equality of input vectors -- this might be a mis-use instead of intention."); } { // sparse vector branch // ++++++++++++++++++++ ISparseVector <double> spx = X as ISparseVector <double>; if (spx != null) { foreach (var entry in spx.SparseStruct) { int m = entry.Key % INCX; if (m != 0) { // entry is skipped by x-increment continue; } int n = entry.Key / INCX; double xi = entry.Value; Y[n * INCY] += xi * alpha; } return; } } { // both arrays-branch -> use BLAS // ++++++++++++++++++++++++++++++ double[] _XasDouble = X as double[]; double[] _YasDouble = Y as double[]; if (_XasDouble != null && _YasDouble != null) { BLAS.daxpy(N, alpha, _XasDouble, INCX, _YasDouble, INCY); return; } } { // default branch // ++++++++++++++ for (int n = 0; n < N; n++) { Y[n * INCY] += X[n * INCX] * alpha; } return; } }
/// <summary> /// Move the pivot to the diagonal for this elimination step. /// </summary> /// <param name="matrix">The matrix.</param> /// <param name="rhs">The right-hand side vector.</param> /// <param name="pivot">The pivot element.</param> /// <param name="eliminationStep">The elimination step.</param> /// <remarks> /// This is done by swapping the rows and columns of the diagonal and that of the pivot. /// </remarks> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="matrix"/>, <paramref name="rhs"/> or <paramref name="pivot"/> is <c>null</c>. /// </exception> public void MovePivot(ISparseMatrix <T> matrix, ISparseVector <T> rhs, ISparseMatrixElement <T> pivot, int eliminationStep) { matrix.ThrowIfNull(nameof(matrix)); rhs.ThrowIfNull(nameof(rhs)); pivot.ThrowIfNull(nameof(pivot)); // If we haven't setup, just skip if (_markowitzProduct == null) { return; } int oldProduct; var row = pivot.Row; var col = pivot.Column; // If the pivot is a singleton, then we just consumed it if (_markowitzProduct[row] == 0 || _markowitzProduct[col] == 0) { Singletons--; } // Exchange rows if (row != eliminationStep) { // Swap row Markowitz numbers var tmp = _markowitzRow[row]; _markowitzRow[row] = _markowitzRow[eliminationStep]; _markowitzRow[eliminationStep] = tmp; // Update the Markowitz product oldProduct = _markowitzProduct[row]; _markowitzProduct[row] = _markowitzRow[row] * _markowitzColumn[row]; if (oldProduct == 0) { if (_markowitzProduct[row] != 0) { Singletons--; } } else { if (_markowitzProduct[row] == 0) { Singletons++; } } } // Exchange columns if (col != eliminationStep) { // Swap column Markowitz numbers var tmp = _markowitzColumn[col]; _markowitzColumn[col] = _markowitzColumn[eliminationStep]; _markowitzColumn[eliminationStep] = tmp; // Update the Markowitz product oldProduct = _markowitzProduct[col]; _markowitzProduct[col] = _markowitzRow[col] * _markowitzColumn[col]; if (oldProduct == 0) { if (_markowitzProduct[col] != 0) { Singletons--; } } else { if (_markowitzProduct[col] == 0) { Singletons++; } } } // Also update the moved pivot oldProduct = _markowitzProduct[eliminationStep]; _markowitzProduct[eliminationStep] = _markowitzRow[eliminationStep] * _markowitzColumn[eliminationStep]; if (oldProduct == 0) { if (_markowitzProduct[eliminationStep] != 0) { Singletons--; } } else { if (_markowitzProduct[eliminationStep] == 0) { Singletons++; } } }