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); }
// 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); }