/// <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 }
/// <summary> /// Sparse QR factorization [V,beta,pinv,R] = qr (A) /// </summary> static NumericFactorization Factorize(SparseMatrix A, SymbolicFactorization S) { double[] Beta; int i, p, p1, top, len, col; int m = A.m; int n = A.n; int[] Ap = A.p; int[] Ai = A.i; double[] Ax = A.x; int[] q = S.q; int[] parent = S.parent; int[] pinv = S.pinv; int m2 = S.m2; int vnz = S.lnz; int rnz = S.unz; int[] leftmost = S.leftmost; int[] w = new int[m2 + n]; // get int workspace double[] x = new double[m2]; // get double workspace int s = m2; // offset into w SparseMatrix R, V; NumericFactorization N = new NumericFactorization(); // allocate result N.L = V = new SparseMatrix(m2, n, vnz, true); // allocate result V N.U = R = new SparseMatrix(m2, n, rnz, true); // allocate result R N.B = Beta = new double[n]; // allocate result Beta int[] Rp = R.p; int[] Ri = R.i; double[] Rx = R.x; int[] Vp = V.p; int[] Vi = V.i; double[] Vx = V.x; for (i = 0; i < m2; i++) { w[i] = -1; // clear w, to mark nodes } rnz = 0; vnz = 0; for (int k = 0; k < n; k++) // compute V and R { Rp[k] = rnz; // R(:,k) starts here Vp[k] = p1 = vnz; // V(:,k) starts here w[k] = k; // add V(k,k) to pattern of V Vi[vnz++] = k; top = n; col = q != null ? q[k] : k; for (p = Ap[col]; p < Ap[col + 1]; p++) // find R(:,k) pattern { i = leftmost[Ai[p]]; // i = min(find(A(i,q))) for (len = 0; w[i] != k; i = parent[i]) // traverse up to k { //len++; w[s + len++] = i; w[i] = k; } while (len > 0) { --top; --len; w[s + top] = w[s + len]; // push path on stack } i = pinv[Ai[p]]; // i = permuted row of A(:,col) x[i] = Ax[p]; // x (i) = A(:,col) if (i > k && w[i] < k) // pattern of V(:,k) = x (k+1:m) { Vi[vnz++] = i; // add i to pattern of V(:,k) w[i] = k; } } for (p = top; p < n; p++) // for each i in pattern of R(:,k) { i = w[s + p]; // R(i,k) is nonzero ApplyHouseholder(V, i, Beta[i], x); // apply (V(i),Beta(i)) to x Ri[rnz] = i; // R(i,k) = x(i) Rx[rnz++] = x[i]; x[i] = 0; if (parent[i] == k) { vnz = V.Scatter(i, 0, w, null, k, V, vnz); } } for (p = p1; p < vnz; p++) // gather V(:,k) = x { Vx[p] = x[Vi[p]]; x[Vi[p]] = 0; } Ri[rnz] = k; // R(k,k) = norm (x) Rx[rnz++] = CreateHouseholder(Vx, p1, ref Beta[k], vnz - p1); // [v,beta]=house(x) } Rp[n] = rnz; // finalize R Vp[n] = vnz; // finalize V return(N); // success }