Exemplo n.º 1
0
        // 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, Intracommunicator comm)
        {
            // check sanity. rank 0 only
            if (comm.Rank == 0 && (!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, communication = 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 = 0; Matrix L = null, U = null, L_1;

            if (comm.Rank == 0)
            {
                size = A.Height;
                Matrix.Decompose(A, out L, out U);
            }
            bm2.pause();
            sequential += bm2.getElapsedSeconds();

            bm2.start();
            comm.Broadcast(ref size, 0);
            comm.Broadcast(ref U, 0);
            comm.Broadcast(ref b, 0);
            bm2.pause();
            communication += bm2.getElapsedSeconds();

            // Inverse matrix L*
            comm.Barrier();
            L_1 = MatrixParallel.Inverse(L, comm, ref sequential, ref parallel, ref communication);

            // 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

            // split T & C into groups of rows, each for one slave, according to the nature of this algorithm
            // each slave will have one piece of T & one piece of C stored locally. the rest of T & C is not needed
            // there might be cases where jobs > slaves, so some might get no job at all
            // Changes: only split L_1. Slaves will calculate T & C (pieces) themselves
            bm2.start();
            Matrix jobDistro = Utils.splitJob(size, comm.Size);
            int    startRow = 0, endRow = 0, myJobSize = (int)jobDistro[0, comm.Rank];

            for (int p = 0; p < comm.Size; p++)
            {
                if (p != comm.Rank)
                {
                    startRow += (int)jobDistro[0, p];
                }
                else
                {
                    endRow = startRow + (int)jobDistro[0, p] - 1;
                    break;
                }
            }
            Matrix[] L_1Ps = new Matrix[comm.Size];
            if (comm.Rank == 0)
            {
                int slaveStart = 0;
                for (int p = 0; p < comm.Size; p++)
                {
                    L_1Ps[p]    = Matrix.extractRows(L_1, slaveStart, slaveStart + (int)jobDistro[0, p] - 1);
                    slaveStart += (int)jobDistro[0, p];
                }
            }
            bm2.pause();
            sequential += bm2.getElapsedSeconds();

            bm2.start();
            Matrix L_1P = comm.Scatter(L_1Ps, 0);

            bm2.pause();
            communication += bm2.getElapsedSeconds();
            bm2.start();
            Matrix T = -L_1P * U; Matrix C = L_1P * b;

            bm2.pause();
            parallel += bm2.getElapsedSeconds();

            // the actual iteration
            // if it still doesn't converge after this many loops, assume it won't converge and give up
            Boolean converge  = false;
            int     loopLimit = 100;

            x = Matrix.zeroLike(b); // at step k
            for (loops = 0; loops < loopLimit; loops++)
            {
                bm3.start();
                // (re-)distributing x vector. Must be done every single loop
                // this loop needs x from the previous loop
                comm.Broadcast(ref x, 0);
                bm3.pause();
                communication += bm3.getElapsedSeconds();

                // calculation step
                bm3.start();
                comm.Barrier();
                Matrix new_x = T * x + C;

                // check convergence
                converge = Matrix.SomeClose(new_x, x, 1e-15, startRow);

                // collect result x
                comm.Barrier();
                x = comm.Reduce(new_x, Matrix.Concatenate, 0);

                // collect convergence. consider converged if ALL slaves claim so
                converge = comm.Reduce(converge, bothTrue, 0);
                comm.Broadcast(ref converge, 0); // make sure EVERYONE breaks/coninues
                bm3.pause();
                parallel += bm3.getElapsedSeconds();
                if (converge)
                {
                    loops++;
                    break;
                }
            }

            bm2.start();
            // round the result slightly
            err = null;
            if (comm.Rank == 0)
            {
                x.Round(1e-14);
                err = A * x - b;
                err.Round(1e-14);
            }
            bm2.pause();
            sequential += bm2.getElapsedSeconds();

            bm.pause();
            if (showBenchmark)
            {
                Console.WriteLine("Sequential part took " + sequential + " secs.");
                Console.WriteLine("Parallel part took " + parallel + " secs.");
                Console.WriteLine("Communication took " + communication + " secs.");
                Console.WriteLine("Total: " + bm.getResult() + " (" + bm.getElapsedSeconds() + " secs). Seq + Parallel: " + (sequential + parallel));
            }

            return(converge);
        }
Exemplo n.º 2
0
        static void Main(string[] _args)
        {
            using (new MPI.Environment(ref _args))
            {
                Intracommunicator comm = Communicator.world;
                if (comm.Rank == 0)
                {
                    // program for rank 0
                    string programName   = "Gauss-Seidel Linear System of Equations Solver";
                    string programVer    = "1.0 (parallel)";
                    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.WriteLine("Exiting...");
                        MPI.Environment.Abort(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  = "";

                    Console.WriteLine("Now working with " + (comm.Size).ToString() + " process(es)...\n");
                    Gauss_Seidel_Parallel.showBenchmark = showBenchmark;

                    bm.start();
                    for (int j = 0; j < equCounts; j++)
                    {
                        Console.Write("Solving system #" + (j + 1).ToString() + "... ");
                        Matrix x, err;
                        int    loops = 0;
                        for (int r = 1; r < comm.Size; r++)
                        {
                            comm.Send("start", r, 0);
                        }
                        bool converge = Gauss_Seidel_Parallel.solve(As[j], bs[j], out x, out err, out loops, comm);
                        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
                        if (outputFile.Length > 0)
                        {
                            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. Exiting...");

                    // tell other ranks to exit
                    for (int r = 1; r < comm.Size; r++)
                    {
                        comm.Send("exit", r, 0);
                    }
                }
                else
                {
                    // program for all other ranks
                    // wait for command (start (solveSub), exit)
                    string command = null;
                    do
                    {
                        command = comm.Receive <string>(0, 0); // receive command from rank 0
                        if (command == "start")
                        {
                            Matrix A = null, b = null, x, err; int loops;
                            Gauss_Seidel_Parallel.solve(A, b, out x, out err, out loops, comm);
                        }
                    } while (command != "exit");
                }
            }
        }
Exemplo n.º 3
0
        static void Main(string[] _args)
        {
            using (new MPI.Environment(ref _args))
            {
                Intracommunicator comm = Communicator.world;
                if (comm.Rank == 0)
                {
                    // program for rank 0
                    string programName   = "Gauss-Seidel Linear System of Equations Solver";
                    string programVer    = "1.0 (test)";
                    string programAuthor = "Quy N.H.";
                    Console.WriteLine(programName + " v" + programVer + " by " + programAuthor + "\n");

                    // check number of processes in this communicator
                    if (comm.Size < 2)
                    {
                        Console.WriteLine("Please run at least 2 processes of me.");
                        Console.WriteLine("Exiting...");
                        MPI.Environment.Abort(1);
                    }

                    string inputFile = "", outputFile = "";
                    bool   benchmarkMode = true, showEquation = false, generateInput = false;
                    int    benchmarkSize = 100;
                    int    benchmarkTime = 100;

                    // get input(s)
                    List <Matrix> As = new List <Matrix>(), bs = new List <Matrix>(), sols = new List <Matrix>(), xs_p = new List <Matrix>(), xs_s = 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));
                        }
                    }
                    else if (inputFile.Length > 0)
                    {
                        // parse input
                        string inputArray = File.ReadAllText(inputFile);
                        Utils.parseInput(inputArray, out As, out bs, out sols);
                    }
                    else
                    {
                        // yell at user
                        Console.WriteLine("Give me some inputs!");
                        Console.WriteLine("Exiting...");
                        MPI.Environment.Abort(1);
                    }

                    // do the calculation
                    List <bool>   converges_p = new List <bool>(), converges_s = new List <bool>();
                    List <int>    loopses_p = new List <int>(), loopses_s = new List <int>();
                    List <Matrix> errs_p = new List <Matrix>(), errs_s = new List <Matrix>();

                    int       equCounts = As.Count;
                    benchmark bm       = new benchmark();
                    string    bmResult = "";

                    bm.start();
                    for (int j = 0; j < equCounts; j++)
                    {
                        Console.Write("Solving system #" + (j + 1).ToString() + "... ");
                        Matrix x, err;
                        int    loops = 0;
                        for (int r = 1; r < comm.Size; r++)
                        {
                            comm.Send("start", r, 0);
                        }
                        Console.Write("Parallel... ");
                        bool converge = Gauss_Seidel_Parallel.solve(As[j], bs[j], out x, out err, out loops, comm);
                        xs_p.Add(x);
                        loopses_p.Add(loops);
                        converges_p.Add(converge);
                        errs_p.Add(err);
                        Console.Write("Serial... ");
                        converge = Gauss_Seidel.solve(As[j], bs[j], out x, out err, out loops);
                        xs_s.Add(x);
                        loopses_s.Add(loops);
                        converges_s.Add(converge);
                        errs_s.Add(err);
                        Console.WriteLine("Done.");
                    }
                    bmResult = bm.getResult();

                    // write output
                    Console.WriteLine("\nVerifying results:\n");
                    int total = 0, passed = 0, failed = 0;
                    for (int j = 0; j < equCounts; j++)
                    {
                        Matrix x_p = xs_p[j], err_p = errs_p[j], x_s = xs_s[j], err_s = errs_s[j];
                        int    loops_p = loopses_p[j], loops_s = loopses_s[j];
                        bool   converge_p = converges_p[j], converge_s = converges_s[j];
                        bool   c = false, l = false, s = false;
                        Console.Write("System #" + (j + 1).ToString() + ": ");
                        if (s = x_p.ToString() == x_s.ToString())
                        {
                            Console.Write("solutions match, ");
                        }
                        else
                        {
                            Console.Write("solutions DON'T match, ");
                        }
                        if (l = loops_p == loops_s)
                        {
                            Console.Write("loop count matches, ");
                        }
                        else
                        {
                            Console.Write("loop count DOESN'T match, ");
                        }
                        if (c = converge_p == converge_s)
                        {
                            Console.Write("convergence matches. ");
                        }
                        else
                        {
                            Console.Write("convergence DOESN'T match. ");
                        }
                        if (s && c && l)
                        {
                            Console.WriteLine("Passed!");
                            passed += 1;
                        }
                        else
                        {
                            Console.WriteLine("Failed!");
                            failed += 1;
                        }
                        total += 1;
                    }

                    Console.WriteLine("\nTotal: " + total.ToString() + ". Passed: " + passed.ToString() + ". Failed: " + failed.ToString());

                    Console.WriteLine("\nElapsed time: " + bmResult + " (" + string.Format("{0:0.###}", bm.getElapsedSeconds() / equCounts) + " sec / equation).");

                    Console.WriteLine("Done. Exiting...");

                    // tell other ranks to exit
                    for (int r = 1; r < comm.Size; r++)
                    {
                        comm.Send("exit", r, 0);
                    }
                }
                else
                {
                    // program for all other ranks
                    // wait for command (start (solveSub), exit)
                    string command = null;
                    do
                    {
                        command = comm.Receive <string>(0, 0); // receive command from rank 0
                        if (command == "start")
                        {
                            Matrix A = null, b = null, x, err; int loops;
                            Gauss_Seidel_Parallel.solve(A, b, out x, out err, out loops, comm);
                        }
                    } while (command != "exit");
                }
            }
        }