public void DetermineStatus()
        {
            var criteria = new List<IIterationStopCriterium<double>>
            {
                new FailureStopCriterium(),
                new DivergenceStopCriterium(),
                new IterationCountStopCriterium<double>(1)
            };

            var iterator = new Iterator<double>(criteria);

            // First step, nothing should happen.
            iterator.DetermineStatus(
                0,
                DenseVector.Create(3, i => 4),
                DenseVector.Create(3, i => 4),
                DenseVector.Create(3, i => 4));
            Assert.AreEqual(IterationStatus.Continue, iterator.Status, "Incorrect status");

            // Second step, should run out of iterations.
            iterator.DetermineStatus(
                1,
                DenseVector.Create(3, i => 4),
                DenseVector.Create(3, i => 4),
                DenseVector.Create(3, i => 4));
            Assert.AreEqual(IterationStatus.StoppedWithoutConvergence, iterator.Status, "Incorrect status");
        }
예제 #2
0
        public void CanSolveForRandomMatrix(int order)
        {
            var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order);
            var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order);

            var monitor = new Iterator<double>(new IIterationStopCriterium<double>[]
                {
                    new IterationCountStopCriterium<double>(1000),
                    new ResidualStopCriterium(1e-10)
                });
            var solver = new TFQMR(monitor);
            var matrixX = solver.Solve(matrixA, matrixB);

            // The solution X row dimension is equal to the column dimension of A
            Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);

            // The solution X has the same number of columns as B
            Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);

            var matrixBReconstruct = matrixA*matrixX;

            // Check the reconstruction.
            for (var i = 0; i < matrixB.RowCount; i++)
            {
                for (var j = 0; j < matrixB.ColumnCount; j++)
                {
                    Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1.0e-7);
                }
            }
        }
예제 #3
0
        public void CanSolveForRandomMatrix(int order)
        {
            var matrixA = Matrix<double>.Build.Random(order, order, 1);
            var matrixB = Matrix<double>.Build.Random(order, order, 1);

            var monitor = new Iterator<double>(
                new IterationCountStopCriterium<double>(1000),
                new ResidualStopCriterium<double>(1e-10));

            var solver = new GpBiCg();
            var matrixX = matrixA.SolveIterative(matrixB, solver, monitor);

            // The solution X row dimension is equal to the column dimension of A
            Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);

            // The solution X has the same number of columns as B
            Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);

            var matrixBReconstruct = matrixA*matrixX;

            // Check the reconstruction.
            for (var i = 0; i < matrixB.RowCount; i++)
            {
                for (var j = 0; j < matrixB.ColumnCount; j++)
                {
                    Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1.0e-7);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Creates a default iterator with all the <see cref="IIterationStopCriterium"/> objects.
        /// </summary>
        /// <returns>A new <see cref="IIterator"/> object.</returns>
        public static IIterator CreateDefault()
        {
            var iterator = new Iterator();
            iterator.Add(new FailureStopCriterium());
            iterator.Add(new DivergenceStopCriterium());
            iterator.Add(new IterationCountStopCriterium());
            iterator.Add(new ResidualStopCriterium());

            return iterator;
        }
예제 #5
0
        public void SolveUnitMatrixAndBackMultiply()
        {
            // Create the identity matrix
            var matrix = SparseMatrix.Identity(100);

            // Create the y vector
            var y = DenseVector.Create(matrix.RowCount, i => 1);

            // Create an iteration monitor which will keep track of iterative convergence
            var monitor = new Iterator<double>(new IIterationStopCriterium<double>[]
                {
                    new IterationCountStopCriterium<double>(MaximumIterations),
                    new ResidualStopCriterium(ConvergenceBoundary),
                    new DivergenceStopCriterium(),
                    new FailureStopCriterium()
                });

            var solver = new TFQMR(monitor);

            // Solve equation Ax = y
            var x = solver.Solve(matrix, y);

            // Now compare the results
            Assert.IsNotNull(x, "#02");
            Assert.AreEqual(y.Count, x.Count, "#03");

            // Back multiply the vector
            var z = matrix.Multiply(x);

            // Check that the solution converged
            Assert.IsTrue(monitor.HasConverged, "#04");

            // Now compare the vectors
            for (var i = 0; i < y.Count; i++)
            {
                Assert.IsTrue((y[i] - z[i]).IsSmaller(ConvergenceBoundary, 1), "#05-" + i);
            }
        }
        public void ResetToPrecalculationState()
        {
            var criteria = new List<IIterationStopCriterium<double>>
            {
                new FailureStopCriterium(),
                new DivergenceStopCriterium(),
                new IterationCountStopCriterium<double>(1)
            };

            var iterator = new Iterator<double>(criteria);

            // First step, nothing should happen.
            iterator.DetermineStatus(
                0,
                DenseVector.Create(3, i => 4),
                DenseVector.Create(3, i => 4),
                DenseVector.Create(3, i => 4));
            Assert.AreEqual(IterationStatus.Continue, iterator.Status, "Incorrect status");

            iterator.Reset();
            Assert.AreEqual(IterationStatus.Continue, iterator.Status, "Incorrect status");
            Assert.AreEqual(IterationStatus.Continue, criteria[0].Status, "Incorrect status");
            Assert.AreEqual(IterationStatus.Continue, criteria[1].Status, "Incorrect status");
            Assert.AreEqual(IterationStatus.Continue, criteria[2].Status, "Incorrect status");
        }
 public void DetermineStatusWithoutStopCriteriaDoesNotThrow()
 {
     var iterator = new Iterator<double>();
     Assert.DoesNotThrow(() => iterator.DetermineStatus(
         0,
         DenseVector.Create(3, i => 4),
         DenseVector.Create(3, i => 5),
         DenseVector.Create(3, i => 6)));
 }
예제 #8
0
        public void SolveUnitMatrixAndBackMultiply()
        {
            // Create the identity matrix
            var matrix = Matrix<double>.Build.SparseIdentity(100);

            // Create the y vector
            var y = Vector<double>.Build.Dense(matrix.RowCount, 1);

            // Create an iteration monitor which will keep track of iterative convergence
            var monitor = new Iterator<double>(
                new IterationCountStopCriterion<double>(MaximumIterations),
                new ResidualStopCriterion<double>(ConvergenceBoundary),
                new DivergenceStopCriterion<double>(),
                new FailureStopCriterion<double>());

            var solver = new MlkBiCgStab();

            // Solve equation Ax = y
            var x = matrix.SolveIterative(y, solver, monitor);

            // Now compare the results
            Assert.IsNotNull(x, "#02");
            Assert.AreEqual(y.Count, x.Count, "#03");

            // Back multiply the vector
            var z = matrix.Multiply(x);

            // Check that the solution converged
            Assert.IsTrue(monitor.Status == IterationStatus.Converged, "#04");

            // Now compare the vectors
            for (var i = 0; i < y.Count; i++)
            {
                Assert.GreaterOrEqual(ConvergenceBoundary, Math.Abs(y[i] - z[i]), "#05-" + i);
            }
        }
예제 #9
0
        public void CanSolveForRandomVector(int order)
        {
            var matrixA = Matrix<double>.Build.Random(order, order, 1);
            var vectorb = Vector<double>.Build.Random(order, 1);

            var monitor = new Iterator<double>(
                new IterationCountStopCriterion<double>(1000),
                new ResidualStopCriterion<double>(1e-10));

            var solver = new MlkBiCgStab();

            var resultx = matrixA.SolveIterative(vectorb, solver, monitor);
            Assert.AreEqual(matrixA.ColumnCount, resultx.Count);

            var matrixBReconstruct = matrixA*resultx;

            // Check the reconstruction.
            for (var i = 0; i < order; i++)
            {
                Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-7);
            }
        }
