Exemplo n.º 1
0
 public void AllMethodsTest()
 {
     double          epsilon            = Math.Pow(10, -10);
     int             maxIterations      = 10000;
     GaussSeidel     gaussSeidel        = new GaussSeidel(_generatorTotalCases, _generatorMatrix, _generatorVector, maxIterations, epsilon);
     PartialGauss    sparsePartialGauss = new PartialGauss(_generatorTotalCases, _generatorMatrix, _generatorVector, true);
     PartialGauss    partialGauss       = new PartialGauss(_generatorTotalCases, _generatorMatrix, _generatorVector, false);
     SparseLUSolver  sparseLUSolver     = new SparseLUSolver(_generatorTotalCases, _generatorMatrix, _generatorVector);
     OwnSparseSolver ownSparseSolver    = new OwnSparseSolver(_ownSparseGenerator.GenerateOwnSparseMatrix(), _generatorVector, maxIterations, epsilon);
 }
Exemplo n.º 2
0
        static void Main(string[] args)
        {

            GaussSeidel solver = new GaussSeidel(1.0);

            double[] M = new double[9];
            M[0] = 12.0;
            M[1] = 3.0;
            M[2] = -5.0;
            M[3] = 1.0;
            M[4] = 5.0;
            M[5] = 3.0;
            M[6] = 3.0;
            M[7] = 7.0;
            M[8] = 13.0;
            

            double[] B = new double[3];
            B[0] = 1.0;
            B[1] = 28.0;
            B[2] = 76.0;
            
            double[] startX = new double[3];
            startX[0] = 1.0;
            startX[0] = 0.0;
            startX[0] = 1.0;

            LinearProblemProperties linearProblemProperties = new LinearProblemProperties(
                M,
                B,
                startX,
                3);

            double[] X = new double[3];

            NonLinearConjugateGradient nonLinearConjugateGradient = new NonLinearConjugateGradient(3);

            double[] X1 = nonLinearConjugateGradient.Solve(linearProblemProperties);

            for (int i= 0;i<4;i++)
                X = solver.Solve(linearProblemProperties);

            double[] out0 = nonLinearConjugateGradient.CalculateError(linearProblemProperties.M, linearProblemProperties.B, X1);
           double[] out1 = nonLinearConjugateGradient.CalculateError(linearProblemProperties.M, linearProblemProperties.B, X);

            Console.ReadLine();


        }
Exemplo n.º 3
0
        private void button1_Click(object sender, EventArgs e)
        {
            if (Operaciones.Text != "")
            {
                Operaciones.Clear();
                Operaciones.Focus();
            }

            GSeidel = new GaussSeidel();
            int cantidadElementos = int.Parse(textBox1.Text);

            GSeidel.cantidadElementos = int.Parse(textBox1.Text);
            cantidadElementos         = GSeidel.cantidadElementos;

            int pointx = 70;
            int pointy = 70;

            panel2.Controls.Clear();

            for (int j = 0; j < int.Parse(textBox1.Text); j++)
            {
                for (int i = 0; i < int.Parse(textBox1.Text); i++)
                {
                    TextBox text   = new TextBox();
                    string  nombre = "txt" + j + i;
                    text.Name      = nombre;
                    text.BackColor = Color.PaleVioletRed;
                    text.Location  = new Point(pointx, pointy);
                    text.Size      = new Size(40, 40);
                    panel2.Controls.Add(text);
                    pointy += 40;
                }

                pointx += 70;
                pointy  = 70;
            }

            /* for (int u = 0; u < cantidadElementos; u++)
             * {
             *   TextBox text = new TextBox();
             *   string nombre = "txt" + u;
             *   text.Name = nombre;
             *   text.BackColor = Color.Violet;
             *   text.Location = new Point(pointx, pointy);
             *   text.Size = new Size(40, 40);
             *   panel2.Controls.Add(text);
             *   pointy += 40;
             * }*/
        }
