public static void test_SparseCG()
        {
            int N = 10;
            SymmetricSparseMatrix M = new SymmetricSparseMatrix();

            double[] B = new double[N];
            for (int i = 0; i < N; ++i)
            {
                for (int j = i; j < N; ++j)
                {
                    if (i == j)
                    {
                        M.Set(i, j, 1);
                    }
                    else
                    {
                        M.Set(i, j, (double)(i + j) / 100.0);
                    }
                }
                B[i] = i + 1;
            }

            double[] X = new double[N];

            SparseSymmetricCG Solver = new SparseSymmetricCG()
            {
                B = B, MultiplyF = M.Multiply
            };

            Solver.Solve();
            string s = "";

            for (int i = 0; i < N; ++i)
            {
                s += " " + Solver.X[i];
            }
            System.Console.WriteLine(s);
        }
Beispiel #2
0
        // Result must be as large as Mesh.MaxVertexID
        public bool Solve(Vector3D[] Result)
        {
            UpdateForSolve();

            // use initial positions as initial solution.
            Array.Copy(Px, Sx, N);
            Array.Copy(Py, Sy, N);
            Array.Copy(Pz, Sz, N);


            Action <double[], double[]> CombinedMultiply = (X, B) => {
                M.Multiply(X, B);
                for (int i = 0; i < N; ++i)
                {
                    B[i] += WeightsM[i, i] * X[i];
                }
            };

            SparseSymmetricCG SolverX = new SparseSymmetricCG()
            {
                B                  = Bx, X = Sx,
                MultiplyF          = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply,
                UseXAsInitialGuess = true
            };
            SparseSymmetricCG SolverY = new SparseSymmetricCG()
            {
                B                  = By, X = Sy,
                MultiplyF          = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply,
                UseXAsInitialGuess = true
            };
            SparseSymmetricCG SolverZ = new SparseSymmetricCG()
            {
                B                  = Bz, X = Sz,
                MultiplyF          = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply,
                UseXAsInitialGuess = true
            };

            SparseSymmetricCG[] solvers = new SparseSymmetricCG[3] {
                SolverX, SolverY, SolverZ
            };
            bool[] ok      = new bool[3];
            int[]  indices = new int[3] {
                0, 1, 2
            };

            // preconditioned solve is slower =\
            //Action<int> SolveF = (i) => {  ok[i] = solvers[i].SolvePreconditioned(); };
            Action <int> SolveF = (i) => { ok[i] = solvers[i].Solve(); };

            gParallel.ForEach(indices, SolveF);

            if (ok[0] == false || ok[1] == false || ok[2] == false)
            {
                return(false);
            }

            for (int i = 0; i < N; ++i)
            {
                int vid = ToMeshV[i];
                Result[vid] = new Vector3D(Sx[i], Sy[i], Sz[i]);
            }

            // apply post-fixed constraints
            if (HavePostFixedConstraints)
            {
                foreach (var constraint in SoftConstraints)
                {
                    if (constraint.Value.PostFix)
                    {
                        int vid = constraint.Key;
                        Result[vid] = constraint.Value.Position;
                    }
                }
            }

            return(true);
        }
