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 }
// Result must be as large as Mesh.MaxVertexID public bool Solve(Vector3D[] Result) { if (WeightsM == null) { Initialize(); // force initialize... } 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) => { // packed multiply is 3-4x faster... //M.Multiply(X, B); PackedM.Multiply(X, B); for (int i = 0; i < N; ++i) { B[i] += WeightsM.D[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); }
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 }