Exemplo n.º 4
0
        static void Main(string[] args)
        {
            GaussSeidel solver = new GaussSeidel(1.0);

            double[] M = new double[9];
            M[0] = 12.0;
            M[1] = 3.0;
            M[2] = -5.0;
            M[3] = 1.0;
            M[4] = 5.0;
            M[5] = 3.0;
            M[6] = 3.0;
            M[7] = 7.0;
            M[8] = 13.0;


            double[] B = new double[3];
            B[0] = 1.0;
            B[1] = 28.0;
            B[2] = 76.0;

            double[] startX = new double[3];
            startX[0] = 1.0;
            startX[0] = 0.0;
            startX[0] = 1.0;

            LinearProblemProperties linearProblemProperties = new LinearProblemProperties(
                M,
                B,
                startX,
                3);

            double[] X = new double[3];

            NonLinearConjugateGradient nonLinearConjugateGradient = new NonLinearConjugateGradient(3);

            double[] X1 = nonLinearConjugateGradient.Solve(linearProblemProperties);

            for (int i = 0; i < 4; i++)
            {
                X = solver.Solve(linearProblemProperties);
            }

            double[] out0 = nonLinearConjugateGradient.CalculateError(linearProblemProperties.M, linearProblemProperties.B, X1);
            double[] out1 = nonLinearConjugateGradient.CalculateError(linearProblemProperties.M, linearProblemProperties.B, X);

            Console.ReadLine();
        }
Exemplo n.º 5
0
        public void GaussSeidelSparseTest()
        {
            int             maxIterations      = 100;
            double          epsilon            = Math.Pow(10, -10);
            Generator       generator          = new Generator(30);
            Generator       ownSparseGenerator = new Generator(30, true);
            GaussSeidel     gaussSeidel        = new GaussSeidel(generator.TotalCases, generator.OriginalMatrix, generator.OriginalVector, maxIterations, epsilon);
            OwnSparseSolver ownSparseSolver    = new OwnSparseSolver(ownSparseGenerator.GenerateOwnSparseMatrix(), generator.OriginalVector, maxIterations, epsilon);

            Assert.AreEqual(gaussSeidel.GaussSeidelSolution.Length, ownSparseSolver.OwnSparseMatrixSolution.Length);

            for (int i = 0; i < gaussSeidel.GaussSeidelSolution.Length; i++)
            {
                if (gaussSeidel.GaussSeidelSolution[i] != ownSparseSolver.OwnSparseMatrixSolution[i])
                {
                    Assert.Fail();
                }
            }
        }
Exemplo n.º 6
0
        private void btnSeidel_Click(object sender, EventArgs e)
        {
            txtEcuaciones.Clear();

            GaussSeidel mt = new GaussSeidel(dgvEcuaciones.RowCount, dgvEcuaciones.ColumnCount);

            float[,] matIn = llenarArray();

            for (int i = 0; i < dgvEcuaciones.RowCount; i++)
            {
                for (int j = 0; j < dgvEcuaciones.ColumnCount; j++)
                {
                    mt.SetValue(i, j, matIn[i, j]);
                }
            }

            mt.Cambio   += new EventHandler <MatrizEventArgs>(mt_Cambio);
            mt.Completo += new EventHandler <MatrizEventArgs>(mt_Completo);

            mt.ApplyMethod();
        }
Exemplo n.º 7
0
        public MainWindowViewModel()
        {
            logger        = new Logger();
            logger.Write += Logger_Write;
            Settings.Load();
            run = new RelayCommand(x => {
                IMethod method = null;
                var a          = Matrix.FromArray(A);
                var b          = Vector.FromArray(B);
                switch (methodIndex)
                {
                case 0:
                    method = new Cholesky();
                    break;

                case 1:
                    method = new GaussSeidel();
                    break;

                case 2:
                    method = new successive_overrelaxation();
                    break;

                case 3:
                    method = new LUmet();
                    break;

                default:
                    logger.NewMsg("Такого методу немає");
                    break;
                }
                if (method != null)
                {
                    method.Log = logger;
                    X          = method.Run(a, b).ToArray();
                }
            });
            random = new RelayCommand(x =>
            {
                A         = Matrix.GetRandomMatrix(Size).ToArray();
                var randB = new double[1, Size];
                var r     = new Random();
                for (int i = 0; i < Size; ++i)
                {
                    randB[0, i] = r.Next(-1000, 1000);
                }
                B = randB;
            });
            close = new RelayCommand(x =>
            {
                App.Current.Shutdown();
            });
            clearLog = new RelayCommand(x =>
            {
                Log = "";
            });
            openSettings = new RelayCommand(x =>
            {
                var form = new SettingsWindow();
                form.Show();
            });
        }
