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 }
public void Initialize() { ToMeshV = new int[Mesh.MaxVertexID]; ToIndex = new int[Mesh.MaxVertexID]; N = 0; foreach (int vid in Mesh.VertexIndices()) { ToMeshV[N] = vid; ToIndex[vid] = N; N++; } Px = new double[N]; Py = new double[N]; Pz = new double[N]; nbr_counts = new int[N]; M = new SymmetricSparseMatrix(); for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; Vector3D v = Mesh.GetVertex(vid); Px[i] = v.x; Py[i] = v.y; Pz[i] = v.z; nbr_counts[i] = Mesh.GetVtxEdgeCount(vid); } // construct laplacian matrix for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; int n = nbr_counts[i]; double sum_w = 0; foreach (int nbrvid in Mesh.VtxVerticesItr(vid)) { int j = ToIndex[nbrvid]; int n2 = nbr_counts[j]; // weight options //double w = -1; double w = -1.0 / Math.Sqrt(n + n2); //double w = -1.0 / n; M.Set(i, j, w); sum_w += w; } sum_w = -sum_w; M.Set(vid, vid, sum_w); } // transpose(L) * L, but matrix is symmetric... if (UseSoftConstraintNormalEquations) { //M = M.Multiply(M); M = M.Square(); // only works if M is symmetric } // construct packed version of M matrix PackedM = new PackedSparseMatrix(M); // compute laplacian vectors of initial mesh positions MLx = new double[N]; MLy = new double[N]; MLz = new double[N]; M.Multiply(Px, MLx); M.Multiply(Py, MLy); M.Multiply(Pz, MLz); // zero out... for (int i = 0; i < Px.Length; ++i) { MLx[i] = 0; MLy[i] = 0; MLz[i] = 0; } // allocate memory for internal buffers Preconditioner = new DiagonalMatrix(N); WeightsM = new DiagonalMatrix(N); Cx = new double[N]; Cy = new double[N]; Cz = new double[N]; Bx = new double[N]; By = new double[N]; Bz = new double[N]; Sx = new double[N]; Sy = new double[N]; Sz = new double[N]; UpdateForSolve(); }
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 }