예제 #10
0
        public void SolvePoissonMatrixAndBackMultiply()
        {
            // Create the matrix
            var matrix = Matrix<double>.Build.Sparse(100, 100);

            // Assemble the matrix. We assume we're solving the Poisson equation
            // on a rectangular 10 x 10 grid
            const int GridSize = 10;

            // The pattern is:
            // 0 .... 0 -1 0 0 0 0 0 0 0 0 -1 4 -1 0 0 0 0 0 0 0 0 -1 0 0 ... 0
            for (var i = 0; i < matrix.RowCount; i++)
            {
                // Insert the first set of -1's
                if (i > (GridSize - 1))
                {
                    matrix[i, i - GridSize] = -1;
                }

                // Insert the second set of -1's
                if (i > 0)
                {
                    matrix[i, i - 1] = -1;
                }

                // Insert the centerline values
                matrix[i, i] = 4;

                // Insert the first trailing set of -1's
                if (i < matrix.RowCount - 1)
                {
                    matrix[i, i + 1] = -1;
                }

                // Insert the second trailing set of -1's
                if (i < matrix.RowCount - GridSize)
                {
                    matrix[i, i + GridSize] = -1;
                }
            }

            // Create the y vector
            var y = Vector<double>.Build.Dense(matrix.RowCount, 1);

            // Create an iteration monitor which will keep track of iterative convergence
            var monitor = new Iterator<double>(
                new IterationCountStopCriterion<double>(MaximumIterations),
                new ResidualStopCriterion<double>(ConvergenceBoundary),
                new DivergenceStopCriterion<double>(),
                new FailureStopCriterion<double>());

            var solver = new MlkBiCgStab();

            // Solve equation Ax = y
            var x = matrix.SolveIterative(y, solver, monitor);

            // Now compare the results
            Assert.IsNotNull(x, "#02");
            Assert.AreEqual(y.Count, x.Count, "#03");

            // Back multiply the vector
            var z = matrix.Multiply(x);

            // Check that the solution converged
            Assert.IsTrue(monitor.Status == IterationStatus.Converged, "#04");

            // Now compare the vectors
            for (var i = 0; i < y.Count; i++)
            {
                Assert.GreaterOrEqual(ConvergenceBoundary, Math.Abs(y[i] - z[i]), "#05-" + i);
            }
        }
