/// <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> /// Compute the numeric LDL' factorization of PAP'. /// </summary> /// <param name="A">The matrix, A.</param> /// <param name="S">The symobolic factorization.</param> /// <param name="D">The diagonals of LDL.</param> /// <param name="L">The lower triangular matrix.</param> /// <exception cref="System.Exception">Diagonal element is zero.</exception> /// <exception cref="Exception">Diagonal element is zero.</exception> internal static void FactorizeLDL(CompressedColumnStorage A, SymbolicFactorization S, out double[] D, out CompressedColumnStorage L) { var n = A.ncols; var aColPointers = A.ColumnPointers; var aRowIndices = A.RowIndices; var aValues = A.Values; var parent = S.ParentIndices; var P = S.PermutationVector; var Pinv = S.InversePermute; D = new double[n]; L = new CompressedColumnStorage(n, n, S.ColumnPointers[n]); Array.Copy(S.ColumnPointers, L.ColumnPointers, n + 1); var lColPointers = L.ColumnPointers; var lRowIndices = L.RowIndices; var lValues = L.Values; // Workspace var y = new double[n]; var pattern = new int[n]; var flag = new int[n]; var lnz = new int[n]; for (var k = 0; k < n; k++) { // compute nonzero Pattern of kth row of L, in topological order y[k] = 0.0; // Y(0:k) is now all zero var top = n; flag[k] = k; // mark node k as visited lnz[k] = 0; // count of nonzeros in column k of L var kk = P != null ? P[k] : k; var p2 = aColPointers[kk + 1]; for (var p = aColPointers[kk]; p < p2; p++) { var i = Pinv != null ? Pinv[aRowIndices[p]] : aRowIndices[p]; // get A(i,k) if (i <= k) { y[i] += aValues[p]; // scatter A(i,k) into Y (sum duplicates) int len; for (len = 0; flag[i] != k; i = parent[i]) { pattern[len++] = i; // L(k,i) is nonzero flag[i] = k; // mark i as visited } while (len > 0) { pattern[--top] = pattern[--len]; } } } // compute numerical values kth row of L (a sparse triangular solve) D[k] = y[k]; // get D(k,k) and clear Y(k) y[k] = 0.0; for (; top < n; top++) { var i = pattern[top]; // Pattern [top:n-1] is pattern of L(:,k) var yi = y[i]; y[i] = 0.0; p2 = lColPointers[i] + lnz[i]; int p; for (p = lColPointers[i]; p < p2; p++) { y[lRowIndices[p]] -= lValues[p] * yi; } var l_ki = yi / D[i]; D[k] -= l_ki * yi; lRowIndices[p] = k; // store L(k,i) in column form of L lValues[p] = l_ki; lnz[i]++; // increment count of nonzeros in col i } if (D[k] == 0.0) // failure, D(k,k) is zero { throw new Exception("Diagonal element is zero."); } } }