Exemplo n.º 8
0
        public void FormGaussSeidel_Load(object sender, EventArgs e)
        {
            GaussSeidel newgaus = new GaussSeidel();

            label4.Visible = false;
        }
Exemplo n.º 9
0
        public void TimesTest()
        {
            /** EXCHANGE SEPARATOR FOR CSV **/
            System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
            customCulture.NumberFormat.NumberDecimalSeparator    = ".";
            System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;

            /** CONFIGURATION **/
            int       totalAgents = 60;
            int       startAgents = 5;
            int       loopJump    = 5;
            int       loopCounter = 0;
            int       maxIterations;
            double    epsilon = Math.Pow(10, -10);
            Generator generator;
            Generator ownSparseGenerator;

            maxIterations = 1000;
            double[] agents = new double[totalAgents / startAgents];
            double[] cases  = new double[totalAgents / startAgents];

            /** TIMES LISTS **/
            List <double> partialGaussTimes       = new List <double>();
            List <double> sparsePartialGaussTimes = new List <double>();
            List <double> gaussSeidelTimes        = new List <double>();
            List <double> sparseLUTimes           = new List <double>();
            List <double> ownSparseTimes          = new List <double>();

            /** X AND F(X) FOR APPROXIMATION **/
            Approximation approximation = new Approximation();

            double[] arguments                = new double[totalAgents - startAgents + 1];
            double[] partialGaussValues       = new double[totalAgents - startAgents + 1];
            double[] sparsePartialGaussValues = new double[totalAgents - startAgents + 1];
            double[] gaussSeidelValues        = new double[totalAgents - startAgents + 1];
            double[] sparseLUValues           = new double[totalAgents - startAgents + 1];
            double[] ownSparseValues          = new double[totalAgents - startAgents + 1];

            /** COUNTING TIMES **/
            using (var w = new StreamWriter("times.csv"))
            {
                var newLine = "Total Agents, Total Cases, Generate Equation, SparseLU, Gauss-Seidel, Sparse Partial Gauss, Partial Gauss, Own Sparse";
                w.WriteLine(newLine);
                w.Flush();

                loopCounter = 0;
                for (int i = startAgents; i <= totalAgents; i += loopJump)
                {
                    partialGaussTimes.Clear();
                    sparsePartialGaussTimes.Clear();
                    gaussSeidelTimes.Clear();
                    sparseLUTimes.Clear();
                    ownSparseTimes.Clear();

                    generator          = new Generator(i);
                    ownSparseGenerator = new Generator(i, true);

                    for (int j = 0; j < 100; j++)
                    {
                        GaussSeidel     gaussSeidel        = new GaussSeidel(generator.TotalCases, generator.OriginalMatrix, generator.OriginalVector, maxIterations, epsilon);
                        PartialGauss    partialGauss       = new PartialGauss(generator.TotalCases, generator.OriginalMatrix, generator.OriginalVector, false);
                        PartialGauss    sparsePartialGauss = new PartialGauss(generator.TotalCases, generator.OriginalMatrix, generator.OriginalVector, true);
                        SparseLUSolver  sparseLUSolver     = new SparseLUSolver(generator.TotalCases, generator.OriginalMatrix, generator.OriginalVector);
                        OwnSparseSolver ownSparseSolver    = new OwnSparseSolver(ownSparseGenerator.GenerateOwnSparseMatrix(), generator.OriginalVector, maxIterations, epsilon);

                        partialGaussTimes.Add(partialGauss.GaussPartialTiming);
                        sparsePartialGaussTimes.Add(sparsePartialGauss.SparseGaussPartialTiming);
                        gaussSeidelTimes.Add(gaussSeidel.GaussSeidelTiming);
                        sparseLUTimes.Add(sparseLUSolver.SparseLUTiming);
                        ownSparseTimes.Add(ownSparseSolver.OwnSparseMatrixTiming);
                    }

                    partialGaussTimes.Sort();
                    sparsePartialGaussTimes.Sort();
                    gaussSeidelTimes.Sort();
                    sparseLUTimes.Sort();
                    ownSparseTimes.Sort();

                    partialGaussTimes.Remove(partialGaussTimes.FirstOrDefault());
                    partialGaussTimes.Remove(partialGaussTimes.LastOrDefault());

                    sparsePartialGaussTimes.Remove(sparsePartialGaussTimes.FirstOrDefault());
                    sparsePartialGaussTimes.Remove(sparsePartialGaussTimes.LastOrDefault());

                    gaussSeidelTimes.Remove(gaussSeidelTimes.FirstOrDefault());
                    gaussSeidelTimes.Remove(gaussSeidelTimes.LastOrDefault());

                    sparseLUTimes.Remove(sparseLUTimes.FirstOrDefault());
                    sparseLUTimes.Remove(sparseLUTimes.LastOrDefault());

                    ownSparseTimes.Remove(ownSparseTimes.FirstOrDefault());
                    ownSparseTimes.Remove(ownSparseTimes.LastOrDefault());

                    newLine = $"{i},{generator.TotalCases},{generator.GenerateEquationTiming},{sparseLUTimes.Average()},{gaussSeidelTimes.Average()},{sparsePartialGaussTimes.Average()}, {partialGaussTimes.Average()}, {ownSparseTimes.Average()}";
                    w.WriteLine(newLine);
                    w.Flush();

                    arguments[loopCounter]                = generator.TotalCases;
                    partialGaussValues[loopCounter]       = partialGaussTimes.Average();
                    sparsePartialGaussValues[loopCounter] = sparsePartialGaussTimes.Average();
                    gaussSeidelValues[loopCounter]        = gaussSeidelTimes.Average();
                    sparseLUValues[loopCounter]           = sparseLUTimes.Average();
                    ownSparseValues[loopCounter]          = ownSparseTimes.Average();

                    agents[loopCounter] = generator.TotalAgents;
                    cases[loopCounter]  = generator.TotalCases;

                    loopCounter++;
                }
            }

            /** APPROXIMATION **/
            var partialGaussApproximationTest       = approximation.GetApproximation(3, arguments, partialGaussValues);
            var sparsePartialGaussApproximationTest = approximation.GetApproximation(2, arguments, sparsePartialGaussValues);
            var gaussSeidelApproximationTest        = approximation.GetApproximation(2, arguments, gaussSeidelValues);
            var sparseLUApproximationTest           = approximation.getLinearRegression(arguments, sparseLUValues);
            var ownSparseApproximationTest          = approximation.GetApproximation(2, arguments, ownSparseValues);

            /** toString **/
            using (var s = new StreamWriter("strings.txt"))
            {
                s.WriteLine("PARTIAL GAUSS " + partialGaussApproximationTest.GetString());
                s.WriteLine("SPARSE PARTIAL GAUUS " + sparsePartialGaussApproximationTest.GetString());
                s.WriteLine("GAUSS SEIDEL " + gaussSeidelApproximationTest.GetString());
                s.WriteLine("SPARSE LU " + sparseLUApproximationTest.GetString());
                s.WriteLine("OWN SPARSE " + ownSparseApproximationTest.GetString());
                s.Flush();
            }

            /** toValue **/
            using (var v = new StreamWriter("approximation.csv"))
            {
                var line = "Total Agents, Total Cases, SparseLU, Gauss-Seidel, Sparse Partial Gauss, Partial Gauss, Own Sparse";
                v.WriteLine(line);
                v.Flush();

                for (int i = 0; i < (totalAgents / startAgents); i++)
                {
                    line = $"{agents[i]}, {cases[i]}, {sparseLUApproximationTest.GetResult(cases[i])}, {gaussSeidelApproximationTest.GetResult(cases[i])}, {sparsePartialGaussApproximationTest.GetResult(cases[i])}, {partialGaussApproximationTest.GetResult(cases[i])}, {ownSparseApproximationTest.GetResult(cases[i])}";
                    v.WriteLine(line);
                    v.Flush();
                }
            }

            /** ERRORS **/
            double partialGaussError       = 0;
            double sparsePartialGaussError = 0;
            double gaussSeidelError        = 0;
            double sparseLUError           = 0;
            double ownSparseError          = 0;

            for (int i = 0; i < (totalAgents / startAgents); i++)
            {
                partialGaussError       += Math.Sqrt(Math.Pow(partialGaussValues[i] - partialGaussApproximationTest.GetResult(cases[i]), 2));
                sparsePartialGaussError += Math.Sqrt(Math.Pow(sparsePartialGaussValues[i] - sparsePartialGaussApproximationTest.GetResult(cases[i]), 2));
                gaussSeidelError        += Math.Sqrt(Math.Pow(gaussSeidelValues[i] - gaussSeidelApproximationTest.GetResult(cases[i]), 2));
                sparseLUError           += Math.Sqrt(Math.Pow(sparseLUValues[i] - sparseLUApproximationTest.GetResult(cases[i]), 2));
                ownSparseError          += Math.Sqrt(Math.Pow(ownSparseValues[i] - ownSparseApproximationTest.GetResult(cases[i]), 2));
            }

            using (var e = new StreamWriter("errors.txt"))
            {
                e.WriteLine("PARTIAL GAUSS ERROR " + partialGaussError);
                e.WriteLine("SPARSE PARTIAL GAUSS ERROR " + sparsePartialGaussError);
                e.WriteLine("GAUSS SEIDEL ERROR " + gaussSeidelError);
                e.WriteLine("SPARSE LU ERROR " + sparseLUError);
                e.WriteLine("OWN SPARSE ERROR " + ownSparseError);
                e.Flush();
            }

            /** COUNTING TIME FOR 100K */
            using (var w = new StreamWriter("100k.txt"))
            {
                w.WriteLine("PARTIAL GAUSS 100k " + partialGaussApproximationTest.GetResult(100000) / Math.Pow(10, 6) + " SEKUND");
                w.WriteLine("SPARSE PARTIAL 100k " + sparsePartialGaussApproximationTest.GetResult(100000) / Math.Pow(10, 6) + " SEKUND");
                w.WriteLine("GAUSS SEIDEL 100k " + gaussSeidelApproximationTest.GetResult(100000) / Math.Pow(10, 6) + " SEKUND");
                w.WriteLine("SPARSE LU 100k " + sparseLUApproximationTest.GetResult(100000) + " MIKROSEKUND");
                w.WriteLine("OWN SPARSE 100k " + ownSparseApproximationTest.GetResult(100000) / Math.Pow(10, 6) + " SEKUND");
                w.Flush();
            }
        }