예제 #11
0
 private void InitializeSolver()
 {
     result = Vector<double>.Build.Dense(n * m);
       Control.LinearAlgebraProvider = new OpenBlasLinearAlgebraProvider();
     //Control.UseNativeMKL();
     //Control.LinearAlgebraProvider = new MklLinearAlgebraProvider();
     //Control.UseManaged();
     var iterationCountStopCriterion = new IterationCountStopCriterion<double>(1000);
     var residualStopCriterion = new ResidualStopCriterion<double>(1e-7);
     monitor = new Iterator<double>(iterationCountStopCriterion, residualStopCriterion);
     solver = new BiCgStab();
     preconditioner = new MILU0Preconditioner();
 }
예제 #12
0
        /// <summary>
        /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
        /// solution vector and x is the unknown vector.
        /// </summary>
        /// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
        /// <param name="input">The solution vector, <c>b</c></param>
        /// <param name="result">The result vector, <c>x</c></param>
        /// <param name="iterator">The iterator to use to control when to stop iterating.</param>
        /// <param name="preconditioner">The preconditioner to use for approximations.</param>
        public void Solve(Matrix <double> matrix, Vector <double> input, Vector <double> result, Iterator <double> iterator, IPreconditioner <double> preconditioner)
        {
            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
            }

            if (result.Count != input.Count)
            {
                throw new ArgumentException(Resources.ArgumentVectorsSameLength);
            }

            if (iterator == null)
            {
                iterator = new Iterator <double>();
            }

            if (preconditioner == null)
            {
                preconditioner = new UnitPreconditioner <double>();
            }

            // Create a copy of the solution and result vectors so we can use them
            // later on
            var internalInput  = input.Clone();
            var internalResult = result.Clone();

            foreach (var solver in _solvers)
            {
                // Store a reference to the solver so we can stop it.

                IterationStatus status;
                try
                {
                    // Reset the iterator and pass it to the solver
                    iterator.Reset();

                    // Start the solver
                    solver.Item1.Solve(matrix, internalInput, internalResult, iterator, solver.Item2 ?? preconditioner);
                    status = iterator.Status;
                }
                catch (Exception)
                {
                    // The solver broke down.
                    // Log a message about this
                    // Switch to the next preconditioner.
                    // Reset the solution vector to the previous solution
                    input.CopyTo(internalInput);
                    continue;
                }

                // There was no fatal breakdown so check the status
                if (status == IterationStatus.Converged)
                {
                    // We're done
                    internalResult.CopyTo(result);
                    break;
                }

                // We're not done
                // Either:
                // - calculation finished without convergence
                if (status == IterationStatus.StoppedWithoutConvergence)
                {
                    // Copy the internal result to the result vector and
                    // continue with the calculation.
                    internalResult.CopyTo(result);
                }
                else
                {
                    // - calculation failed --> restart with the original vector
                    // - calculation diverged --> restart with the original vector
                    // - Some unknown status occurred --> To be safe restart.
                    input.CopyTo(internalInput);
                }
            }
        }
        public void DetermineStatusWithNegativeIterationNumberThrowsArgumentOutOfRangeException()
        {
            var criteria = new List<IIterationStopCriterium<double>>
            {
                new FailureStopCriterium(),
                new DivergenceStopCriterium(),
                new IterationCountStopCriterium<double>(),
                new ResidualStopCriterium()
            };
            var iterator = new Iterator<double>(criteria);

            Assert.Throws<ArgumentOutOfRangeException>(() => iterator.DetermineStatus(
                -1,
                DenseVector.Create(3, i => 4),
                DenseVector.Create(3, i => 5),
                DenseVector.Create(3, i => 6)));
        }
예제 #14
0
        public void CanSolveForRandomVector(int order)
        {
            var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order);
            var vectorb = MatrixLoader.GenerateRandomDenseVector(order);

            var monitor = new Iterator<double>(new IIterationStopCriterium<double>[]
                {
                    new IterationCountStopCriterium<double>(1000),
                    new ResidualStopCriterium(1e-10),
                });
            var solver = new TFQMR(monitor);

            var resultx = solver.Solve(matrixA, vectorb);
            Assert.AreEqual(matrixA.ColumnCount, resultx.Count);

            var matrixBReconstruct = matrixA*resultx;

            // Check the reconstruction.
            for (var i = 0; i < order; i++)
            {
                Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-7);
            }
        }
