private double[] makeInitialGuess(IList <double> b) { var initialGuess = new double[NumRows]; var initGuessValue = StarMath.SumAllElements(b) / SumAllElements(); for (var i = 0; i < NumRows; i++) { initialGuess[i] = initGuessValue; } return(initialGuess); }
private bool isGaussSeidelAppropriate(IList <double> b, out List <int>[] potentialDiagonals, ref IList <double> initialGuess) { potentialDiagonals = null; if (NumRows < StarMath.GaussSeidelMinimumMatrixSize) { return(false); } if (initialGuess == null) { initialGuess = makeInitialGuess(b); } var error = StarMath.norm1(StarMath.subtract(b, multiply(initialGuess))) / b.norm1(); if (error > StarMath.MaxErrorForUsingGaussSeidel) { return(false); } return(findPotentialDiagonals(out potentialDiagonals, StarMath.GaussSeidelDiagonalDominanceRatio)); }
private int[] reorderMatrixForDiagonalDominance(int length, List <int>[] potentialIndices) { var popularity = new int[length]; for (var i = 0; i < length; i++) { popularity[i] = potentialIndices.Count(r => r.Contains(i)); } var orderToAddress = StarMath.makeLinearProgression(length, 1).OrderBy(x => popularity[x]).ToList(); var stack = new Stack <int[]>(); var seed = new int[length]; int[] candidate; var solutionFound = false; for (var i = 0; i < length; i++) { seed[i] = -1; } stack.Push(seed); do { candidate = stack.Pop(); var numToFill = candidate.Count(x => x == -1); if (numToFill == 0) { solutionFound = true; } else { var colIndex = orderToAddress[length - numToFill]; var possibleIndicesForRow = new List <int>(); for (var oldRowIndex = 0; oldRowIndex < length; oldRowIndex++) { if (!potentialIndices[oldRowIndex].Contains(colIndex)) { continue; } if (candidate.Contains(oldRowIndex)) { continue; } possibleIndicesForRow.Add(oldRowIndex); } if (possibleIndicesForRow.Count == 1) { candidate[colIndex] = possibleIndicesForRow[0]; stack.Push(candidate); } else { possibleIndicesForRow = possibleIndicesForRow.OrderBy(r => Math.Abs(this[r, colIndex])).ToList(); foreach (var i in possibleIndicesForRow) { var child = (int[])candidate.Clone(); child[colIndex] = i; stack.Push(child); } } } } while (!solutionFound && stack.Any()); if (solutionFound) { return(candidate); } return(null); }
public double[] SolveIteratively(IList <double> b, IList <double> initialGuess = null, List <int>[] potentialDiagonals = null) { double[] x; if (initialGuess == null) { x = makeInitialGuess(b); } else { x = initialGuess.ToArray(); } if (potentialDiagonals == null && !findPotentialDiagonals(out potentialDiagonals, StarMath.GaussSeidelDiagonalDominanceRatio)) { return(null); } var order = Enumerable.Range(0, NumRows).ToArray(); if (!order.All(rowIndex => potentialDiagonals[rowIndex].Contains(rowIndex))) { order = reorderMatrixForDiagonalDominance(NumRows, potentialDiagonals); } if (order == null) { return(null); } var bNorm1 = StarMath.norm1(b); var error = StarMath.norm1(StarMath.subtract(b, multiply(x))) / bNorm1; var success = error <= StarMath.GaussSeidelMaxError; var xWentNaN = false; var iteration = NumRows * StarMath.GaussSeidelMaxIterationFactor; while (!xWentNaN && !success && iteration-- > 0) { for (var i = 0; i < NumRows; i++) { var rowI = order[i]; var diagCell = Diagonals[i]; var adjust = b[rowI]; var cell = RowFirsts[rowI]; do { if (cell != diagCell) { adjust -= cell.Value * x[cell.ColIndex]; } cell = cell.Right; } while (cell != null); x[rowI] = (1 - StarMath.GaussSeidelRelaxationOmega) * x[rowI] + StarMath.GaussSeidelRelaxationOmega * adjust / this[rowI, i]; } xWentNaN = x.Any(double.IsNaN); error = StarMath.norm1(StarMath.subtract(b, multiply(x))) / bNorm1; success = error <= StarMath.GaussSeidelMaxError; } if (!success) { return(null); } return(x); }