Beispiel #3
0
        public static void test_SparseCG_Precond()
        {
            // A test case where Jacobi preconditioner (ie M = diag(A)) provides some improvement
            // described in http://www.math.iit.edu/~fass/477577_Chapter_16.pdf

            int N = 10000;
            SymmetricSparseMatrix M = new SymmetricSparseMatrix();

            double[] B = new double[N];
            for (int i = 0; i < N; ++i)
            {
                for (int j = i; j < N; ++j)
                {
                    if (i == j)
                    {
                        M.Set(i, i, 0.5 + Math.Sqrt(i));
                    }
                    else if (Math.Abs(i - j) == 1)
                    {
                        M.Set(i, j, 1);
                    }
                    else if (Math.Abs(i - j) == 100)
                    {
                        M.Set(i, j, 1);
                    }
                }
                B[i] = 1;
            }

            SparseSymmetricCG Solver = new SparseSymmetricCG()
            {
                B = B, MultiplyF = M.Multiply
            };

            Solver.Solve();
            double[] BTest = new double[N];
            M.Multiply(Solver.X, BTest);
            double diff = BufferUtil.DistanceSquared(B, BTest);

            if (diff > MathUtil.ZeroTolerance)
            {
                System.Console.WriteLine("test_SparseCG: initial solve failed!");
            }

            PackedSparseMatrix PackedM = new PackedSparseMatrix(M);

            PackedM.Sort();
            SparseSymmetricCG Solver_PackedM = new SparseSymmetricCG()
            {
                B = B, MultiplyF = PackedM.Multiply
            };

            Solver_PackedM.Solve();
            PackedM.Multiply(Solver_PackedM.X, BTest);
            double diff_packed = BufferUtil.DistanceSquared(B, BTest);

            if (diff_packed > MathUtil.ZeroTolerance)
            {
                System.Console.WriteLine("test_SparseCG: Packed solve failed!");
            }

#if false
            SparseCholeskyDecomposition cholDecomp = new SparseCholeskyDecomposition(PackedM);
            cholDecomp.ComputeIncomplete();

            // factorization is filled with NaNs!! doing something wrong.

            double[] TmpX = new double[N], Y = new double[N];
            cholDecomp.Solve(BTest, TmpX, Y);

            // note: can also try just lower-triangular matrix - this is (L+D), Gauss-Seidel preconditioner?
            //   see http://www.math.iit.edu/~fass/477577_Chapter_16.pdf

            Action <double[], double[]> cholPrecond = (R, Z) => {
                cholDecomp.Solve(R, Z, Y);
            };

            SymmetricSparseMatrix diagPrecond = new SymmetricSparseMatrix(N);
            for (int k = 0; k < N; ++k)
            {
                diagPrecond[k, k] = 1.0 / M[k, k];
            }

            SparseSymmetricCG Solver_Precond = new SparseSymmetricCG()
            {
                B = B, MultiplyF = PackedM.Multiply, PreconditionMultiplyF = diagPrecond.Multiply
            };
            //SparseSymmetricCG Solver_Precond = new SparseSymmetricCG() { B = B, MultiplyF = PackedM.Multiply, PreconditionMultiplyF = cholPrecond };
            Solver_Precond.SolvePreconditioned();
            PackedM.Multiply(Solver_Precond.X, BTest);
            double diff_precond = BufferUtil.DistanceSquared(B, BTest);
            if (diff_precond > MathUtil.ZeroTolerance)
            {
                System.Console.WriteLine("test_SparseCG: cholesky-preconditioned solve failed!");
            }

            System.Console.WriteLine("Iterations regular {0}  precond {1}", Solver_PackedM.Iterations, Solver_Precond.Iterations);
            System.Console.WriteLine("Tol regular {0}  precond {1}", diff_packed, diff_precond);
#endif
        }
