Exemple #1
0
        public bool Solve()
        {
            Iterations = 0;
            int size = B.Length;

            // Based on the algorithm in "Matrix Computations" by Golum and Van Loan.
            R  = new double[size];
            P  = new double[size];
            AP = new double[size];

            if (X == null || UseXAsInitialGuess == false)
            {
                if (X == null)
                {
                    X = new double[size];
                }

                Array.Clear(X, 0, X.Length);
                Array.Copy(B, R, B.Length);
            }
            else
            {
                // hopefully is X is a decent initialization...
                InitializeR(R);
            }

            // [RMS] these were inside loop but they are constant!
            double norm  = BufferUtil.Dot(B, B);
            double root1 = Math.Sqrt(norm);

            // The first iteration.
            double rho0 = BufferUtil.Dot(R, R);

            // [RMS] If we were initialized w/ constraints already satisfied,
            //   then we are done! (happens for example in mesh deformations)
            if (rho0 < MathUtil.ZeroTolerance * root1)
            {
                return(true);
            }

            Array.Copy(R, P, R.Length);

            MultiplyF(P, AP);

            double alpha = rho0 / BufferUtil.Dot(P, AP);

            BufferUtil.MultiplyAdd(X, alpha, P);
            BufferUtil.MultiplyAdd(R, -alpha, AP);
            double rho1 = BufferUtil.Dot(R, R);

            // The remaining iterations.
            int iter;

            for (iter = 1; iter < MaxIterations; ++iter)
            {
                double root0 = Math.Sqrt(rho1);
                if (root0 <= MathUtil.ZeroTolerance * root1)
                {
                    break;
                }

                double beta = rho1 / rho0;
                UpdateP(P, beta, R);

                MultiplyF(P, AP);

                alpha = rho1 / BufferUtil.Dot(P, AP);

                // can compute these two steps simultaneously
                double RdotR = 0;
                gParallel.Evaluate(
                    () => { BufferUtil.MultiplyAdd(X, alpha, P); },
                    () => { RdotR = BufferUtil.MultiplyAdd_GetSqrSum(R, -alpha, AP); }
                    );

                rho0 = rho1;
                rho1 = RdotR;                 // BufferUtil.Dot(R, R);
            }

            //System.Console.WriteLine("{0} iterations", iter);
            Iterations = iter;
            return(iter < MaxIterations);
        }
Exemple #2
0
        /// <summary>
        /// standard CG solve
        /// </summary>
        public bool Solve()
        {
            Iterations = 0;
            if (B == null || MultiplyF == null)
            {
                throw new Exception("SparseSymmetricCGMultipleRHS.Solve(): Must set B and MultiplyF!");
            }

            int NRHS = B.Length;

            if (NRHS == 0)
            {
                throw new Exception("SparseSymmetricCGMultipleRHS.Solve(): Need at least one RHS vector in B");
            }

            int size = B[0].Length;

            // Based on the algorithm in "Matrix Computations" by Golum and Van Loan.
            R = BufferUtil.AllocNxM(NRHS, size);
            P = BufferUtil.AllocNxM(NRHS, size);
            W = BufferUtil.AllocNxM(NRHS, size);

            if (X == null || UseXAsInitialGuess == false)
            {
                if (X == null)
                {
                    X = BufferUtil.AllocNxM(NRHS, size);
                }

                for (int j = 0; j < NRHS; ++j)
                {
                    Array.Clear(X[j], 0, size);
                    Array.Copy(B[j], R[j], size);
                }
            }
            else
            {
                // hopefully is X is a decent initialization...
                InitializeR(R);
            }

            // [RMS] these were inside loop but they are constant!
            double[] norm = new double[NRHS];
            for (int j = 0; j < NRHS; ++j)
            {
                norm[j] = BufferUtil.Dot(B[j], B[j]);
            }

            double[] root1 = new double[NRHS];
            for (int j = 0; j < NRHS; ++j)
            {
                root1[j] = Math.Sqrt(norm[j]);
            }

            // The first iteration.
            double[] rho0 = new double[NRHS];
            for (int j = 0; j < NRHS; ++j)
            {
                rho0[j] = BufferUtil.Dot(R[j], R[j]);
            }

            // [RMS] If we were initialized w/ constraints already satisfied,
            //   then we are done! (happens for example in mesh deformations)
            bool[] converged  = new bool[NRHS];
            int    nconverged = 0;

            for (int j = 0; j < NRHS; ++j)
            {
                converged[j] = rho0[j] < (ConvergeTolerance * root1[j]);
                if (converged[j])
                {
                    nconverged++;
                }
            }
            if (nconverged == NRHS)
            {
                return(true);
            }

            for (int j = 0; j < NRHS; ++j)
            {
                Array.Copy(R[j], P[j], size);
            }

            MultiplyF(P, W);

            double[] alpha = new double[NRHS];
            for (int j = 0; j < NRHS; ++j)
            {
                alpha[j] = rho0[j] / BufferUtil.Dot(P[j], W[j]);
            }

            for (int j = 0; j < NRHS; ++j)
            {
                BufferUtil.MultiplyAdd(X[j], alpha[j], P[j]);
            }

            for (int j = 0; j < NRHS; ++j)
            {
                BufferUtil.MultiplyAdd(R[j], -alpha[j], W[j]);
            }

            double[] rho1 = new double[NRHS];
            for (int j = 0; j < NRHS; ++j)
            {
                rho1[j] = BufferUtil.Dot(R[j], R[j]);
            }

            double[] beta = new double[NRHS];

            var rhs = Interval1i.Range(NRHS);

            // The remaining iterations.
            int iter;

            for (iter = 1; iter < MaxIterations; ++iter)
            {
                bool done = true;
                for (int j = 0; j < NRHS; ++j)
                {
                    if (converged[j] == false)
                    {
                        double root0 = Math.Sqrt(rho1[j]);
                        if (root0 <= ConvergeTolerance * root1[j])
                        {
                            converged[j] = true;
                        }
                    }
                    if (converged[j] == false)
                    {
                        done = false;
                    }
                }
                if (done)
                {
                    break;
                }

                for (int j = 0; j < NRHS; ++j)
                {
                    beta[j] = rho1[j] / rho0[j];
                }

                UpdateP(P, beta, R, converged);

                MultiplyF(P, W);

                gParallel.ForEach(rhs, (j) =>
                {
                    if (converged[j] == false)
                    {
                        alpha[j] = rho1[j] / BufferUtil.Dot(P[j], W[j]);
                    }
                });

                // can do all these in parallel, but improvement is minimal
                gParallel.ForEach(rhs, (j) =>
                {
                    if (converged[j] == false)
                    {
                        BufferUtil.MultiplyAdd(X[j], alpha[j], P[j]);
                    }
                });
                gParallel.ForEach(rhs, (j) =>
                {
                    if (converged[j] == false)
                    {
                        rho0[j] = rho1[j];
                        rho1[j] = BufferUtil.MultiplyAdd_GetSqrSum(R[j], -alpha[j], W[j]);
                    }
                });
            }

            //System.Console.WriteLine("{0} iterations", iter);
            Iterations = iter;
            return(iter < MaxIterations);
        }