Exemplo n.º 10
0
        static void Main(string[] args)
        {
            var sw = new Stopwatch();
            var a  = new Matrix(3);

            a[0, 0] = 25;
            a[0, 1] = 15;
            a[0, 2] = -5;
            a[1, 0] = 15;
            a[1, 1] = 18;
            a[1, 2] = 0;
            a[2, 0] = -5;
            a[2, 1] = 0;
            a[2, 2] = 11;
            var x = new Vector(3);

            x[0] = 1;
            x[1] = 1;
            x[2] = 1;
            var     b      = a * x;
            IMethod method = null;

            Console.WriteLine("*** Performance Test ***");
            Console.WriteLine("*** Successive Overrelaxation ***");
            method = new successive_overrelaxation();
            method.Run(a, b);
            var listRes = new List <TimeSpan>();

            for (int i = 0; i < 1000; i++)
            {
                sw.Start();
                var res = method.Run(a, b);
                sw.Stop();
                listRes.Add(sw.Elapsed);
                Console.WriteLine($"{sw.Elapsed.TotalMilliseconds} ms");
                sw.Reset();
            }
            Console.WriteLine($"Average - {listRes.Average(y => y.TotalMilliseconds)} ms");
            Console.WriteLine("*** LU ***");
            method  = new LUmet();
            listRes = new List <TimeSpan>();
            for (int i = 0; i < 1000; i++)
            {
                sw.Start();
                var res = method.Run(a, b);
                sw.Stop();
                listRes.Add(sw.Elapsed);
                Console.WriteLine($"{sw.Elapsed.TotalMilliseconds} ms");
                sw.Reset();
            }
            Console.WriteLine($"Average - {listRes.Average(y => y.TotalMilliseconds)} ms");
            Console.WriteLine("*** Gauss - Seidel ***");
            method  = new GaussSeidel();
            listRes = new List <TimeSpan>();
            for (int i = 0; i < 1000; i++)
            {
                sw.Start();
                var res = method.Run(a, b);
                sw.Stop();
                listRes.Add(sw.Elapsed);
                Console.WriteLine($"{sw.Elapsed.TotalMilliseconds} ms");
                sw.Reset();
            }
            Console.WriteLine($"Average - {listRes.Average(y => y.TotalMilliseconds)} ms");
            Console.WriteLine("*** Cholesky ***");
            method  = new Cholesky();
            listRes = new List <TimeSpan>();
            for (int i = 0; i < 1000; i++)
            {
                sw.Start();
                var res = method.Run(a, b);
                sw.Stop();
                listRes.Add(sw.Elapsed);
                Console.WriteLine($"{sw.Elapsed.TotalMilliseconds} ms");
                sw.Reset();
            }
            Console.WriteLine($"Average - {listRes.Average(y => y.TotalMilliseconds)} ms");
            Console.ReadLine();
        }
