94 levels_.emplace_back();
96 for (
int L = 0; L + 1 < prm_.
maxLevels; ++L) {
97 finalizeSmoother(levels_[
static_cast<std::size_t
>(L)]);
98 if (levels_[
static_cast<std::size_t
>(L)].A.
n <= prm_.
coarsest)
101 if (!coarsen(levels_[
static_cast<std::size_t
>(L)], next))
103 levels_.push_back(std::move(next));
105 finalizeSmoother(levels_.back());
106 for (
auto& lv : levels_)
111 void apply(
const std::vector<double>& r, std::vector<double>& z)
const {
112 Level& l0 = levels_[0];
114 std::fill(l0.
x.begin(), l0.
x.end(), 0.0);
119 int numLevels()
const {
return static_cast<int>(levels_.size()); }
120 Index size(
int L = 0)
const {
return levels_[
static_cast<std::size_t
>(L)].A.
n; }
125 double nnz0 =
static_cast<double>(levels_[0].A.coef.size() + levels_[0].A.diag.size());
127 for (
auto& lv : levels_)
128 tot +=
static_cast<double>(lv.A.coef.size() + lv.A.diag.size());
129 return (nnz0 > 0) ? tot / nnz0 : 0.0;
148 const std::vector<Level>&
levels()
const {
return levels_; }
153 mutable std::vector<Level> levels_;
155 static void allocScratch(Level& lv) {
156 const std::size_t n =
static_cast<std::size_t
>(lv.A.n);
159 lv.res.assign(n, 0.0);
160 lv.t0.assign(n, 0.0);
161 lv.t1.assign(n, 0.0);
165 void finalizeSmoother(Level& lv) {
166 const std::size_t n =
static_cast<std::size_t
>(lv.A.n);
167 lv.invDiag.assign(n, 0.0);
168 for (std::size_t i = 0; i < n; ++i) {
169 const double d = lv.A.diag[i];
170 lv.invDiag[i] = (std::fabs(d) > 1e-300) ? 1.0 / d : 0.0;
176 std::vector<double> v(n, 0.0), w(n, 0.0);
177 for (std::size_t i = 0; i < n; ++i) {
182 std::uint64_t z =
static_cast<std::uint64_t
>(i) + 0x9E3779B97F4A7C15ULL;
183 z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL;
184 z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL;
186 v[i] = (z & 1ULL) ? 1.0 : -1.0;
188 double nrm = std::sqrt(dot(v, v));
196 for (
int k = 0; k < prm_.
eigIters; ++k) {
198 for (std::size_t i = 0; i < n; ++i)
199 w[i] *= lv.invDiag[i];
201 const double wn = std::sqrt(dot(w, w));
204 for (std::size_t i = 0; i < n; ++i)
207 lv.lmax = (lam > 0.0) ? lam : 1.0;
212 bool coarsen(Level& lv, Level& next) {
213 const Index n = lv.A.n;
215 const Index nNodes = n / s;
219 std::vector<std::map<Index, double>> blk(
static_cast<std::size_t
>(nNodes));
220 std::vector<double> ddiag(
static_cast<std::size_t
>(nNodes), 0.0);
221 for (Index i = 0; i < n; ++i) {
222 const Index I = i / s;
223 ddiag[
static_cast<std::size_t
>(I)] += lv.A.diag[
static_cast<std::size_t
>(i)] *
224 lv.A.diag[
static_cast<std::size_t
>(i)];
225 for (Index k = lv.A.start[
static_cast<std::size_t
>(i)];
226 k < lv.A.start[
static_cast<std::size_t
>(i) + 1]; ++k) {
227 const Index J = lv.A.nbr[
static_cast<std::size_t
>(k)] / s;
228 const double c = lv.A.coef[
static_cast<std::size_t
>(k)];
230 ddiag[
static_cast<std::size_t
>(I)] += c * c;
232 blk[
static_cast<std::size_t
>(I)][J] += c * c;
236 std::vector<std::vector<Index>> strong(
static_cast<std::size_t
>(nNodes));
240 for (Index I = 0; I < nNodes; ++I)
241 for (
auto& [J, fro2] : blk[static_cast<std::size_t>(I)])
242 if (fro2 >= th2 * std::sqrt(ddiag[static_cast<std::size_t>(I)] *
243 ddiag[static_cast<std::size_t>(J)]))
244 strong[static_cast<std::size_t>(I)].push_back(J);
246 const auto& s = strong[
static_cast<std::size_t
>(I)];
247 return std::binary_search(s.begin(), s.end(), J);
251 std::vector<Index> agg(
static_cast<std::size_t
>(nNodes), -1);
255 for (Index I = 0; I < nNodes; ++I) {
256 if (agg[
static_cast<std::size_t
>(I)] != -1)
259 for (Index J : strong[static_cast<std::size_t>(I)])
260 if (agg[static_cast<std::size_t>(J)] != -1) {
266 agg[
static_cast<std::size_t
>(I)] = nAgg;
267 for (Index J : strong[static_cast<std::size_t>(I)])
268 agg[static_cast<std::size_t>(J)] = nAgg;
272 for (Index I = 0; I < nNodes; ++I) {
273 if (agg[
static_cast<std::size_t
>(I)] != -1)
277 for (Index J : strong[static_cast<std::size_t>(I)]) {
278 const Index a = agg[
static_cast<std::size_t
>(J)];
281 const double w = blk[
static_cast<std::size_t
>(I)][J];
288 agg[
static_cast<std::size_t
>(I)] = best;
292 for (Index I = 0; I < nNodes; ++I) {
293 if (agg[
static_cast<std::size_t
>(I)] != -1)
295 agg[
static_cast<std::size_t
>(I)] = nAgg;
296 for (Index J : strong[static_cast<std::size_t>(I)])
297 if (agg[static_cast<std::size_t>(J)] == -1)
298 agg[static_cast<std::size_t>(J)] = nAgg;
301 if (nAgg <= 1 || nAgg == nNodes)
307 std::vector<Index> cnt(
static_cast<std::size_t
>(nAgg), 0);
308 for (Index I = 0; I < nNodes; ++I)
309 ++cnt[
static_cast<std::size_t
>(agg[
static_cast<std::size_t
>(I)])];
310 std::vector<double> invSqrtCnt(
static_cast<std::size_t
>(nAgg));
311 for (Index a = 0; a < nAgg; ++a)
312 invSqrtCnt[
static_cast<std::size_t
>(a)] =
313 1.0 / std::sqrt(
static_cast<double>(cnt[
static_cast<std::size_t
>(a)]));
314 const Index ncoarse = nAgg * s;
325 auto p0col = [&](
Index i) -> Index {
326 const Index I = i / s, d = i % s;
327 return agg[
static_cast<std::size_t
>(I)] * s + d;
329 auto p0val = [&](
Index i) ->
double {
330 return invSqrtCnt[
static_cast<std::size_t
>(agg[
static_cast<std::size_t
>(i / s)])];
332 std::vector<Index> Pstart(
static_cast<std::size_t
>(n) + 1, 0), Pcol;
333 std::vector<double> Pval;
334 std::map<Index, double> row;
335 for (Index i = 0; i < n; ++i) {
336 const Index I = i / s;
338 double dF = lv.A.diag[
static_cast<std::size_t
>(i)];
339 for (Index k = lv.A.start[
static_cast<std::size_t
>(i)];
340 k < lv.A.start[
static_cast<std::size_t
>(i) + 1]; ++k) {
341 const Index J = lv.A.nbr[
static_cast<std::size_t
>(k)] / s;
342 if (J != I && !isStrong(I, J))
343 dF += lv.A.coef[
static_cast<std::size_t
>(k)];
346 row[p0col(i)] += p0val(i);
348 const double f = (std::fabs(dF) > 1e-300) ? (-sc / dF) : 0.0;
349 row[p0col(i)] += f * dF * p0val(i);
350 for (Index k = lv.A.start[
static_cast<std::size_t
>(i)];
351 k < lv.A.start[
static_cast<std::size_t
>(i) + 1]; ++k) {
352 const Index j = lv.A.nbr[
static_cast<std::size_t
>(k)];
353 const Index J = j / s;
354 if (J != I && !isStrong(I, J))
356 row[p0col(j)] += f * lv.A.coef[
static_cast<std::size_t
>(k)] * p0val(j);
358 for (
auto& [c, val] : row)
363 Pstart[
static_cast<std::size_t
>(i) + 1] =
static_cast<Index>(Pcol.size());
369 std::vector<std::map<Index, double>> Ac(
static_cast<std::size_t
>(ncoarse));
370 std::map<Index, double> apRow;
371 for (Index i = 0; i < n; ++i) {
373 const double di = lv.A.diag[
static_cast<std::size_t
>(i)];
374 for (Index k = Pstart[
static_cast<std::size_t
>(i)];
375 k < Pstart[static_cast<std::size_t>(i) + 1]; ++k)
376 apRow[Pcol[
static_cast<std::size_t
>(k)]] += di * Pval[
static_cast<std::size_t
>(k)];
377 for (Index k = lv.A.start[
static_cast<std::size_t
>(i)];
378 k < lv.A.start[
static_cast<std::size_t
>(i) + 1]; ++k) {
379 const Index j = lv.A.nbr[
static_cast<std::size_t
>(k)];
380 const double c = lv.A.coef[
static_cast<std::size_t
>(k)];
381 for (Index kk = Pstart[
static_cast<std::size_t
>(j)];
382 kk < Pstart[static_cast<std::size_t>(j) + 1]; ++kk)
383 apRow[Pcol[
static_cast<std::size_t
>(kk)]] += c * Pval[
static_cast<std::size_t
>(kk)];
385 for (Index k = Pstart[
static_cast<std::size_t
>(i)];
386 k < Pstart[static_cast<std::size_t>(i) + 1]; ++k) {
387 const Index c1 = Pcol[
static_cast<std::size_t
>(k)];
388 const double p1 = Pval[
static_cast<std::size_t
>(k)];
389 auto& r1 = Ac[
static_cast<std::size_t
>(c1)];
390 for (
auto& [c2, apv] : apRow)
397 next.A.diag.assign(
static_cast<std::size_t
>(ncoarse), 0.0);
398 next.A.start.assign(
static_cast<std::size_t
>(ncoarse) + 1, 0);
401 for (Index c = 0; c < ncoarse; ++c) {
402 for (
auto& [c2, val] : Ac[static_cast<std::size_t>(c)]) {
404 next.A.diag[
static_cast<std::size_t
>(c)] = val;
405 }
else if (val != 0.0) {
406 next.A.nbr.push_back(c2);
407 next.A.coef.push_back(val);
410 next.A.start[
static_cast<std::size_t
>(c) + 1] =
static_cast<Index>(next.A.nbr.size());
414 lv.Pstart = std::move(Pstart);
415 lv.Pcol = std::move(Pcol);
416 lv.Pval = std::move(Pval);
422 void vcycle(
int L)
const {
423 Level& lv = levels_[
static_cast<std::size_t
>(L)];
424 if (L + 1 ==
static_cast<int>(levels_.size())) {
428 smooth(lv, prm_.
pre);
430 lv.A.apply(lv.x, lv.res);
431 for (std::size_t i = 0; i < lv.res.size(); ++i)
432 lv.res[i] = lv.b[i] - lv.res[i];
434 Level& cl = levels_[
static_cast<std::size_t
>(L + 1)];
435 std::fill(cl.b.begin(), cl.b.end(), 0.0);
436 for (Index i = 0; i < lv.A.n; ++i)
437 for (Index k = lv.Pstart[
static_cast<std::size_t
>(i)];
438 k < lv.Pstart[
static_cast<std::size_t
>(i) + 1]; ++k)
439 cl.b[
static_cast<std::size_t
>(lv.Pcol[
static_cast<std::size_t
>(k)])] +=
440 lv.Pval[
static_cast<std::size_t
>(k)] * lv.res[
static_cast<std::size_t
>(i)];
441 std::fill(cl.x.begin(), cl.x.end(), 0.0);
444 for (Index i = 0; i < lv.A.n; ++i) {
446 for (Index k = lv.Pstart[
static_cast<std::size_t
>(i)];
447 k < lv.Pstart[
static_cast<std::size_t
>(i) + 1]; ++k)
448 s += lv.Pval[
static_cast<std::size_t
>(k)] *
449 cl.x[
static_cast<std::size_t
>(lv.Pcol[
static_cast<std::size_t
>(k)])];
450 lv.x[
static_cast<std::size_t
>(i)] += s;
452 smooth(lv, prm_.
post);
458 void smooth(
const Level& lv,
int sweeps)
const {
462 for (
int s = 0; s < sweeps; ++s)
466 for (
int s = 0; s < sweeps; ++s)
470 void jacobiSweep(
const Level& lv)
const {
476 lv.A.apply(lv.x, lv.res);
477 for (std::size_t i = 0; i < lv.x.size(); ++i)
478 lv.x[i] += step * lv.invDiag[i] * (lv.b[i] - lv.res[i]);
485 void chebSweep(
const Level& lv)
const {
487 const double lam = 1.1 * lv.lmax;
492 for (std::size_t i = 0; i < r.size(); ++i)
493 r[i] = lv.b[i] - r[i];
494 std::fill(d.begin(), d.end(), 0.0);
495 for (
int i = 1; i <= k; ++i) {
496 const double c1 = (2.0 * i - 3.0) / (2.0 * i + 1.0);
497 const double c2 = (8.0 * i - 4.0) / ((2.0 * i + 1.0) * lam);
498 for (std::size_t j = 0; j < d.size(); ++j)
499 d[j] = c1 * d[j] + c2 * lv.invDiag[j] * r[j];
500 for (std::size_t j = 0; j < lv.x.size(); ++j)
504 for (std::size_t j = 0; j < r.size(); ++j)
512 void coarseSolve(Level& lv)
const {
517 const Index n = lv.A.n;
523 for (Index i = 0; i < n; ++i)
524 r[
static_cast<std::size_t
>(i)] =
525 lv.b[
static_cast<std::size_t
>(i)] - r[
static_cast<std::size_t
>(i)];
527 double rr = dot(r, r);
528 const double rr0 = rr;
529 const int maxit =
static_cast<int>(std::min<Index>(n, 200));
530 for (
int k = 0; k < maxit && rr > 1e-24 * rr0; ++k) {
532 const double pAp = dot(p, Ap);
535 const double alpha = rr / pAp;
536 for (Index i = 0; i < n; ++i) {
537 x[
static_cast<std::size_t
>(i)] += alpha * p[
static_cast<std::size_t
>(i)];
538 r[
static_cast<std::size_t
>(i)] -= alpha * Ap[
static_cast<std::size_t
>(i)];
540 const double rrn = dot(r, r);
541 const double beta = rrn / rr;
542 for (Index i = 0; i < n; ++i)
543 p[
static_cast<std::size_t
>(i)] =
544 r[
static_cast<std::size_t
>(i)] + beta * p[
static_cast<std::size_t
>(i)];
549 static double dot(
const std::vector<double>& a,
const std::vector<double>& b) {
551 for (std::size_t i = 0; i < a.size(); ++i)