예제 #15
0
        public void SolvePoissonMatrixAndBackMultiply()
        {
            // Create the matrix
            var matrix = new SparseMatrix(100);

            // Assemble the matrix. We assume we're solving the Poisson equation
            // on a rectangular 10 x 10 grid
            const int GridSize = 10;

            // The pattern is:
            // 0 .... 0 -1 0 0 0 0 0 0 0 0 -1 4 -1 0 0 0 0 0 0 0 0 -1 0 0 ... 0
            for (var i = 0; i < matrix.RowCount; i++)
            {
                // Insert the first set of -1's
                if (i > (GridSize - 1))
                {
                    matrix[i, i - GridSize] = -1;
                }

                // Insert the second set of -1's
                if (i > 0)
                {
                    matrix[i, i - 1] = -1;
                }

                // Insert the centerline values
                matrix[i, i] = 4;

                // Insert the first trailing set of -1's
                if (i < matrix.RowCount - 1)
                {
                    matrix[i, i + 1] = -1;
                }

                // Insert the second trailing set of -1's
                if (i < matrix.RowCount - GridSize)
                {
                    matrix[i, i + GridSize] = -1;
                }
            }

            // Create the y vector
            var y = DenseVector.Create(matrix.RowCount, i => 1);

            // Create an iteration monitor which will keep track of iterative convergence
            var monitor = new Iterator<double>(new IIterationStopCriterium<double>[]
                {
                    new IterationCountStopCriterium<double>(MaximumIterations),
                    new ResidualStopCriterium(ConvergenceBoundary),
                    new DivergenceStopCriterium(),
                    new FailureStopCriterium()
                });
            var solver = new MlkBiCgStab(monitor);

            // Solve equation Ax = y
            var x = solver.Solve(matrix, y);

            // Now compare the results
            Assert.IsNotNull(x, "#02");
            Assert.AreEqual(y.Count, x.Count, "#03");

            // Back multiply the vector
            var z = matrix.Multiply(x);

            // Check that the solution converged
            Assert.IsTrue(monitor.HasConverged, "#04");

            // Now compare the vectors
            for (var i = 0; i < y.Count; i++)
            {
            #if !PORTABLE
                Assert.IsTrue(Math.Abs(y[i] - z[i]).IsSmaller(ConvergenceBoundary, 1), "#05-" + i);
            #else
                Assert.IsTrue(Math.Abs(y[i] - z[i]).IsSmaller(ConvergenceBoundary * 100.0, 1), "#05-" + i);
            #endif
            }
        }