Beispiel #4
0
        public static void test_SparseCG()
        {
            Random r = new Random(31337);

            int N   = 100;
            var pts = TestUtil.RandomScalars(N, r, new Interval1d(1, 10));
            SymmetricSparseMatrix M = new SymmetricSparseMatrix();

            double[] B = new double[N];
            for (int i = 0; i < N; ++i)
            {
                for (int j = i; j < N; ++j)
                {
                    if (i == j)
                    {
                        M.Set(i, j, pts[i]);
                    }
                    else
                    {
                        M.Set(i, j, (double)(i + j) / 10.0);
                    }
                }
                B[i] = i + 1;
            }

            SparseSymmetricCG Solver = new SparseSymmetricCG()
            {
                B = B, MultiplyF = M.Multiply
            };

            Solver.Solve();
            double[] BTest = new double[N];
            M.Multiply(Solver.X, BTest);
            double diff = BufferUtil.DistanceSquared(B, BTest);

            if (diff > MathUtil.ZeroTolerance)
            {
                System.Console.WriteLine("test_SparseCG: initial solve failed!");
            }

            PackedSparseMatrix PackedM = new PackedSparseMatrix(M);

            PackedM.Sort();
            SparseSymmetricCG Solver_PackedM = new SparseSymmetricCG()
            {
                B = B, MultiplyF = PackedM.Multiply
            };

            Solver_PackedM.Solve();
            PackedM.Multiply(Solver_PackedM.X, BTest);
            double diff_packed = BufferUtil.DistanceSquared(B, BTest);

            if (diff_packed > MathUtil.ZeroTolerance)
            {
                System.Console.WriteLine("test_SparseCG: Packed solve failed!");
            }

#if false
            SparseCholeskyDecomposition decomp = new SparseCholeskyDecomposition(PackedM);
            decomp.ComputeIncomplete();
            PackedSparseMatrix choleskyPrecond = decomp.L.Square();

            SymmetricSparseMatrix diagPrecond = new SymmetricSparseMatrix(N);
            for (int k = 0; k < N; ++k)
            {
                diagPrecond[k, k] = 1.0 / M[k, k];
            }

            SparseSymmetricCG Solver_Precond = new SparseSymmetricCG()
            {
                B = B, MultiplyF = PackedM.Multiply, PreconditionMultiplyF = diagPrecond.Multiply
            };
            Solver_Precond.SolvePreconditioned();
            PackedM.Multiply(Solver_Precond.X, BTest);
            double diff_precond = BufferUtil.DistanceSquared(B, BTest);
            if (diff_precond > MathUtil.ZeroTolerance)
            {
                System.Console.WriteLine("test_SparseCG: cholesky-preconditioned solve failed!");
            }

            System.Console.WriteLine("Iterations regular {0}  precond {1}", Solver_PackedM.Iterations, Solver_Precond.Iterations);
            System.Console.WriteLine("Tol regular {0}  precond {1}", diff_packed, diff_precond);
#endif
        }
        // [RMS] this only tests some basic cases...
        public static void test_Laplacian()
        {
            // compact version
            DMesh3 mesh = new DMesh3(TestUtil.MakeRemeshedCappedCylinder(1.0), true);

            Debug.Assert(mesh.IsCompact);

            AxisAlignedBox3d bounds = mesh.GetBounds();

            TestUtil.WriteDebugMesh(mesh, "___CG_before.obj");

            List <IMesh> result_meshes = new List <IMesh>();

            // make uniform laplacian matrix
            int N = mesh.VertexCount;
            SymmetricSparseMatrix M = new SymmetricSparseMatrix();

            //DenseMatrix M = new DenseMatrix(N, N);
            double[] Px = new double[N], Py = new double[N], Pz = new double[N];

            int[] nbr_counts = new int[N];
            for (int vid = 0; vid < N; ++vid)
            {
                nbr_counts[vid] = mesh.GetVtxEdgeCount(vid);
            }

            int        ti          = MeshQueries.FindNearestTriangle_LinearSearch(mesh, new Vector3d(2, 5, 2));
            int        v_pin       = mesh.GetTriangle(ti).a;
            List <int> constraints = new List <int>()
            {
                v_pin
            };
            double consW      = 10;
            double consBottom = 10;

            foreach (int vid in constraints)
            {
                result_meshes.Add(TestUtil.MakeMarker(mesh.GetVertex(vid), (vid == 0) ? 0.2f : 0.1f, Colorf.Red));
            }

            for (int vid = 0; vid < N; ++vid)
            {
                int      n = nbr_counts[vid];
                Vector3d v = mesh.GetVertex(vid), c = Vector3d.Zero;

                Px[vid] = v.x; Py[vid] = v.y; Pz[vid] = v.z;

                bool bottom = (v.y - bounds.Min.y) < 0.01f;

                double sum_w = 0;
                foreach (int nbrvid in mesh.VtxVerticesItr(vid))
                {
                    int n2 = nbr_counts[nbrvid];

                    // weight options
                    //double w = -1;
                    double w = -1.0 / Math.Sqrt(n + n2);
                    //double w = -1.0 / n;

                    M.Set(vid, nbrvid, w);

                    c     += w * mesh.GetVertex(nbrvid);
                    sum_w += w;
                }
                sum_w = -sum_w;

                M.Set(vid, vid, sum_w);

                // add soft constraints
                if (constraints.Contains(vid))
                {
                    M.Set(vid, vid, sum_w + consW);
                }
                else if (bottom)
                {
                    M.Set(vid, vid, sum_w + consBottom);
                }
            }

            // compute laplacians
            double[] MLx = new double[N], MLy = new double[N], MLz = new double[N];
            M.Multiply(Px, MLx);
            M.Multiply(Py, MLy);
            M.Multiply(Pz, MLz);


            DiagonalMatrix Preconditioner = new DiagonalMatrix(N);

            for (int i = 0; i < N; i++)
            {
                Preconditioner.Set(i, i, 1.0 / M[i, i]);
            }


            MLy[v_pin] += consW * 0.5f;
            MLx[v_pin] += consW * 0.5f;
            MLz[v_pin] += consW * 0.5f;

            bool useXAsGuess = true;
            // preconditioned
            SparseSymmetricCG SolverX = new SparseSymmetricCG()
            {
                B = MLx, X = Px, MultiplyF = M.Multiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = useXAsGuess
            };
            // initial solution
            SparseSymmetricCG SolverY = new SparseSymmetricCG()
            {
                B = MLy, X = Py, MultiplyF = M.Multiply, UseXAsInitialGuess = useXAsGuess
            };
            // neither of those
            SparseSymmetricCG SolverZ = new SparseSymmetricCG()
            {
                B = MLz, MultiplyF = M.Multiply
            };

            bool bx = SolverX.Solve();
            bool by = SolverY.Solve();
            bool bz = SolverZ.Solve();

            for (int vid = 0; vid < mesh.VertexCount; ++vid)
            {
                Vector3d newV = new Vector3d(SolverX.X[vid], SolverY.X[vid], SolverZ.X[vid]);
                mesh.SetVertex(vid, newV);
            }

            result_meshes.Add(mesh);
            TestUtil.WriteDebugMeshes(result_meshes, "___CG_result.obj");
        }