Пример #1
0
        public static Matrix InverseAlt(Matrix matrix, ref Double timeS, ref double timeP)
        {
            if (!matrix.isSquare)
            {
                Exception e = new Exception("Matrix must be square!");
                throw e;
            }

            benchmark bm = new benchmark();

            bm.start();
            int    n      = matrix.dim1;
            Matrix result = Matrix.zeroLike(matrix);

            int[]  perm;
            int    toggle;
            Matrix lum = LUPDecompose(matrix, out perm, out toggle);

            if (lum == null)
            {
                return(Matrix.zeroLike(matrix)); //throw new Exception("Unable to compute inverse");
            }
            Double det = Determinant(lum, perm, toggle);

            if (det == 0) // not invertible
            {
                // still return for the sake of simplicity
                // Zero matrix * any matrix = zero matrix
                // so it's never a valid answer
                return(Matrix.zeroLike(matrix));
            }
            bm.pause();
            timeS += bm.getElapsedSeconds();

            bm.start();
            double[] b = new double[n];
            for (int i = 0; i < n; ++i)
            {
                for (int j = 0; j < n; ++j)
                {
                    if (i == perm[j])
                    {
                        b[j] = 1.0;
                    }
                    else
                    {
                        b[j] = 0.0;
                    }
                }
                double[] x = HelperSolve(lum, b);
                for (int j = 0; j < n; ++j)
                {
                    result[j, i] = x[j];
                }
            }
            timeP += bm.getElapsedSeconds();
            return(result);
        }
Пример #2
0
        // return true if it converges. Output: solution matrix, errors, loops it took
        public static Boolean solve(Matrix A, Matrix b, out Matrix x, out Matrix err, out int loops)
        {
            // check sanity
            if (!A.isSquare || !b.isColumn || (A.Height != b.Height))
            {
                Exception e = new Exception("Matrix A must be square! Matrix b must be a column matrix with the same height as matrix A!");
                throw e;
            }

            // follow samples in Wikipedia step by step https://en.wikipedia.org/wiki/Gauss%E2%80%93Seidel_method

            benchmark bm = new benchmark(), bm2 = new benchmark(), bm3 = new benchmark();
            double    sequential = 0, parallel = 0;

            bm.start();

            bm2.start();
            // decompose A into the sum of a lower triangular component L* and a strict upper triangular component U
            int    size = A.Height;
            Matrix L, U;

            Matrix.Decompose(A, out L, out U);
            sequential += bm2.getElapsedSeconds();

            // Inverse matrix L*
            Matrix L_1 = Matrix.InverseAlt(L, ref sequential, ref parallel);

            // Main iteration: x (at step k+1) = T * x (at step k) + C
            // where T = - (inverse of L*) * U, and C = (inverse of L*) * b

            bm2.start();
            // init necessary variables
            x = Matrix.zeroLike(b); // at step k
            Matrix new_x;           // at step k + 1

            sequential += bm2.getElapsedSeconds();
            bm2.start();
            Matrix T = -L_1 * U;
            Matrix C = L_1 * b;

            parallel += bm2.getElapsedSeconds();
            // Console.WriteLine(T.ToString(0.00001));
            // Console.WriteLine(C.ToString(0.00001));

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

            sequential += bm2.getElapsedSeconds();
            bm2.start();
            for (; loops < loopLimit; loops++)
            {
                new_x = T * x + C; // yup, only one line
                // Console.WriteLine("Loop #" + loops);
                // Console.WriteLine(new_x.ToString(0.00001));

                // consider it's converged if it changes less than threshold (1e-15)
                if (converge = Matrix.AllClose(new_x, x, 1e-15))
                {
                    x = new_x;
                    loops++;
                    break;
                }

                // save result
                x = new_x;
            }
            parallel += bm2.getElapsedSeconds();

            bm2.start();
            // round the result slightly
            x.Round(1e-14);
            err = A * x - b;
            err.Round(1e-14);
            sequential += bm2.getElapsedSeconds();

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

            return(converge);
        }