예제 #16
0
        public void SolveScaledUnitMatrixAndBackMultiply()
        {
            // Create the identity matrix
            var matrix = Matrix<double>.Build.SparseIdentity(100);

            // Scale it with a funny number
            matrix.Multiply(Math.PI, matrix);

            // Create the y vector
            var y = Vector<double>.Build.Dense(matrix.RowCount, 1);

            // Create an iteration monitor which will keep track of iterative convergence
            var monitor = new Iterator<double>(
                new IterationCountStopCriterion<double>(MaximumIterations),
                new ResidualStopCriterion<double>(ConvergenceBoundary),
                new DivergenceStopCriterion<double>(),
                new FailureStopCriterion<double>());

            var solver = new TFQMR();

            // Solve equation Ax = y
            var x = matrix.SolveIterative(y, solver, monitor);

            // Now compare the results
            Assert.IsNotNull(x, "#02");
            Assert.AreEqual(y.Count, x.Count, "#03");

            // Back multiply the vector
            var z = matrix.Multiply(x);

            // Check that the solution converged
            Assert.IsTrue(monitor.Status == IterationStatus.Converged, "#04");

            // Now compare the vectors
            Assert.LessOrEqual(Distance.Chebyshev(y, z), 2*ConvergenceBoundary);
        }
        /// <summary>
        /// Run example
        /// </summary>
        public void Run()
        {
            // Format matrix output to console
            var formatProvider = (CultureInfo)CultureInfo.InvariantCulture.Clone();
            formatProvider.TextInfo.ListSeparator = " ";

            // Solve next system of linear equations (Ax=b):
            // 5*x + 2*y - 4*z = -7
            // 3*x - 7*y + 6*z = 38
            // 4*x + 1*y + 5*z = 43

            // Create matrix "A" with coefficients
            var matrixA = new DenseMatrix(new[,] { { 5.00, 2.00, -4.00 }, { 3.00, -7.00, 6.00 }, { 4.00, 1.00, 5.00 } });
            Console.WriteLine(@"Matrix 'A' with coefficients");
            Console.WriteLine(matrixA.ToString("#0.00\t", formatProvider));
            Console.WriteLine();

            // Create vector "b" with the constant terms.
            var vectorB = new DenseVector(new[] { -7.0, 38.0, 43.0 });
            Console.WriteLine(@"Vector 'b' with the constant terms");
            Console.WriteLine(vectorB.ToString("#0.00\t", formatProvider));
            Console.WriteLine();

            // Create stop criteriums to monitor an iterative calculation. There are next available stop criteriums:
            // - DivergenceStopCriterium: monitors an iterative calculation for signs of divergence;
            // - FailureStopCriterium: monitors residuals for NaN's;
            // - IterationCountStopCriterium: monitors the numbers of iteration steps;
            // - ResidualStopCriterium: monitors residuals if calculation is considered converged;

            // Stop calculation if 1000 iterations reached during calculation
            var iterationCountStopCriterium = new IterationCountStopCriterium(1000);

            // Stop calculation if residuals are below 1E-10 --> the calculation is considered converged
            var residualStopCriterium = new ResidualStopCriterium(1e-10);

            // Create monitor with defined stop criteriums
            var monitor = new Iterator(new IIterationStopCriterium[] { iterationCountStopCriterium, residualStopCriterium });

            // Load all suitable solvers from current assembly. Below in this example, there is user-defined solver
            // "class UserBiCgStab : IIterativeSolverSetup<double>" which uses regular BiCgStab solver. But user may create any other solver
            // and solver setup classes which implement IIterativeSolverSetup<T> and pass assembly to next function:
            CompositeSolver.LoadSolverInformationFromAssembly(Assembly.GetExecutingAssembly());

            // Create composite solver
            var solver = new CompositeSolver(monitor);

            // 1. Solve the matrix equation
            var resultX = solver.Solve(matrixA, vectorB);
            Console.WriteLine(@"1. Solve the matrix equation");
            Console.WriteLine();

            // 2. Check solver status of the iterations.
            // Solver has property IterationResult which contains the status of the iteration once the calculation is finished.
            // Possible values are:
            // - CalculationCancelled: calculation was cancelled by the user;
            // - CalculationConverged: calculation has converged to the desired convergence levels;
            // - CalculationDiverged: calculation diverged;
            // - CalculationFailure: calculation has failed for some reason;
            // - CalculationIndetermined: calculation is indetermined, not started or stopped;
            // - CalculationRunning: calculation is running and no results are yet known;
            // - CalculationStoppedWithoutConvergence: calculation has been stopped due to reaching the stopping limits, but that convergence was not achieved;
            Console.WriteLine(@"2. Solver status of the iterations");
            Console.WriteLine(solver.IterationResult);
            Console.WriteLine();

            // 3. Solution result vector of the matrix equation
            Console.WriteLine(@"3. Solution result vector of the matrix equation");
            Console.WriteLine(resultX.ToString("#0.00\t", formatProvider));
            Console.WriteLine();

            // 4. Verify result. Multiply coefficient matrix "A" by result vector "x"
            var reconstructVecorB = matrixA * resultX;
            Console.WriteLine(@"4. Multiply coefficient matrix 'A' by result vector 'x'");
            Console.WriteLine(reconstructVecorB.ToString("#0.00\t", formatProvider));
            Console.WriteLine();
        }
