public override IterativeStatistics Solve(ILinearTransformation matrix, IPreconditioner preconditioner, IVectorView rhs,
                                                  IVector solution, bool initialGuessIsZero, Func <IVector> zeroVectorInitializer)
        {
            //TODO: find a better way to handle optimizations for the case x0=0, than using an initialGuessIsZero flag
            Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length);
            Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length);

            this.Matrix         = matrix;
            this.Preconditioner = preconditioner;
            this.Rhs            = rhs;

            // Initial solution and rhs (r = b - A * x)
            this.solution = solution;
            if (ReorthoCache.Directions.Count > 0)
            {
                if (!initialGuessIsZero)
                {
                    solution.Clear();
                }
                CalculateInitialSolutionFromStoredDirections(rhs, solution);
                residual = ExactResidual.Calculate(matrix, rhs, solution);
            }
            else             // preferably call base method
            {
                // r = b - A * x
                if (initialGuessIsZero)
                {
                    residual = rhs.Copy();
                }
                else
                {
                    residual = ExactResidual.Calculate(matrix, rhs, solution);
                }
            }

            // Initialize vectors
            //TODO: Pehaps I can just clear them from previous iterations
            precondResidual      = zeroVectorInitializer();
            direction            = zeroVectorInitializer();
            matrixTimesDirection = zeroVectorInitializer();

            int maxIterations = MaxIterationsProvider.GetMaxIterations(matrix.NumColumns);

            return(SolveInternal(maxIterations, zeroVectorInitializer));
        }
        /// <summary>
        /// See <see cref="IPcgResidualUpdater.UpdateResidual(PcgAlgorithmBase, IVector)"/>
        /// </summary>
        public void UpdateResidual(PcgAlgorithmBase pcg, IVector residual)
        {
            //TODO: perhaps this should be done in an Initialize() method
            if (numIterationsBeforeCorrection == int.MinValue)
            {
                numIterationsBeforeCorrection = (int)Math.Floor(Math.Sqrt(pcg.Rhs.Length));
            }

            if ((pcg.Iteration % numIterationsBeforeCorrection == 0) && (pcg.Iteration != 0)) //The first iteration uses the correct residual.
            {
                // Calculate the exact residual: r = b - A * x
                ExactResidual.Calculate(pcg.Matrix, pcg.Rhs, pcg.Solution, residual);
            }
            else
            {
                // Normally the residual vector is updated as: r = r - α * A*d
                residual.AxpyIntoThis(pcg.MatrixTimesDirection, -pcg.StepSize);
            }
        }
