/// <summary> /// Ordering and symbolic analysis for a Cholesky factorization. /// </summary> /// <param name="A">Matrix to factorize.</param> /// <param name="p">Permutation.</param> private void SymbolicAnalysis(CompressedColumnStorage <Complex> A, int[] p) { int n = A.ColumnCount; var sym = this.S = new SymbolicFactorization(); // Find inverse permutation. sym.pinv = Permutation.Invert(p); // C = spones(triu(A(P,P))) var C = PermuteSym(A, sym.pinv, false); // Find etree of C. sym.parent = GraphHelper.EliminationTree(n, n, C.ColumnPointers, C.RowIndices, false); // Postorder the etree. var post = GraphHelper.TreePostorder(sym.parent, n); // Find column counts of chol(C) var c = GraphHelper.ColumnCounts(SymbolicColumnStorage.Create(C, false), sym.parent, post, false); sym.cp = new int[n + 1]; // Find column pointers for L sym.unz = sym.lnz = Helper.CumulativeSum(sym.cp, c, n); }
/// <summary> /// Symbolic ordering and analysis for QR. /// </summary> private void SymbolicAnalysis(ColumnOrdering order, CompressedColumnStorage <double> A) { int m = A.RowCount; int n = A.ColumnCount; var sym = this.symFactor = new SymbolicFactorization(); // Fill-reducing ordering sym.q = AMD.Generate(A, order); var C = order > 0 ? Permute(A, null, sym.q) : SymbolicColumnStorage.Create(A); // 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); if (ok) { sym.unz = 0; for (int k = 0; k < n; k++) { sym.unz += sym.cp[k]; } } }
/// <summary> /// Ordering and symbolic analysis for a Cholesky factorization /// </summary> /// <param name="order"></param> /// <param name="A"></param> /// <returns></returns> static SymbolicFactorization SymbolicAnalysis(int order, SparseMatrix A) { int n = A.n; int[] c, post, P; SymbolicFactorization S = new SymbolicFactorization(); // allocate result S P = Ordering.AMD(order, A); // P = amd(A+A'), or natural S.pinv = Common.InversePermutation(P, n); // find inverse permutation if (order != 0 && S.pinv == null) { return(null); } SparseMatrix C = A.PermuteSym(S.pinv, false); // C = spones(triu(A(P,P))) S.parent = Common.EliminationTree(C, false); // find etree of C post = Common.TreePostorder(S.parent, n); // postorder the etree c = Common.ColumnCounts(C, S.parent, post, false); // find column counts of chol(C) S.cp = new int[n + 1]; // allocate result S.cp S.unz = S.lnz = Common.CumulativeSum(S.cp, c, n); // find column pointers for L return(S); }
/// <summary> /// Symbolic ordering and analysis for LU. /// </summary> /// <param name="A"></param> /// <param name="p">Permutation.</param> private void SymbolicAnalysis(CompressedColumnStorage <Complex> A, int[] p) { var sym = this.S = new SymbolicFactorization(); // Fill-reducing ordering sym.q = p; // Guess nnz(L) and nnz(U) sym.unz = sym.lnz = 4 * (A.ColumnPointers[n]) + n; }
/// <summary> /// Symbolic ordering and analysis for LU. /// </summary> /// <param name="order"></param> /// <param name="A"></param> private void SymbolicAnalysis(ColumnOrdering order, CompressedColumnStorage <double> A) { var sym = this.symFactor = new SymbolicFactorization(); // Fill-reducing ordering sym.q = AMD.Generate(A, order); // Guess nnz(L) and nnz(U) sym.unz = sym.lnz = 4 * (A.ColumnPointers[n]) + n; }
/// <summary> /// Symbolic ordering and analysis for LU. /// </summary> /// <param name="order"></param> /// <param name="A"></param> /// <returns></returns> static SymbolicFactorization SymbolicAnalysis(int order, SparseMatrix A) { // ori: cs_sqr int n = A.n; SymbolicFactorization S = new SymbolicFactorization(); // allocate result S S.q = Ordering.AMD(order, A); // fill-reducing ordering if (order != 0 && S.q == null) { return(null); } S.unz = 4 * (A.p[n]) + n; // For LU factorization only S.lnz = S.unz; // Guess nnz(L) and nnz(U) return(S); // return result S }
/// <summary> /// Symbolic ordering and analysis for QR /// </summary> static SymbolicFactorization SymbolicAnalysis(int order, SparseMatrix A) { // ori: cs_sqr int n = A.n, k; bool ok = true; int[] post; SymbolicFactorization S = new SymbolicFactorization(); // allocate result S S.q = Ordering.AMD(order, A); // fill-reducing ordering if (order != 0 && S.q == null) { return(null); } SparseMatrix C = order > 0 ? (SparseMatrix)A.Permute(null, S.q, false) : A; S.parent = Common.EliminationTree(C, true); // etree of C'*C, where C=A(:,q) post = Common.TreePostorder(S.parent, n); S.cp = Common.ColumnCounts(C, S.parent, post, true); // col counts chol(C'*C) ok = C != null && S.parent != null && S.cp != null && CountV(C, S); if (ok) { for (S.unz = 0, k = 0; k < n; k++) { S.unz += S.cp[k]; } } ok = ok && S.lnz >= 0 && S.unz >= 0; // int overflow guard return(ok ? S : null); // return result S }
/// <summary> /// Ordering and symbolic analysis for a LDL' factorization. /// </summary> /// <param name="order">Column ordering.</param> /// <param name="A">Matrix to factorize.</param> private void SymbolicAnalysis(ColumnOrdering order, CompressedColumnStorage <double> A) { int n = A.ColumnCount; var sym = this.S = new SymbolicFactorization(); var ap = A.ColumnPointers; var ai = A.RowIndices; // P = amd(A+A') or natural var P = AMD.Generate(A, order); var Pinv = Permutation.Invert(P); // Output: column pointers and elimination tree. var lp = new int[n + 1]; var parent = new int[n]; // Workspace var lnz = new int[n]; var flag = new int[n]; int i, k, p, kk, p2; for (k = 0; k < n; k++) { // L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) parent[k] = -1; // parent of k is not yet known flag[k] = k; // mark node k as visited lnz[k] = 0; // count of nonzeros in column k of L kk = (P != null) ? (P[k]) : (k); // kth original, or permuted, column p2 = ap[kk + 1]; for (p = ap[kk]; p < p2; p++) { // A(i,k) is nonzero (original or permuted A) i = (Pinv != null) ? (Pinv[ai[p]]) : (ai[p]); if (i < k) { // follow path from i to root of etree, stop at flagged node for (; flag[i] != k; i = parent[i]) { // find parent of i if not yet determined if (parent[i] == -1) { parent[i] = k; } lnz[i]++; // L(k,i) is nonzero flag[i] = k; // mark i as visited } } } } // construct Lp index array from Lnz column counts lp[0] = 0; for (k = 0; k < n; k++) { lp[k + 1] = lp[k] + lnz[k]; } sym.parent = parent; sym.cp = lp; sym.q = P; sym.pinv = Pinv; }
/// <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) { Complex d, lki; Complex[] 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 Complex[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 * Complex.Conjugate(lki); // d = d - L(k,i)*L(k,i) p = c[i]++; Li[p] = k; // store L(k,i) in column i Lx[p] = Complex.Conjugate(lki); } // Compute L(k,k) if (d.Real <= 0 || d.Imaginary != 0) { return(null); // not pos def } p = c[k]++; Li[p] = k; // store L(k,k) = sqrt (d) in column k Lx[p] = Complex.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; Complex[] 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 Complex[] x = new Complex[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; Complex[] Rx = R.x; int[] Vp = V.p; int[] Vi = V.i; Complex[] 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 }
/// <summary> /// Compute nnz(V) = S.lnz, S.pinv, S.leftmost, S.m2 from A and S.parent /// </summary> static bool CountV(SparseMatrix A, SymbolicFactorization S) { int i, k, p, pa, n = A.n, m = A.m; int[] Ap = A.p, Ai = A.i, head, tail, nque, pinv, leftmost, w, parent = S.parent; S.pinv = pinv = new int[m + n]; // allocate pinv, S.leftmost = leftmost = new int[m]; // and leftmost w = new int[m]; // get workspace head = new int[n]; tail = new int[n]; 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); }
// [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 }
public static CCS GenerateP_Delta_Mpc(Model target, LoadCase loadCase, IRrefFinder rrefFinder) { target.ReIndexNodes(); var n = target.Nodes.Count; var boundaryConditions = GetModelBoundaryConditions(target, loadCase); var lastRow = 0; #region step 1 //step 1: combine all eqs to one system //var filledCols = new bool[6 * n]; var extraEqCount = 0; foreach (var mpcElm in target.MpcElements) { if (mpcElm.AppliesForLoadCase(loadCase)) { extraEqCount += mpcElm.GetExtraEquationsCount(); } } extraEqCount += boundaryConditions.RowCount; var allEqsCrd = new CoordinateStorage <double>(extraEqCount, n * 6 + 1, 1);//rows: extra eqs, cols: 6*n+1 (+1 is for right hand side) foreach (var mpcElm in target.MpcElements) { if (mpcElm.AppliesForLoadCase(loadCase)) { var extras = mpcElm.GetExtraEquations(); extras.EnumerateMembers((row, col, val) => { allEqsCrd.At(row + lastRow, col, val); }); lastRow += extras.RowCount; } } { boundaryConditions.EnumerateMembers((row, col, val) => { allEqsCrd.At(row + lastRow, col, val); }); lastRow += boundaryConditions.RowCount; } var allEqs = allEqsCrd.ToCCs(); #endregion #region comment /* #region step 2 * //step 2: create adjacency matrix of variables * * //step 2-1: find nonzero pattern * var allEqsNonzeroPattern = allEqs.Clone(); * * for (var i = 0; i < allEqsNonzeroPattern.Values.Length; i++) * allEqsNonzeroPattern.Values[i] = 1; * * //https://math.stackexchange.com/questions/2340450/extract-independent-sub-systems-from-a-bigger-linear-eq-system * var tmp = allEqsNonzeroPattern.Transpose(); * * var variableAdj = tmp.Multiply(allEqsNonzeroPattern); #endregion * #region step 3 * //extract parts * var parts = EnumerateGraphParts(variableAdj); * #endregion * #region step 4 * { * * allEqs.EnumerateColumns((colNum, vals) => * { * if (vals.Count == 0) * Console.WriteLine("Col {0} have {1} nonzeros", colNum, vals.Count); * }); * * var order = ColumnOrdering.MinimumDegreeAtPlusA; * * // Partial pivoting tolerance (0.0 to 1.0) * double tolerance = 1.0; * * var lu = CSparse.Double.Factorization.SparseLU.Create(allEqs, order, tolerance); * * } * #endregion */ #endregion rrefFinder.CalculateRref(allEqs); var q = AMD.Generate(allEqs, ColumnOrdering.MinimumDegreeAtA); var s = new SymbolicFactorization() { q = q }; var qr = CSparse.Double.Factorization.SparseQR.Create(allEqs, ColumnOrdering.MinimumDegreeAtA); var r = ((CCS)ReflectionUtils.GetFactorR(qr, "R")); //var q = ((CCS)ReflectionUtils.GetFactorR(qr, "Q")); //var s = ((SymbolicFactorization)ReflectionUtils.GetFactorR(qr, "S")); var idependents = new bool[allEqs.RowCount]; var rd = allEqs.ToDenseMatrix(); r.EnumerateMembers((row, col, val) => { if (row == col) { if (Math.Abs(val) < 1e-6) { return; } } idependents[row] = true; } ); //var t=qr. throw new NotImplementedException(); //return buf.ToCCs(); }