예제 #18
0
파일: TFQMR.cs 프로젝트: kpboyle1/devtreks
        /// <summary>
        /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
        /// solution vector and x is the unknown vector.
        /// </summary>
        /// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
        /// <param name="input">The solution vector, <c>b</c></param>
        /// <param name="result">The result vector, <c>x</c></param>
        /// <param name="iterator">The iterator to use to control when to stop iterating.</param>
        /// <param name="preconditioner">The preconditioner to use for approximations.</param>
        public void Solve(Matrix <double> matrix, Vector <double> input, Vector <double> result, Iterator <double> iterator, IPreconditioner <double> preconditioner)
        {
            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resource.ArgumentMatrixSquare, "matrix");
            }

            if (result.Count != input.Count)
            {
                throw new ArgumentException(Resource.ArgumentVectorsSameLength);
            }

            if (input.Count != matrix.RowCount)
            {
                throw Matrix.DimensionsDontMatch <ArgumentException>(input, matrix);
            }

            if (iterator == null)
            {
                iterator = new Iterator <double>();
            }

            if (preconditioner == null)
            {
                preconditioner = new UnitPreconditioner <double>();
            }

            preconditioner.Initialize(matrix);

            var d = new DenseVector(input.Count);
            var r = DenseVector.OfVector(input);

            var uodd  = new DenseVector(input.Count);
            var ueven = new DenseVector(input.Count);

            var v = new DenseVector(input.Count);
            var pseudoResiduals = DenseVector.OfVector(input);

            var x     = new DenseVector(input.Count);
            var yodd  = new DenseVector(input.Count);
            var yeven = DenseVector.OfVector(input);

            // Temp vectors
            var temp  = new DenseVector(input.Count);
            var temp1 = new DenseVector(input.Count);
            var temp2 = new DenseVector(input.Count);

            // Define the scalars
            double alpha = 0;
            double eta   = 0;
            double theta = 0;

            // Initialize
            var tau = input.L2Norm();
            var rho = tau * tau;

            // Calculate the initial values for v
            // M temp = yEven
            preconditioner.Approximate(yeven, temp);

            // v = A temp
            matrix.Multiply(temp, v);

            // Set uOdd
            v.CopyTo(ueven);

            // Start the iteration
            var iterationNumber = 0;

            while (iterator.DetermineStatus(iterationNumber, result, input, pseudoResiduals) == IterationStatus.Continue)
            {
                // First part of the step, the even bit
                if (IsEven(iterationNumber))
                {
                    // sigma = (v, r)
                    var sigma = v.DotProduct(r);
                    if (sigma.AlmostEqualNumbersBetween(0, 1))
                    {
                        // FAIL HERE
                        iterator.Cancel();
                        break;
                    }

                    // alpha = rho / sigma
                    alpha = rho / sigma;

                    // yOdd = yEven - alpha * v
                    v.Multiply(-alpha, temp1);
                    yeven.Add(temp1, yodd);

                    // Solve M temp = yOdd
                    preconditioner.Approximate(yodd, temp);

                    // uOdd = A temp
                    matrix.Multiply(temp, uodd);
                }

                // The intermediate step which is equal for both even and
                // odd iteration steps.
                // Select the correct vector
                var uinternal = IsEven(iterationNumber) ? ueven : uodd;
                var yinternal = IsEven(iterationNumber) ? yeven : yodd;

                // pseudoResiduals = pseudoResiduals - alpha * uOdd
                uinternal.Multiply(-alpha, temp1);
                pseudoResiduals.Add(temp1, temp2);
                temp2.CopyTo(pseudoResiduals);

                // d = yOdd + theta * theta * eta / alpha * d
                d.Multiply(theta * theta * eta / alpha, temp);
                yinternal.Add(temp, d);

                // theta = ||pseudoResiduals||_2 / tau
                theta = pseudoResiduals.L2Norm() / tau;
                var c = 1 / Math.Sqrt(1 + (theta * theta));

                // tau = tau * theta * c
                tau *= theta * c;

                // eta = c^2 * alpha
                eta = c * c * alpha;

                // x = x + eta * d
                d.Multiply(eta, temp1);
                x.Add(temp1, temp2);
                temp2.CopyTo(x);

                // Check convergence and see if we can bail
                if (iterator.DetermineStatus(iterationNumber, result, input, pseudoResiduals) != IterationStatus.Continue)
                {
                    // Calculate the real values
                    preconditioner.Approximate(x, result);

                    // Calculate the true residual. Use the temp vector for that
                    // so that we don't pollute the pseudoResidual vector for no
                    // good reason.
                    CalculateTrueResidual(matrix, temp, result, input);

                    // Now recheck the convergence
                    if (iterator.DetermineStatus(iterationNumber, result, input, temp) != IterationStatus.Continue)
                    {
                        // We're all good now.
                        return;
                    }
                }

                // The odd step
                if (!IsEven(iterationNumber))
                {
                    if (rho.AlmostEqualNumbersBetween(0, 1))
                    {
                        // FAIL HERE
                        iterator.Cancel();
                        break;
                    }

                    var rhoNew = pseudoResiduals.DotProduct(r);
                    var beta   = rhoNew / rho;

                    // Update rho for the next loop
                    rho = rhoNew;

                    // yOdd = pseudoResiduals + beta * yOdd
                    yodd.Multiply(beta, temp1);
                    pseudoResiduals.Add(temp1, yeven);

                    // Solve M temp = yOdd
                    preconditioner.Approximate(yeven, temp);

                    // uOdd = A temp
                    matrix.Multiply(temp, ueven);

                    // v = uEven + beta * (uOdd + beta * v)
                    v.Multiply(beta, temp1);
                    uodd.Add(temp1, temp);

                    temp.Multiply(beta, temp1);
                    ueven.Add(temp1, v);
                }

                // Calculate the real values
                preconditioner.Approximate(x, result);

                iterationNumber++;
            }
        }
