public static Matrix InverseAlt(Matrix matrix, ref Double timeS, ref double timeP) { if (!matrix.isSquare) { Exception e = new Exception("Matrix must be square!"); throw e; } benchmark bm = new benchmark(); bm.start(); int n = matrix.dim1; Matrix result = Matrix.zeroLike(matrix); int[] perm; int toggle; Matrix lum = LUPDecompose(matrix, out perm, out toggle); if (lum == null) { return(Matrix.zeroLike(matrix)); //throw new Exception("Unable to compute inverse"); } Double det = Determinant(lum, perm, toggle); if (det == 0) // not invertible { // still return for the sake of simplicity // Zero matrix * any matrix = zero matrix // so it's never a valid answer return(Matrix.zeroLike(matrix)); } bm.pause(); timeS += bm.getElapsedSeconds(); bm.start(); double[] b = new double[n]; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (i == perm[j]) { b[j] = 1.0; } else { b[j] = 0.0; } } double[] x = HelperSolve(lum, b); for (int j = 0; j < n; ++j) { result[j, i] = x[j]; } } timeP += bm.getElapsedSeconds(); return(result); }
static void Main(string[] _args) { string programName = "Gauss-Seidel Linear System of Equations Solver"; string programVer = "1.0 (sequential)"; string programAuthor = "Quy N.H."; Console.WriteLine(programName + " v" + programVer + " by " + programAuthor + "\n"); bool testing = false; string[] args = _args; if (testing) { args = "-o output.txt -b 200 -t 10".Split(new char[] { ' ' }); } // parse args string inputFile = "", outputFile = ""; bool benchmarkMode = false, showEquation = false, generateInput = false, showBenchmark = false; int benchmarkSize = 3; int benchmarkTime = 1; int i = 0; while (i < args.Length) { string arg = args[i]; if (arg.StartsWith("--")) { arg = arg.Substring(2); switch (arg) { case "input": if (i + 1 < args.Length) { inputFile = args[i + 1]; } break; case "output": if (i + 1 < args.Length) { outputFile = args[i + 1]; } break; case "show-equation": showEquation = true; break; case "show-benchmark": showBenchmark = true; break; case "generate-input": generateInput = true; break; case "benchmark": if (i + 1 < args.Length && int.TryParse(args[i + 1], out benchmarkSize)) { benchmarkMode = true; i++; } ; break; case "times": if (i + 1 < args.Length && int.TryParse(args[i + 1], out benchmarkTime)) { benchmarkMode = true; i++; } ; break; } } else if (arg.StartsWith("-")) { arg = arg.Substring(1); switch (arg) { case "i": if (i + 1 < args.Length) { inputFile = args[i + 1]; } break; case "o": if (i + 1 < args.Length) { outputFile = args[i + 1]; } break; case "e": showEquation = true; break; case "m": showBenchmark = true; break; case "g": generateInput = true; break; case "b": if (i + 1 < args.Length && int.TryParse(args[i + 1], out benchmarkSize)) { benchmarkMode = true; i++; } ; break; case "t": if (i + 1 < args.Length && int.TryParse(args[i + 1], out benchmarkTime)) { benchmarkMode = true; i++; } ; break; } } i++; } // get input(s) List <Matrix> As = new List <Matrix>(), bs = new List <Matrix>(), sols = new List <Matrix>(), xs = new List <Matrix>(); if (benchmarkMode) { // generate input for (int j = 0; j < benchmarkTime; j++) { As.Add(Matrix.generateDiagonallyDominantMatrix(benchmarkSize, true, -100, 100)); bs.Add(Matrix.random(benchmarkSize, 1, -100, 100, true)); } Console.WriteLine("Generated " + benchmarkTime.ToString() + " random system(s) to solve."); } else if (inputFile.Length > 0 && File.Exists(inputFile)) { // parse input string inputArray = File.ReadAllText(inputFile); Utils.parseInput(inputArray, out As, out bs, out sols); Console.WriteLine("Got " + As.Count.ToString() + " system(s) from input file."); } else { // yell at user Console.WriteLine("Give me some inputs!"); Console.ReadKey(); Environment.Exit(1); } // do the calculation List <bool> converges = new List <bool>(); List <int> loopses = new List <int>(); List <Matrix> errs = new List <Matrix>(); int equCounts = As.Count; benchmark bm = new benchmark(); string bmResult = ""; Gauss_Seidel.showBenchmark = showBenchmark; bm.start(); for (int j = 0; j < equCounts; j++) { Console.Write("Solving system #" + (j + 1).ToString() + "... "); Matrix x, err; int loops = 0; bool converge = Gauss_Seidel.solve(As[j], bs[j], out x, out err, out loops); xs.Add(x); loopses.Add(loops); converges.Add(converge); errs.Add(err); Console.WriteLine("Done."); } bmResult = bm.getResult(); // write output if (!generateInput) { // show the result as usual writeOutput(outputFile, "\n"); for (int j = 0; j < equCounts; j++) { Matrix x = xs[j], err = errs[j]; int loops = loopses[j]; bool converge = converges[j]; string strResult = ""; if (showEquation) { strResult += "\nEquation:\n" + Utils.writeEquation(As[j], bs[j]); } strResult += "\nNo. equations: " + x.Height.ToString(); strResult += "\nSolution: " + Matrix.Transpose(x).ToString(1e-14); strResult += "\nErrors: " + Matrix.Transpose(err).ToString(1e-14); strResult += "\nMean absolute error: " + string.Format("{0:0.##############}", Matrix.Abs(err).avgValue); strResult += "\nConverged: " + converge.ToString(); strResult += "\nLoops: " + loops.ToString(); writeOutput(outputFile, strResult); } writeOutput(outputFile, "\nElapsed time: " + bmResult + " (" + string.Format("{0:0.###}", bm.getElapsedSeconds() / equCounts) + " sec / equation)."); writeOutput(outputFile, ""); } else { // create a valid input file for (int j = 0; j < equCounts; j++) { Matrix x = xs[j], err = errs[j]; int loops = loopses[j]; bool converge = converges[j]; string strResult = "\n-----------\n"; strResult += x.Height.ToString(); strResult += "\n"; strResult += As[j].ToString(); strResult += "\n"; strResult += Matrix.Transpose(bs[j]).ToString(); strResult += "\n"; strResult += Matrix.Transpose(x).ToString(1e-14); strResult += "\n"; writeOutput(outputFile, strResult); } writeOutput("", "\nElapsed time: " + bmResult + " (" + string.Format("{0:0.###}", bm.getElapsedSeconds() / equCounts) + " sec / equation)."); writeOutput("", ""); } Console.WriteLine("Done. Press a key to exit..."); Console.ReadKey(); }
// return true if it converges. Output: solution matrix, errors, loops it took public static Boolean solve(Matrix A, Matrix b, out Matrix x, out Matrix err, out int loops) { // check sanity if (!A.isSquare || !b.isColumn || (A.Height != b.Height)) { Exception e = new Exception("Matrix A must be square! Matrix b must be a column matrix with the same height as matrix A!"); throw e; } // follow samples in Wikipedia step by step https://en.wikipedia.org/wiki/Gauss%E2%80%93Seidel_method benchmark bm = new benchmark(), bm2 = new benchmark(), bm3 = new benchmark(); double sequential = 0, parallel = 0; bm.start(); bm2.start(); // decompose A into the sum of a lower triangular component L* and a strict upper triangular component U int size = A.Height; Matrix L, U; Matrix.Decompose(A, out L, out U); sequential += bm2.getElapsedSeconds(); // Inverse matrix L* Matrix L_1 = Matrix.InverseAlt(L, ref sequential, ref parallel); // Main iteration: x (at step k+1) = T * x (at step k) + C // where T = - (inverse of L*) * U, and C = (inverse of L*) * b bm2.start(); // init necessary variables x = Matrix.zeroLike(b); // at step k Matrix new_x; // at step k + 1 sequential += bm2.getElapsedSeconds(); bm2.start(); Matrix T = -L_1 * U; Matrix C = L_1 * b; parallel += bm2.getElapsedSeconds(); // Console.WriteLine(T.ToString(0.00001)); // Console.WriteLine(C.ToString(0.00001)); // the actual iteration // if it still doesn't converge after this many loops, assume it won't converge and give up bm2.start(); loops = 0; Boolean converge = false; int loopLimit = 100; sequential += bm2.getElapsedSeconds(); bm2.start(); for (; loops < loopLimit; loops++) { new_x = T * x + C; // yup, only one line // Console.WriteLine("Loop #" + loops); // Console.WriteLine(new_x.ToString(0.00001)); // consider it's converged if it changes less than threshold (1e-15) if (converge = Matrix.AllClose(new_x, x, 1e-15)) { x = new_x; loops++; break; } // save result x = new_x; } parallel += bm2.getElapsedSeconds(); bm2.start(); // round the result slightly x.Round(1e-14); err = A * x - b; err.Round(1e-14); sequential += bm2.getElapsedSeconds(); bm.pause(); if (showBenchmark) { Console.WriteLine("Sequential part took " + sequential + " secs."); Console.WriteLine("Parallel part took " + parallel + " secs."); Console.WriteLine("Total: " + bm.getResult() + " (" + bm.getElapsedSeconds() + " secs). Seq + Parallel: " + (sequential + parallel)); } return(converge); }