/// <summary> /// Symbolic ordering and analysis for QR. /// </summary> /// <param name="A">Matrix to factorize.</param> /// <param name="p">Permutation.</param> protected void SymbolicAnalysis(CompressedColumnStorage <T> A, int[] p, bool natural) { int m = A.RowCount; int n = A.ColumnCount; var sym = this.S = new SymbolicFactorization(); // Fill-reducing ordering sym.q = p; var C = natural ? SymbolicColumnStorage.Create(A) : Permute(A, null, sym.q); // etree of C'*C, where C=A(:,q) sym.parent = GraphHelper.EliminationTree(m, n, C.ColumnPointers, C.RowIndices, true); int[] post = GraphHelper.TreePostorder(sym.parent, n); sym.cp = GraphHelper.ColumnCounts(C, sym.parent, post, true); // col counts chol(C'*C) bool ok = C != null && sym.parent != null && sym.cp != null && CountV(C, sym); if (ok) { sym.unz = 0; for (int k = 0; k < n; k++) { sym.unz += sym.cp[k]; } } }
/// <summary> /// Compute nnz(V) = S.lnz, S.pinv, S.leftmost, S.m2 from A and S.parent /// </summary> private bool CountV(SymbolicColumnStorage A, SymbolicFactorization S) { int i, k, p, pa; int[] pinv, leftmost, parent = S.parent; int m = A.RowCount; int n = A.ColumnCount; int[] ap = A.ColumnPointers; int[] ai = A.RowIndices; S.pinv = pinv = new int[m + n]; // allocate pinv, S.leftmost = leftmost = new int[m]; // and leftmost var w = new int[m]; // get workspace var head = new int[n]; var tail = new int[n]; var nque = new int[n]; // Initialized to 0's for (k = 0; k < n; k++) { head[k] = -1; // queue k is empty } for (k = 0; k < n; k++) { tail[k] = -1; } for (i = 0; i < m; i++) { leftmost[i] = -1; } for (k = n - 1; k >= 0; k--) { for (p = ap[k]; p < ap[k + 1]; p++) { leftmost[ai[p]] = k; // leftmost[i] = min(find(A(i,:))) } } for (i = m - 1; i >= 0; i--) // scan rows in reverse order { pinv[i] = -1; // row i is not yet ordered k = leftmost[i]; if (k == -1) { continue; // row i is empty } if (nque[k]++ == 0) { tail[k] = i; // first row in queue k } w[i] = head[k]; // put i at head of queue k head[k] = i; } S.lnz = 0; S.m2 = m; for (k = 0; k < n; k++) // find row permutation and nnz(V) { i = head[k]; // remove row i from queue k S.lnz++; // count V(k,k) as nonzero if (i < 0) { i = S.m2++; // add a fictitious row } pinv[i] = k; // associate row i with V(:,k) if (--nque[k] <= 0) { continue; // skip if V(k+1:m,k) is empty } S.lnz += nque[k]; // nque [k] is nnz (V(k+1:m,k)) if ((pa = parent[k]) != -1) // move all rows to parent of k { if (nque[pa] == 0) { tail[pa] = tail[k]; } w[tail[k]] = head[pa]; head[pa] = w[i]; nque[pa] += nque[k]; } } for (i = 0; i < m; i++) { if (pinv[i] < 0) { pinv[i] = k++; } } return(true); }