Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }