/// <summary> /// Compute the Numeric Cholesky factorization, L = chol (A, [pinv parent cp]). /// </summary> /// <returns>Numeric Cholesky factorization</returns> public static NumericFactorization Factorize(SparseMatrix A, SymbolicFactorization S) { double d, lki; double[] Lx, x, Cx; int top, i, p, k; int[] Li, Lp, cp, pinv, s, c, parent, Cp, Ci; SparseMatrix L, C; NumericFactorization N = new NumericFactorization(); // allocate result int n = A.n; c = new int[n]; // get int workspace s = new int[n]; x = new double[n]; // get double workspace cp = S.cp; pinv = S.pinv; parent = S.parent; C = pinv != null?A.PermuteSym(pinv, true) : A; Cp = C.p; Ci = C.i; Cx = C.x; N.L = L = new SparseMatrix(n, n, cp[n], true); // allocate result Lp = L.p; Li = L.i; Lx = L.x; for (k = 0; k < n; k++) { Lp[k] = c[k] = cp[k]; } for (k = 0; k < n; k++) // compute L(k,:) for L*L' = C { // Nonzero pattern of L(k,:) top = Common.EReach(C, k, parent, s, c); // find pattern of L(k,:) x[k] = 0; // x (0:k) is now zero for (p = Cp[k]; p < Cp[k + 1]; p++) // x = full(triu(C(:,k))) { if (Ci[p] <= k) { x[Ci[p]] = Cx[p]; } } d = x[k]; // d = C(k,k) x[k] = 0; // clear x for k+1st iteration // Triangular solve for (; top < n; top++) // solve L(0:k-1,0:k-1) * x = C(:,k) { i = s[top]; // s [top..n-1] is pattern of L(k,:) lki = x[i] / Lx[Lp[i]]; // L(k,i) = x (i) / L(i,i) x[i] = 0; // clear x for k+1st iteration for (p = Lp[i] + 1; p < c[i]; p++) { x[Li[p]] -= Lx[p] * lki; } d -= lki * lki; // d = d - L(k,i)*L(k,i) p = c[i]++; Li[p] = k; // store L(k,i) in column i Lx[p] = lki; } // Compute L(k,k) if (d <= 0) { return(null); // not pos def } p = c[k]++; Li[p] = k; // store L(k,k) = sqrt (d) in column k Lx[p] = Math.Sqrt(d); } Lp[n] = cp[n]; // finalize L return(N); // 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 }
// [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 }