/// <summary> /// Solves the system of equations analytically. /// </summary> /// <param name="b">The b.</param> /// <param name="IsASymmetric">if set to <c>true</c> [a is symmetric].</param> /// <param name="potentialDiagonals">The potential diagonals.</param> /// <returns>System.Double[].</returns> public IList <double> SolveAnalytically(IList <double> b, bool IsASymmetric = false) { if (IsASymmetric) { if (ValuesChanged || TopologyChanged) { MatrixInCCS = convertToCCS(this); } if (TopologyChanged) { symbolicFactorizationMat = CSparse.SymbolicAnalysisLDL(MatrixInCCS); } if (ValuesChanged || TopologyChanged) { CSparse.FactorizeLDL(MatrixInCCS, symbolicFactorizationMat, out D, out FactorizationMatrix); } TopologyChanged = ValuesChanged = false; return(CSparse.SolveLDL(b, FactorizationMatrix, D, symbolicFactorizationMat.InversePermute)); } else { var ccs = convertToCCS(this); var columnPermutation = ApproximateMinimumDegree.Generate( new SymbolicColumnStorage(ccs), NumCols); CompressedColumnStorage L, U; int[] pinv; // Numeric LU factorization CSparse.FactorizeLU(ccs, columnPermutation, out L, out U, out pinv); var x = CSparse.ApplyInverse(pinv, b, NumCols); // x = b(p) CSparse.SolveLower(L, x); // x = L\x. CSparse.SolveUpper(U, x); // x = U\x. return(CSparse.ApplyInverse(columnPermutation, x, NumCols)); // b(q) = x } }
/// <summary> /// Solve Gx=b(:,k), where G is either upper (lo=false) or lower (lo=true) /// triangular. /// </summary> /// <param name="G">lower or upper triangular matrix in column-compressed form</param> /// <param name="B">right hand side, b=B(:,k)</param> /// <param name="k">use kth column of B as right hand side</param> /// <param name="xi">size 2*n, nonzero pattern of x in xi[top..n-1]</param> /// <param name="x">size n, x in x[xi[top..n-1]]</param> /// <param name="pinv">mapping of rows to columns of G, ignored if null</param> /// <param name="lo">true if lower triangular, false if upper</param> /// <returns>top, -1 in error</returns> private static int SolveSp(CompressedColumnStorage G, CompressedColumnStorage B, int k, int[] xi, double[] x, int[] pinv, bool lo) { if (xi == null || x == null) { return(-1); } var gColPointers = G.ColumnPointers; var gRowIndices = G.RowIndices; var gValues = G.Values; var bColPointers = B.ColumnPointers; var bRowIndices = B.RowIndices; var bValues = B.Values; var n = G.ncols; // xi[top..n-1]=Reach(B(:,k)) var top = ApproximateMinimumDegree.Reach(gColPointers, gRowIndices, bColPointers, bRowIndices, n, k, xi, pinv); for (var i = top; i < n; i++) { x[xi[i]] = 0; // clear x } for (var i = bColPointers[k]; i < bColPointers[k + 1]; i++) { x[bRowIndices[i]] = bValues[i]; // scatter B } for (var px = top; px < n; px++) { var j = xi[px]; var J = pinv != null ? pinv[j] : j; if (J < 0) { continue; // column J is empty } x[j] /= gValues[lo ? gColPointers[J] : gColPointers[J + 1] - 1]; // x(j) /= G(j,j) var p = lo ? gColPointers[J] + 1 : gColPointers[J]; // lo: L(j,j) 1st entry var q = lo ? gColPointers[J + 1] : gColPointers[J + 1] - 1; for (; p < q; p++) { x[gRowIndices[p]] -= gValues[p] * x[j]; // x(i) -= G(i,j) * x(j) } } // Return top of stack. return(top); }
/// <summary> /// Symbolics the analysis LDL. /// </summary> /// <param name="A">a.</param> /// <returns>SymbolicFactorization.</returns> internal static SymbolicFactorization SymbolicAnalysisLDL(CompressedColumnStorage A) { var n = A.ncols; var aColPointers = A.ColumnPointers; var aRowIndices = A.RowIndices; // P = amd(A+A') or natural var permute = ApproximateMinimumDegree.Generate(A); var invPermute = Invert(permute); // 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]; for (var 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 var kk = permute != null ? permute[k] : k; var p2 = aColPointers[kk + 1]; int p; for (p = aColPointers[kk]; p < p2; p++) { // A(i,k) is nonzero (original or permuted A) var i = invPermute != null ? invPermute[aRowIndices[p]] : aRowIndices[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 (var k = 0; k < n; k++) { lp[k + 1] = lp[k] + lnz[k]; } return(new SymbolicFactorization { ParentIndices = parent, ColumnPointers = lp, PermutationVector = permute, InversePermute = invPermute }); }