Exemplo n.º 11
0
    public static void monogrid_poisson_1d(int n, double a, double b, double ua, double ub,
                                           Func <double, double> force, Func <double, double> exact, ref int it_num,
                                           ref double[] u)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    MONOGRID_POISSON_1D solves a 1D PDE, using the Gauss-Seidel method.
    //
    //  Discussion:
    //
    //    This routine solves a 1D boundary value problem of the form
    //
    //      - U''(X) = F(X) for A < X < B,
    //
    //    with boundary conditions U(A) = UA, U(B) = UB.
    //
    //    The Gauss-Seidel method is used.
    //
    //    This routine is provided primarily for comparison with the
    //    multigrid solver.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    26 July 2014
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Reference:
    //
    //    William Hager,
    //    Applied Numerical Linear Algebra,
    //    Prentice-Hall, 1988,
    //    ISBN13: 978-0130412942,
    //    LC: QA184.H33.
    //
    //  Parameters:
    //
    //    Input, int N, the number of intervals.
    //
    //    Input, double A, B, the endpoints.
    //
    //    Input, double UA, UB, the boundary values at the endpoints.
    //
    //    Input, double FORCE ( double x ), the name of the function
    //    which evaluates the right hand side.
    //
    //    Input, double EXACT ( double x ), the name of the function
    //    which evaluates the exact solution.
    //
    //    Output, int &IT_NUM, the number of iterations.
    //
    //    Output, double U[N+1], the computed solution.
    //
    {
        double d1 = 0;
        int    i;
        //
        //  Initialization.
        //
        const double tol = 0.0001;

        //
        //  Set the nodes.
        //
        double[] x = typeMethods.r8vec_linspace_new(n + 1, a, b);
        //
        //  Set the right hand side.
        //
        double[] r = new double[n + 1];

        r[0] = ua;
        double h = (b - a) / n;

        for (i = 1; i < n; i++)
        {
            r[i] = h * h * force(x[i]);
        }

        r[n] = ub;

        for (i = 0; i <= n; i++)
        {
            u[i] = 0.0;
        }

        it_num = 0;
        //
        //  Gauss-Seidel iteration.
        //
        for (;;)
        {
            it_num += 1;

            GaussSeidel.gauss_seidel(n + 1, r, ref u, ref d1);

            if (d1 <= tol)
            {
                break;
            }
        }
    }