예제 #19
0
        /// <summary>
        /// Run example
        /// </summary>
        public void Run()
        {
            // Format matrix output to console
            var formatProvider = (CultureInfo)CultureInfo.InvariantCulture.Clone();
            formatProvider.TextInfo.ListSeparator = " ";

            // Solve next system of linear equations (Ax=b):
            // 5*x + 2*y - 4*z = -7
            // 3*x - 7*y + 6*z = 38
            // 4*x + 1*y + 5*z = 43

            // Create matrix "A" with coefficients
            var matrixA = DenseMatrix.OfArray(new[,] { { 5.00, 2.00, -4.00 }, { 3.00, -7.00, 6.00 }, { 4.00, 1.00, 5.00 } });
            Console.WriteLine(@"Matrix 'A' with coefficients");
            Console.WriteLine(matrixA.ToString("#0.00\t", formatProvider));
            Console.WriteLine();

            // Create vector "b" with the constant terms.
            var vectorB = new DenseVector(new[] { -7.0, 38.0, 43.0 });
            Console.WriteLine(@"Vector 'b' with the constant terms");
            Console.WriteLine(vectorB.ToString("#0.00\t", formatProvider));
            Console.WriteLine();

            // Create stop criteriums to monitor an iterative calculation. There are next available stop criteriums:
            // - DivergenceStopCriterium: monitors an iterative calculation for signs of divergence;
            // - FailureStopCriterium: monitors residuals for NaN's;
            // - IterationCountStopCriterium: monitors the numbers of iteration steps;
            // - ResidualStopCriterium: monitors residuals if calculation is considered converged;

            // Stop calculation if 1000 iterations reached during calculation
            var iterationCountStopCriterium = new IterationCountStopCriterium<double>(1000);

            // Stop calculation if residuals are below 1E-10 --> the calculation is considered converged
            var residualStopCriterium = new ResidualStopCriterium(1e-10);

            // Create monitor with defined stop criteriums
            var monitor = new Iterator<double>(new IIterationStopCriterium<double>[] { iterationCountStopCriterium, residualStopCriterium });

            // Create Transpose Free Quasi-Minimal Residual solver
            var solver = new TFQMR(monitor);

            // 1. Solve the matrix equation
            var resultX = solver.Solve(matrixA, vectorB);
            Console.WriteLine(@"1. Solve the matrix equation");
            Console.WriteLine();

            // 2. Check solver status of the iterations.
            // Solver has property IterationResult which contains the status of the iteration once the calculation is finished.
            // Possible values are:
            // - CalculationCancelled: calculation was cancelled by the user;
            // - CalculationConverged: calculation has converged to the desired convergence levels;
            // - CalculationDiverged: calculation diverged;
            // - CalculationFailure: calculation has failed for some reason;
            // - CalculationIndetermined: calculation is indetermined, not started or stopped;
            // - CalculationRunning: calculation is running and no results are yet known;
            // - CalculationStoppedWithoutConvergence: calculation has been stopped due to reaching the stopping limits, but that convergence was not achieved;
            Console.WriteLine(@"2. Solver status of the iterations");
            Console.WriteLine(solver.IterationResult);
            Console.WriteLine();

            // 3. Solution result vector of the matrix equation
            Console.WriteLine(@"3. Solution result vector of the matrix equation");
            Console.WriteLine(resultX.ToString("#0.00\t", formatProvider));
            Console.WriteLine();

            // 4. Verify result. Multiply coefficient matrix "A" by result vector "x"
            var reconstructVecorB = matrixA * resultX;
            Console.WriteLine(@"4. Multiply coefficient matrix 'A' by result vector 'x'");
            Console.WriteLine(reconstructVecorB.ToString("#0.00\t", formatProvider));
            Console.WriteLine();
        }
        /// <summary>
        /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
        /// solution vector and x is the unknown vector.
        /// </summary>
        /// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
        /// <param name="input">The solution <see cref="Vector"/>, <c>b</c>.</param>
        /// <param name="result">The result <see cref="Vector"/>, <c>x</c>.</param>
        /// <param name="iterator">The iterator to use to control when to stop iterating.</param>
        /// <param name="preconditioner">The preconditioner to use for approximations.</param>
        public void Solve(Matrix <double> matrix, Vector <double> input, Vector <double> result, Iterator <double> iterator, IPreconditioner <double> preconditioner)
        {
            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSquare, nameof(matrix));
            }

            if (result.Count != input.Count)
            {
                throw new ArgumentException(Resources.ArgumentVectorsSameLength);
            }

            if (input.Count != matrix.RowCount)
            {
                throw Matrix.DimensionsDontMatch <ArgumentException>(input, matrix);
            }

            if (iterator == null)
            {
                iterator = new Iterator <double>();
            }

            if (preconditioner == null)
            {
                preconditioner = new UnitPreconditioner <double>();
            }

            preconditioner.Initialize(matrix);

            // Compute r_0 = b - Ax_0 for some initial guess x_0
            // In this case we take x_0 = vector
            // This is basically a SAXPY so it could be made a lot faster
            var residuals = new DenseVector(matrix.RowCount);

            CalculateTrueResidual(matrix, residuals, result, input);

            // Choose r~ (for example, r~ = r_0)
            var tempResiduals = residuals.Clone();

            // create seven temporary vectors needed to hold temporary
            // coefficients. All vectors are mangled in each iteration.
            // These are defined here to prevent stressing the garbage collector
            var vecP     = new DenseVector(residuals.Count);
            var vecPdash = new DenseVector(residuals.Count);
            var nu       = new DenseVector(residuals.Count);
            var vecS     = new DenseVector(residuals.Count);
            var vecSdash = new DenseVector(residuals.Count);
            var temp     = new DenseVector(residuals.Count);
            var temp2    = new DenseVector(residuals.Count);

            // create some temporary double variables that are needed
            // to hold values in between iterations
            double currentRho = 0;
            double alpha      = 0;
            double omega      = 0;

            var iterationNumber = 0;

            while (iterator.DetermineStatus(iterationNumber, result, input, residuals) == IterationStatus.Continue)
            {
                // rho_(i-1) = r~^T r_(i-1) // dotproduct r~ and r_(i-1)
                var oldRho = currentRho;
                currentRho = tempResiduals.DotProduct(residuals);

                // if (rho_(i-1) == 0) // METHOD FAILS
                // If rho is only 1 ULP from zero then we fail.
                if (currentRho.AlmostEqualNumbersBetween(0, 1))
                {
                    // Rho-type breakdown
                    throw new NumericalBreakdownException();
                }

                if (iterationNumber != 0)
                {
                    // beta_(i-1) = (rho_(i-1)/rho_(i-2))(alpha_(i-1)/omega(i-1))
                    var beta = (currentRho / oldRho) * (alpha / omega);

                    // p_i = r_(i-1) + beta_(i-1)(p_(i-1) - omega_(i-1) * nu_(i-1))
                    nu.Multiply(-omega, temp);
                    vecP.Add(temp, temp2);
                    temp2.CopyTo(vecP);

                    vecP.Multiply(beta, vecP);
                    vecP.Add(residuals, temp2);
                    temp2.CopyTo(vecP);
                }
                else
                {
                    // p_i = r_(i-1)
                    residuals.CopyTo(vecP);
                }

                // SOLVE Mp~ = p_i // M = preconditioner
                preconditioner.Approximate(vecP, vecPdash);

                // nu_i = Ap~
                matrix.Multiply(vecPdash, nu);

                // alpha_i = rho_(i-1)/ (r~^T nu_i) = rho / dotproduct(r~ and nu_i)
                alpha = (currentRho * 1) / tempResiduals.DotProduct(nu);

                // s = r_(i-1) - alpha_i nu_i
                nu.Multiply(-alpha, temp);
                residuals.Add(temp, vecS);

                // Check if we're converged. If so then stop. Otherwise continue;
                // Calculate the temporary result.
                // Be careful not to change any of the temp vectors, except for
                // temp. Others will be used in the calculation later on.
                // x_i = x_(i-1) + alpha_i * p^_i + s^_i
                vecPdash.Multiply(alpha, temp);
                temp.Add(vecSdash, temp2);
                temp2.CopyTo(temp);
                temp.Add(result, temp2);
                temp2.CopyTo(temp);

                // Check convergence and stop if we are converged.
                if (iterator.DetermineStatus(iterationNumber, temp, input, vecS) != IterationStatus.Continue)
                {
                    temp.CopyTo(result);

                    // Calculate the true residual
                    CalculateTrueResidual(matrix, residuals, result, input);

                    // Now recheck the convergence
                    if (iterator.DetermineStatus(iterationNumber, result, input, residuals) != IterationStatus.Continue)
                    {
                        // We're all good now.
                        return;
                    }

                    // Continue the calculation
                    iterationNumber++;
                    continue;
                }

                // SOLVE Ms~ = s
                preconditioner.Approximate(vecS, vecSdash);

                // temp = As~
                matrix.Multiply(vecSdash, temp);

                // omega_i = temp^T s / temp^T temp
                omega = temp.DotProduct(vecS) / temp.DotProduct(temp);

                // x_i = x_(i-1) + alpha_i p^ + omega_i s^
                temp.Multiply(-omega, residuals);
                residuals.Add(vecS, temp2);
                temp2.CopyTo(residuals);

                vecSdash.Multiply(omega, temp);
                result.Add(temp, temp2);
                temp2.CopyTo(result);

                vecPdash.Multiply(alpha, temp);
                result.Add(temp, temp2);
                temp2.CopyTo(result);

                // for continuation it is necessary that omega_i != 0.0
                // If omega is only 1 ULP from zero then we fail.
                if (omega.AlmostEqualNumbersBetween(0, 1))
                {
                    // Omega-type breakdown
                    throw new NumericalBreakdownException();
                }

                if (iterator.DetermineStatus(iterationNumber, result, input, residuals) != IterationStatus.Continue)
                {
                    // Recalculate the residuals and go round again. This is done to ensure that
                    // we have the proper residuals.
                    // The residual calculation based on omega_i * s can be off by a factor 10. So here
                    // we calculate the real residual (which can be expensive) but we only do it if we're
                    // sufficiently close to the finish.
                    CalculateTrueResidual(matrix, residuals, result, input);
                }

                iterationNumber++;
            }
        }