// Benchmarks for unsupported iterative solvers: GMRES, MINRES, IDRS, IDRSTABL, BiCGSTABL, DGMRES. #include #include #include #include using namespace Eigen; typedef double Scalar; typedef SparseMatrix SpMat; typedef Matrix Vec; // Generate a SPD sparse matrix (Laplacian-like with diagonal dominance). static SpMat generateSPD(int n, int bandwidth) { SpMat A(n, n); std::vector> trips; trips.reserve(n * (2 * bandwidth + 1)); for (int i = 0; i < n; ++i) { Scalar diag = 0; for (int j = std::max(0, i - bandwidth); j < std::min(n, i + bandwidth + 1); ++j) { if (i != j) { Scalar val = -1.0 / (1 + std::abs(i - j)); trips.emplace_back(i, j, val); diag -= val; } } trips.emplace_back(i, i, diag + 1.0); } A.setFromTriplets(trips.begin(), trips.end()); return A; } // Generate a general (non-symmetric) sparse matrix. static SpMat generateGeneral(int n, int bandwidth) { SpMat A(n, n); std::vector> trips; trips.reserve(n * (2 * bandwidth + 1)); for (int i = 0; i < n; ++i) { Scalar diag = 0; for (int j = std::max(0, i - bandwidth); j < std::min(n, i + bandwidth + 1); ++j) { if (i != j) { Scalar val = -0.5 / (1 + std::abs(i - j)); if (j > i) val *= 1.5; // asymmetry trips.emplace_back(i, j, val); diag += std::abs(val); } } trips.emplace_back(i, i, diag + 1.0); // diagonal dominance } A.setFromTriplets(trips.begin(), trips.end()); return A; } // --- GMRES --- static void BM_GMRES(benchmark::State& state) { int n = state.range(0); int bw = state.range(1); SpMat A = generateGeneral(n, bw); Vec b = Vec::Random(n); GMRES solver; solver.setMaxIterations(1000); solver.setTolerance(1e-10); solver.compute(A); for (auto _ : state) { Vec x = solver.solve(b); benchmark::DoNotOptimize(x.data()); benchmark::ClobberMemory(); } state.counters["iterations"] = solver.iterations(); } // --- DGMRES --- static void BM_DGMRES(benchmark::State& state) { int n = state.range(0); int bw = state.range(1); SpMat A = generateGeneral(n, bw); Vec b = Vec::Random(n); DGMRES solver; solver.setMaxIterations(1000); solver.setTolerance(1e-10); solver.compute(A); for (auto _ : state) { Vec x = solver.solve(b); benchmark::DoNotOptimize(x.data()); benchmark::ClobberMemory(); } state.counters["iterations"] = solver.iterations(); } // --- MINRES (SPD matrices) --- static void BM_MINRES(benchmark::State& state) { int n = state.range(0); int bw = state.range(1); SpMat A = generateSPD(n, bw); Vec b = Vec::Random(n); MINRES solver; solver.setMaxIterations(1000); solver.setTolerance(1e-10); solver.compute(A); for (auto _ : state) { Vec x = solver.solve(b); benchmark::DoNotOptimize(x.data()); benchmark::ClobberMemory(); } state.counters["iterations"] = solver.iterations(); } // --- IDRS --- static void BM_IDRS(benchmark::State& state) { int n = state.range(0); int bw = state.range(1); SpMat A = generateGeneral(n, bw); Vec b = Vec::Random(n); IDRS solver; solver.setMaxIterations(1000); solver.setTolerance(1e-10); solver.compute(A); for (auto _ : state) { Vec x = solver.solve(b); benchmark::DoNotOptimize(x.data()); benchmark::ClobberMemory(); } state.counters["iterations"] = solver.iterations(); } // --- BiCGSTABL --- static void BM_BiCGSTABL(benchmark::State& state) { int n = state.range(0); int bw = state.range(1); SpMat A = generateGeneral(n, bw); Vec b = Vec::Random(n); BiCGSTABL solver; solver.setMaxIterations(1000); solver.setTolerance(1e-10); solver.compute(A); for (auto _ : state) { Vec x = solver.solve(b); benchmark::DoNotOptimize(x.data()); benchmark::ClobberMemory(); } state.counters["iterations"] = solver.iterations(); } // --- Compare with CG (supported module, SPD only) --- static void BM_CG_Reference(benchmark::State& state) { int n = state.range(0); int bw = state.range(1); SpMat A = generateSPD(n, bw); Vec b = Vec::Random(n); ConjugateGradient solver; solver.setMaxIterations(1000); solver.setTolerance(1e-10); solver.compute(A); for (auto _ : state) { Vec x = solver.solve(b); benchmark::DoNotOptimize(x.data()); benchmark::ClobberMemory(); } state.counters["iterations"] = solver.iterations(); } // --- Compare with BiCGSTAB (supported module, general) --- static void BM_BiCGSTAB_Reference(benchmark::State& state) { int n = state.range(0); int bw = state.range(1); SpMat A = generateGeneral(n, bw); Vec b = Vec::Random(n); BiCGSTAB solver; solver.setMaxIterations(1000); solver.setTolerance(1e-10); solver.compute(A); for (auto _ : state) { Vec x = solver.solve(b); benchmark::DoNotOptimize(x.data()); benchmark::ClobberMemory(); } state.counters["iterations"] = solver.iterations(); } static void SolverSizes(::benchmark::Benchmark* b) { for (int n : {1000, 10000, 100000}) { for (int bw : {5, 20}) { b->Args({n, bw}); } } } BENCHMARK(BM_GMRES)->Apply(SolverSizes); BENCHMARK(BM_DGMRES)->Apply(SolverSizes); BENCHMARK(BM_MINRES)->Apply(SolverSizes); BENCHMARK(BM_IDRS)->Apply(SolverSizes); BENCHMARK(BM_BiCGSTABL)->Apply(SolverSizes); BENCHMARK(BM_CG_Reference)->Apply(SolverSizes); BENCHMARK(BM_BiCGSTAB_Reference)->Apply(SolverSizes);