/// <summary> /// Sparse matrix multiplication, C = A*B /// </summary> /// <param name="A">column-compressed matrix</param> /// <param name="B">column-compressed matrix</param> /// <returns>C = A*B, null on error</returns> public static SparseMatrix Multiply(SparseMatrix A, SparseMatrix B) { int p, j, nz = 0, anz, m, n, bnz; bool values; int[] Cp, Ci, Bp, w, Bi; double[] x, Bx, Cx; // check inputs if (A == null || B == null) { return(null); } if (A.n != B.m) { return(null); } m = A.m; anz = A.p[A.n]; n = B.n; Bp = B.p; Bi = B.i; Bx = B.x; bnz = Bp[n]; w = new int[m]; // get workspace values = (A.x != null) && (Bx != null); x = values ? new double[m] : null; // get workspace SparseMatrix C = new SparseMatrix(m, n, anz + bnz, values); // allocate result Cp = C.p; for (j = 0; j < n; j++) { if (nz + m > C.nzmax && !C.Resize(2 * (C.nzmax) + m)) { return(null); // out of memory } Ci = C.i; Cx = C.x; // C.i and C.x may be reallocated Cp[j] = nz; // column j of C starts here for (p = Bp[j]; p < Bp[j + 1]; p++) { nz = A.Scatter(Bi[p], Bx != null ? Bx[p] : 1, w, x, j + 1, C, nz); } if (values) { for (p = Cp[j]; p < nz; p++) { Cx[p] = x[Ci[p]]; } } } Cp[n] = nz; // finalize the last column of C C.Resize(0); // remove extra space from C return(C); // success }
/// <summary> /// C = alpha*A + beta*B /// </summary> /// <param name="A">column-compressed matrix</param> /// <param name="B">column-compressed matrix</param> /// <param name="alpha">scalar alpha</param> /// <param name="beta">scalar beta</param> /// <returns>C=alpha*A + beta*B, null on error</returns> public static SparseMatrix Add(SparseMatrix A, SparseMatrix B, double alpha = 1.0, double beta = 1.0) { int p, j, nz = 0, anz, m, n, bnz; int[] Cp, Ci, Bp, w; bool values; double[] x, Bx, Cx; // check inputs if (A == null || B == null) { return(null); } if (A.m != B.m || A.n != B.n) { return(null); } m = A.m; anz = A.p[A.n]; n = B.n; Bp = B.p; Bx = B.x; bnz = Bp[n]; w = new int[m]; // get workspace values = (A.x != null) && (Bx != null); x = values ? new double[m] : null; // get workspace SparseMatrix C = new SparseMatrix(m, n, anz + bnz, values); // allocate result Cp = C.p; Ci = C.i; Cx = C.x; for (j = 0; j < n; j++) { Cp[j] = nz; // column j of C starts here nz = A.Scatter(j, alpha, w, x, j + 1, C, nz); // alpha*A(:,j) nz = B.Scatter(j, beta, w, x, j + 1, C, nz); // beta*B(:,j) if (values) { for (p = Cp[j]; p < nz; p++) { Cx[p] = x[Ci[p]]; } } } Cp[n] = nz; // finalize the last column of C C.Resize(0); // remove extra space from C return(C); // success }
// [L,U,pinv]=lu(A, [q lnz unz]). lnz and unz can be guess static NumericFactorization Factorize(SparseMatrix A, SymbolicFactorization S, double tol) { int i, n = A.n; int[] q = S.q; int lnz = S.lnz; int unz = S.unz; int[] pinv; NumericFactorization N = new NumericFactorization(); // allocate result SparseMatrix L, U; N.L = L = new SparseMatrix(n, n, lnz, true); // allocate result L N.U = U = new SparseMatrix(n, n, unz, true); // allocate result U N.pinv = pinv = new int[n]; // allocate result pinv double[] x = new double[n]; // get double workspace int[] xi = new int[2 * n]; // get int workspace for (i = 0; i < n; i++) { pinv[i] = -1; // no rows pivotal yet } lnz = unz = 0; int ipiv, top, p, col; double pivot, a, t; int[] Li, Ui, Lp = L.p, Up = U.p; double[] Lx, Ux; for (int k = 0; k < n; k++) // compute L(:,k) and U(:,k) { // Triangular solve Lp[k] = lnz; // L(:,k) starts here Up[k] = unz; // U(:,k) starts here if ((lnz + n > L.nzmax && !L.Resize(2 * L.nzmax + n)) || (unz + n > U.nzmax && !U.Resize(2 * U.nzmax + n))) { return(null); } Li = L.i; Lx = L.x; Ui = U.i; Ux = U.x; col = q != null ? (q[k]) : k; top = Triangular.SolveSp(L, A, col, xi, x, pinv, true); // x = L\A(:,col) // Find pivot ipiv = -1; a = -1; for (p = top; p < n; p++) { i = xi[p]; // x(i) is nonzero if (pinv[i] < 0) // row i is not yet pivotal { if ((t = Math.Abs(x[i])) > a) { a = t; // largest pivot candidate so far ipiv = i; } } else // x(i) is the entry U(pinv[i],k) { Ui[unz] = pinv[i]; Ux[unz++] = x[i]; } } if (ipiv == -1 || a <= 0) { return(null); } if (pinv[col] < 0 && Math.Abs(x[col]) >= a * tol) { ipiv = col; } // Divide by pivot pivot = x[ipiv]; // the chosen pivot Ui[unz] = k; // last entry in U(:,k) is U(k,k) Ux[unz++] = pivot; pinv[ipiv] = k; // ipiv is the kth pivot row Li[lnz] = ipiv; // first entry in L(:,k) is L(k,k) = 1 Lx[lnz++] = 1; for (p = top; p < n; p++) // L(k+1:n,k) = x / pivot { i = xi[p]; if (pinv[i] < 0) // x(i) is an entry in L(:,k) { Li[lnz] = i; // save unpermuted row in L Lx[lnz++] = x[i] / pivot; // scale pivot column } x[i] = 0; // x [0..n-1] = 0 for next k } } // Finalize L and U Lp[n] = lnz; Up[n] = unz; Li = L.i; // fix row indices of L for final pinv for (p = 0; p < lnz; p++) { Li[p] = pinv[Li[p]]; } L.Resize(0); // remove extra space from L and U U.Resize(0); return(N); // success }
/// <summary> /// Sparse matrix multiplication, C = A*B /// </summary> /// <param name="other">column-compressed matrix</param> /// <returns>C = A*B, null on error</returns> public override CompressedColumnStorage <double> Multiply(CompressedColumnStorage <double> other) { if (other == null) { throw new ArgumentNullException(nameof(other)); } int p, j, nz = 0; int[] cp, ci; double[] cx; int m = this.rowCount; int n = other.ColumnCount; int anz = this.NonZerosCount; int bnz = other.NonZerosCount; if (this.ColumnCount != other.RowCount) { throw new ArgumentException(Resources.MatrixDimensions); } if ((m > 0 && this.ColumnCount == 0) || (other.RowCount == 0 && n > 0)) { throw new Exception(Resources.InvalidDimensions); } var bp = other.ColumnPointers; var bi = other.RowIndices; var bx = other.Values; // Workspace var w = new int[m]; var x = new double[m]; var result = new SparseMatrix(m, n, anz + bnz); cp = result.ColumnPointers; for (j = 0; j < n; j++) { if (nz + m > result.Values.Length) { // Might throw out of memory exception. result.Resize(2 * (result.Values.Length) + m); } ci = result.RowIndices; cx = result.Values; // C.i and C.x may be reallocated cp[j] = nz; // column j of C starts here for (p = bp[j]; p < bp[j + 1]; p++) { nz = this.Scatter(bi[p], bx[p], w, x, j + 1, result, nz); } for (p = cp[j]; p < nz; p++) { cx[p] = x[ci[p]]; } } cp[n] = nz; // finalize the last column of C result.Resize(0); // remove extra space from C result.SortIndices(); return(result); // success }