public static void SolveLowerLeftTriangular(double[] tStore, double[] x, int xOffset, int dimension) { for (int r = 0; r < dimension; r++) { double t = Blas1.dDot(tStore, r, dimension, x, xOffset, 1, r); x[xOffset + r] -= t; } }
public static void SolveUpperRightTriangular(double[] tStore, double[] x, int xOffset, int dimension) { for (int r = dimension - 1; r >= 0; r--) { int i0 = dimension * r + r; double t = Blas1.dDot(tStore, i0 + dimension, dimension, x, xOffset + r + 1, 1, dimension - r - 1); x[xOffset + r] = (x[xOffset + r] - t) / tStore[i0]; } }
// Apply a Householder transfrom defined by v to the vector x (which may be // a column of a matrix, if H is applied from the left, or a row of a matrix // if H is applied from the right). On exit v is unchanged, x is changed. // We have H = I - \beta v v^T, so H x = x - (\beta v^T x) v. public static void ApplyHouseholderReflection( double[] uStore, int uOffset, int uStride, double[] yStore, int yOffset, int yStride, int count ) { double s = Blas1.dDot(uStore, uOffset, uStride, yStore, yOffset, yStride, count); Blas1.dAxpy(-s, uStore, uOffset, uStride, yStore, yOffset, yStride, count); }
// Solve a triangular system // aIsUpper indicates whether A is upper/right or lower/left // aIsUnit indicates whether A's diagonal elements are all 1 or not // The relevent elements of xStore are overwritten by the solution vector public static void dTrsv( bool aIsUpper, bool aIsUnit, double[] aStore, int aOffset, int aRowStride, int aColStride, double[] xStore, int xOffset, int xStride, int count ) { int aDiagonalStride = aColStride + aRowStride; // If A is upper triangular, start at the bottom/right and reverse the direction of progression. // This does not affect the passed in variables because integers are pass-by-value. if (aIsUpper) { aOffset = aOffset + (count - 1) * aDiagonalStride; aRowStride = -aRowStride; aColStride = -aColStride; aDiagonalStride = -aDiagonalStride; xOffset = xOffset + (count - 1) * xStride; xStride = -xStride; } // The index of the first row element to be subtracted in the numerator. int aRowIndex = aOffset; // The index of the x element to be solved for. int xIndex = xOffset; // We hoist the aIsUnit test outside the loop and pay the cost of a little repeated code in // order to avoid an unnecessary per-loop test. It's possible the compiler could do this for us. if (aIsUnit) { for (int n = 0; n < count; n++) { xStore[xIndex] -= Blas1.dDot(aStore, aRowIndex, aColStride, xStore, xOffset, xStride, n); aRowIndex += aRowStride; xIndex += xStride; } } else { int aDiagonalIndex = aOffset; for (int n = 0; n < count; n++) { xStore[xIndex] -= Blas1.dDot(aStore, aRowIndex, aColStride, xStore, xOffset, xStride, n); xStore[xIndex] /= aStore[aDiagonalIndex]; aRowIndex += aRowStride; aDiagonalIndex += aDiagonalStride; xIndex += xStride; } } }
// y <- A x + y public static void dGemv( double[] aStore, int aOffset, int aRowStride, int aColStride, double[] xStore, int xOffset, int xStride, double[] yStore, int yOffset, int yStride, int rows, int cols ) { int aIndex = aOffset; int yIndex = yOffset; for (int n = 0; n < rows; n++) { yStore[yIndex] += Blas1.dDot(aStore, aIndex, aColStride, xStore, xOffset, xStride, cols); aIndex += aRowStride; yIndex += yStride; } }
/// <summary> /// Computes the inner (scalar or dot) product of a row and a column vector. /// </summary> /// <param name="v">The row vector.</param> /// <param name="u">The column vector.</param> /// <returns>The value of the scalar product.</returns> public static double operator *(RowVector v, ColumnVector u) { if (v == null) { throw new ArgumentNullException(nameof(v)); } if (u == null) { throw new ArgumentNullException(nameof(u)); } if (v.dimension != u.dimension) { throw new DimensionMismatchException(); } double p = Blas1.dDot(v.store, v.offset, v.stride, u.store, u.offset, u.stride, v.dimension); return(p); }
// on input: // store contains the matrix in column-major order (must have the length dimension^2) // permutation contains the row permutation (typically 0, 1, 2, ..., dimension - 1; must have the length dimension^2) // parity contains the parity of the row permutation (typically 1; must be 1 or -1) // dimension contains the dimension of the matrix (must be non-negative) // on output: // store is replaced by the L and U matrices, L in the lower-left triangle (with 1s along the diagonal), U in the upper-right triangle // permutation is replaced by the row permutation, and parity be the parity of that permutation // A = PLU public static void LUDecompose(double[] store, int[] permutation, ref int parity, int dimension) { for (int d = 0; d < dimension; d++) { int pivotRow = -1; double pivotValue = 0.0; for (int r = d; r < dimension; r++) { int a0 = dimension * d + r; double t = store[a0] - Blas1.dDot(store, r, dimension, store, dimension * d, 1, d); store[a0] = t; if (Math.Abs(t) > Math.Abs(pivotValue)) { pivotRow = r; pivotValue = t; } } if (pivotValue == 0.0) { throw new DivideByZeroException(); } if (pivotRow != d) { // switch rows Blas1.dSwap(store, d, dimension, store, pivotRow, dimension, dimension); int t = permutation[pivotRow]; permutation[pivotRow] = permutation[d]; permutation[d] = t; parity = -parity; } Blas1.dScal(1.0 / pivotValue, store, dimension * d + d + 1, 1, dimension - d - 1); for (int c = d + 1; c < dimension; c++) { double t = Blas1.dDot(store, d, dimension, store, dimension * c, 1, d); store[dimension * c + d] -= t; } } }
public static void SolveUpperRightTriangular(double[] tStore, int tRows, int tCols, double[] xStore, int xOffset) { Debug.Assert(tRows >= tCols); // pre-calculate some useful quantities int trp1 = tRows + 1; int tcm1 = tCols - 1; // initialize the x index (to its highest value) the the diagonal t index (to its highest value) int xIndex = xOffset + tcm1; int tIndex = trp1 * tcm1; // do the first, trivial back-substitution xStore[xIndex] /= tStore[tIndex]; // do the remaining back-substitutions, each of which requires subtracting n previously computed x-values for (int n = 1; n <= tcm1; n++) { xIndex -= 1; tIndex -= trp1; double t = Blas1.dDot(tStore, tIndex + tRows, tRows, xStore, xIndex + 1, 1, n); xStore[xIndex] = (xStore[xIndex] - t) / tStore[tIndex]; } }