Exemplo n.º 12
0
    public static void multigrid_poisson_1d(int n, double a, double b, double ua, double ub,
                                            Func <double, double> force, Func <double, double> exact, ref int it_num,
                                            ref double[] u)

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    MULTIGRID_POISSON_1D solves a 1D PDE using the multigrid method.
    //
    //  Discussion:
    //
    //    This routine solves a 1D boundary value problem of the form
    //
    //      - U''(X) = F(X) for A < X < B,
    //
    //    with boundary conditions U(A) = UA, U(B) = UB.
    //
    //    The multigrid method is used.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    26 July 2014
    //
    //  Author:
    //
    //    Original FORTRAN77 version by William Hager.
    //    C++ version by John Burkardt.
    //
    //  Reference:
    //
    //    William Hager,
    //    Applied Numerical Linear Algebra,
    //    Prentice-Hall, 1988,
    //    ISBN13: 978-0130412942,
    //    LC: QA184.H33.
    //
    //  Parameters:
    //
    //    Input, int N, the number of intervals.
    //    N must be a power of 2.
    //
    //    Input, double A, B, the endpoints.
    //
    //    Input, double UA, UB, the boundary values at the endpoints.
    //
    //    Input, double FORCE ( double x ), the name of the function
    //    which evaluates the right hand side.
    //
    //    Input, double EXACT ( double x ), the name of the function
    //    which evaluates the exact solution.
    //
    //    Output, int &IT_NUM, the number of iterations.
    //
    //    Output, double U[N+1], the computed solution.
    //
    {
        int i;
        //
        //  Determine if we have enough storage.
        //
        int k = (int)Math.Log2(n);

        if (Math.Abs(n - Math.Pow(2, k)) > double.Epsilon)
        {
            Console.WriteLine("");
            Console.WriteLine("MULTIGRID_POISSON_1D - Fatal error!");
            Console.WriteLine("  N is not a power of 2.");
            return;
        }

        int nl = n + n + k - 2;
        //
        //  Initialization.
        //
        const int it = 4;

        it_num = 0;
        const double tol  = 0.0001;
        const double utol = 0.7;
        int          m    = n;

        //
        //  Set the nodes.
        //
        double[] x = typeMethods.r8vec_linspace_new(n + 1, a, b);
        //
        //  Set the right hand side.
        //
        double[] r = new double[nl];
        r[0] = ua;
        double h = (b - a) / n;

        for (i = 1; i < n; i++)
        {
            r[i] = h * h * force(x[i]);
        }

        r[n] = ub;

        double[] uu = new double[nl];

        for (i = 0; i < nl; i++)
        {
            uu[i] = 0.0;
        }

        //
        //  L points to first entry of solution
        //  LL points to penultimate entry.
        //
        int l  = 0;
        int ll = n - 1;
        //
        //  Gauss-Seidel iteration
        //
        double d1 = 0.0;
        int    j  = 0;

        for (;;)
        {
            double d0 = d1;
            j += 1;
            GaussSeidel.gauss_seidel(n + 1, r, ref uu, ref d1, rIndex: +l, uIndex: +l);
            it_num += 1;
            //
            //  Do at least 4 iterations at each level.
            //
            if (j < it)
            {
            }
            //
            //  Enough iterations, satisfactory decrease, on finest grid, exit.
            //
            else if (d1 < tol && n == m)
            {
                break;
            }
            //
            //  Enough iterations, satisfactory convergence, go finer.
            //
            else if (d1 < tol)
            {
                Transfer.ctof(n + 1, uu, n + n + 1, ref uu, ucIndex: +l, ufIndex: +(l - 1 - n - n));

                n += n;
                ll = l - 2;
                l  = l - 1 - n;
                j  = 0;
            }
            //
            //  Enough iterations, slow convergence, 2 < N, go coarser.
            //
            else if (utol * d0 <= d1 && 2 < n)
            {
                Transfer.ftoc(n + 1, uu, r, n / 2 + 1, ref uu, ref r, ufIndex: +l, rfIndex: +l,
                              ucIndex: +(l + n + 1), rcIndex: +(l + n + 1));

                n /= 2;
                l  = ll + 2;
                ll = ll + n + 1;
                j  = 0;
            }
        }

        for (i = 0; i < n + 1; i++)
        {
            u[i] = uu[i];
        }
    }