Esempio n. 3
0
        public void UpdateResidual(CGAlgorithm cg, IVector residual, out double resDotRes)
        {
            // Update the residual vector normally: r = r - α * A*d
            residual.AxpyIntoThis(cg.MatrixTimesDirection, -cg.StepSize);
            resDotRes = residual.DotProduct(residual); //TODO: it is weird that this sets resDotRes and cg.ResDotRes

            // Check if the CG will converge. TODO: Remove duplicate comutations: this check will also be done by CG later.
            double residualNormRatio = convergence.EstimateResidualNormRatio(cg); // let's pray that ICGResidualConvergence does not mutate any fields
            bool   hasConverged      = residualNormRatio <= residualTolerance;

            // Avoid premature convergence by calculating th exact residual.
            if (hasConverged)
            {
                // Exact residual: r = b - A * x
                ExactResidual.Calculate(cg.Matrix, cg.Rhs, cg.Solution, residual);

                // Recalculate the r * r
                resDotRes = residual.DotProduct(residual);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Solves the linear system A * x = b, where A = <paramref name="matrix"/> and b = <paramref name="rhs"/>.
        /// Initially x = <paramref name="initialGuess"/> and then it converges to the solution.
        /// </summary>
        /// <param name="matrix">
        /// Represents the matrix A of the linear system A * x = b, which must be symmetric positive definite.
        /// </param>
        /// <param name="rhs">
        /// The right hand side vector b of the linear system A * x = b. Constraints:
        /// <paramref name="rhs"/>.<see cref="IIndexable1D.Length"/>
        /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumRows"/>.
        /// </param>
        /// <param name="solution">
        /// The vector from which to start refining the solution vector x. Constraints:
        /// <paramref name="solution"/>.<see cref="IIndexable1D.Length"/>
        /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumColumns"/>.
        /// </param>
        /// <param name="initialGuessIsZero">
        /// If <paramref name="solution"/> is 0, then set <paramref name="initialGuessIsZero"/> to true to avoid performing the
        /// operation b-A*0 before starting.
        /// </param>
        /// <exception cref="NonMatchingDimensionsException">
        /// Thrown if <paramref name="rhs"/> or <paramref name="solution"/> violate the described constraints.
        /// </exception>
        public IterativeStatistics Solve(ILinearTransformation matrix, IVectorView rhs, IVector solution,
                                         bool initialGuessIsZero) //TODO: find a better way to handle the case x0=0
        {
            //TODO: these will also be checked by the matrix vector multiplication.
            Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length);
            Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length);

            this.Matrix   = matrix;
            this.Rhs      = rhs;
            this.solution = solution;

            // r = b - A * x
            if (initialGuessIsZero)
            {
                residual = rhs.Copy();
            }
            else
            {
                residual = ExactResidual.Calculate(matrix, rhs, solution);
            }

            return(SolveInternal(maxIterationsProvider.GetMaxIterations(matrix.NumColumns)));
        }
        /// <summary>
        /// Solves the linear system A * x = b by solving the preconditioned system inv(P) * A * inv(P)^T * y = inv(P) * b,
        /// where A = <paramref name="matrix"/>, b = <paramref name="rhsVector"/>, x is the solution, y = P^T * x,
        /// P*P^T = <paramref name="preconditioner"/>.
        /// Initially x = <paramref name="initialGuess"/> and then it converges to the solution.
        /// </summary>
        /// <param name="matrix">
        /// Represents the matrix A of the linear system A * x = b, which must be symmetric positive definite.
        /// </param>
        /// <param name="rhs">
        /// The right hand side vector b of the linear system A * x = b. Constraints:
        /// <paramref name="rhs"/>.<see cref="IIndexable1D.Length"/>
        /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumRows"/>.
        /// </param>
        /// <param name="preconditioner">
        /// A preconditioner matrix that is also symmetric positive definite and has the same dimensions as A.
        /// </param>
        /// <param name="solution">
        /// The vector from which to start refining the solution vector x. Constraints:
        /// <paramref name="solution"/>.<see cref="IIndexable1D.Length"/>
        /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumColumns"/>.
        /// </param>
        /// <param name="initialGuessIsZero">
        /// If <paramref name="solution"/> is 0, then set <paramref name="initialGuessIsZero"/> to true to avoid performing the
        /// operation b-A*0 before starting.
        /// </param>
        /// <exception cref="NonMatchingDimensionsException">
        /// Thrown if <paramref name="rhs"/> or <paramref name="solution"/> violate the described constraints.
        /// </exception>
        public virtual IterativeStatistics Solve(ILinearTransformation matrix, IPreconditioner preconditioner, IVectorView rhs,
                                                 IVector solution, bool initialGuessIsZero, Func <IVector> zeroVectorInitializer)
        {
            //TODO: find a better way to handle optimizations for the case x0=0, than using an initialGuessIsZero flag

            Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length);
            Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length);

            this.Matrix         = matrix;
            this.Preconditioner = preconditioner;
            this.Rhs            = rhs;
            this.solution       = solution;

            // r = b - A * x
            if (initialGuessIsZero)
            {
                residual = rhs.Copy();
            }
            else
            {
                residual = ExactResidual.Calculate(matrix, rhs, solution);
            }
            return(SolveInternal(MaxIterationsProvider.GetMaxIterations(matrix.NumColumns), zeroVectorInitializer));
        }
Esempio n. 6
0
        public IterativeStatistics Solve(ILinearTransformation matrix, IPreconditioner preconditioner, IVectorView rhs, IVector solution,
                                         bool initialGuessIsZero, Func <IVector> zeroVectorInitializer)
        {
            Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length);
            Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length);

            var innerIterations = innerIterationsProvider.GetMaxIterations(matrix.NumRows);

            IVector[] v              = new Vector[innerIterations + 1];
            var       y              = Vector.CreateZero(innerIterations + 1);
            var       c              = Vector.CreateZero(innerIterations + 1);
            var       s              = Vector.CreateZero(innerIterations + 1);
            var       delta          = 0.001;
            double    residualNorm   = double.MaxValue;
            var       usedIterations = 0;

            if (initialGuessIsZero)
            {
                residual = rhs.Copy();
            }
            else
            {
                residual = ExactResidual.Calculate(matrix, rhs, solution);
            }

            for (var iteration = 0; iteration < maximumIterations; iteration++)
            {
                preconditioner.SolveLinearSystem(residual, residual);
                //var residual = ExactResidual.Calculate(matrix, rhs, solution);

                residualNorm = residual.Norm2();

                double residualTolerance;
                if (iteration == 0)
                {
                    residualTolerance = residualNorm * relativeTolerance;
                }

                v[0] = residual.Scale(1 / residualNorm);

                var g = Vector.CreateZero(innerIterations + 1);
                g[0] = residualNorm;
                var hessenbergMatrix = Matrix.CreateZero(innerIterations + 1, innerIterations);

                var indexIteration = 0;
                for (int innerIteration = 0; innerIteration < innerIterations; innerIteration++)
                {
                    indexIteration        = innerIteration;
                    v[innerIteration + 1] = Vector.CreateZero(v[innerIteration].Length);

                    matrix.Multiply(v[innerIteration], v[innerIteration + 1]);
                    preconditioner.SolveLinearSystem(v[innerIteration + 1], v[innerIteration + 1]);

                    var av = v[innerIteration + 1].Norm2();

                    for (var j = 0; j <= innerIteration; j++)
                    {
                        hessenbergMatrix[j, innerIteration] = v[j].DotProduct(v[innerIteration + 1]);
                        v[innerIteration + 1] = v[innerIteration + 1].Subtract(v[j].Scale(hessenbergMatrix[j, innerIteration]));
                    }

                    hessenbergMatrix[innerIteration + 1, innerIteration] = v[innerIteration + 1].Norm2();


                    if (Math.Abs(av + delta * hessenbergMatrix[innerIteration + 1, innerIteration] - av) < 10e-9)
                    {
                        for (int j = 0; j <= innerIteration; j++)
                        {
                            var htmp = v[j].DotProduct(v[innerIteration + 1]);
                            hessenbergMatrix[j, innerIteration] += htmp;
                            v[innerIteration + 1].LinearCombinationIntoThis(1.0, v[j], -htmp);
                        }

                        hessenbergMatrix[innerIteration + 1, innerIteration] = v[innerIteration + 1].Norm2();
                    }

                    if (Math.Abs(hessenbergMatrix[innerIteration + 1, innerIteration]) > 10e-17)
                    {
                        v[innerIteration + 1].ScaleIntoThis(1 / hessenbergMatrix[innerIteration + 1, innerIteration]);
                    }

                    if (innerIteration > 0)
                    {
                        y = hessenbergMatrix.GetColumn(innerIteration).GetSubvector(0, innerIteration + 2);

                        for (int i = 0; i <= innerIteration - 1; i++)
                        {
                            y = CalculateGivensRotation(c[i], s[i], i, y);
                        }
                        hessenbergMatrix.SetSubcolumn(innerIteration, y);
                    }

                    var mu = Math.Sqrt(hessenbergMatrix[innerIteration, innerIteration] *
                                       hessenbergMatrix[innerIteration, innerIteration] +
                                       hessenbergMatrix[innerIteration + 1, innerIteration] *
                                       hessenbergMatrix[innerIteration + 1, innerIteration]);
                    c[innerIteration] = hessenbergMatrix[innerIteration, innerIteration] / mu;
                    s[innerIteration] = -hessenbergMatrix[innerIteration + 1, innerIteration] / mu;

                    hessenbergMatrix[innerIteration, innerIteration] =
                        c[innerIteration] * hessenbergMatrix[innerIteration, innerIteration] -
                        s[innerIteration] * hessenbergMatrix[innerIteration + 1, innerIteration];

                    hessenbergMatrix[innerIteration + 1, innerIteration] = 0.0;
                    g = CalculateGivensRotation(c[innerIteration], s[innerIteration], innerIteration, g);

                    residualNorm = Math.Abs(g[innerIteration + 1]);
                    usedIterations++;

                    if (residualNorm <= relativeTolerance && residualNorm <= absoluteTolerance)
                    {
                        break;
                    }
                }

                indexIteration = indexIteration - 1;

                y[indexIteration + 1] = g[indexIteration + 1] / hessenbergMatrix[indexIteration + 1, indexIteration + 1];
                for (int i = indexIteration; i >= 0; i--)
                {
                    y[i] = (g[i] - (hessenbergMatrix.GetRow(i).GetSubvector(i + 1, indexIteration + 2)
                                    .DotProduct(y.GetSubvector(i + 1, indexIteration + 2)))) / hessenbergMatrix[i, i];
                }


                for (int i = 0; i < matrix.NumRows; i++)
                {
                    var subV = Vector.CreateZero(indexIteration + 2);
                    for (int j = 0; j < indexIteration + 2; j++)
                    {
                        subV[j] = v[j][i];
                    }

                    solution.Set(i, solution[i] + subV.DotProduct(y.GetSubvector(0, indexIteration + 2)));
                }

                if (residualNorm <= relativeTolerance && residualNorm <= absoluteTolerance)
                {
                    break;
                }
            }
            return(new IterativeStatistics()
            {
                HasConverged = residualNorm <= relativeTolerance && residualNorm <= absoluteTolerance,
                AlgorithmName = name,
                NumIterationsRequired = usedIterations,
                ResidualNormRatioEstimation = residualNorm
            });
        }