12#ifndef ARCCORE_ALINA_RELAXATION_H
13#define ARCCORE_ALINA_RELAXATION_H
26#include "arccore/alina/BackendInterface.h"
27#include "arccore/alina/Adapters.h"
28#include "arccore/alina/ValueTypeInterface.h"
29#include "arccore/alina/QRFactorizationImpl.h"
30#include "arccore/alina/BuiltinBackend.h"
31#include "arccore/alina/DenseMatrixInverseImpl.h"
32#include "arccore/alina/BackendInterface.h"
33#include "arccore/alina/ILUSolverImpl.h"
34#include "arccore/alina/ValueTypeInterface.h"
35#include "arccore/alina/RelaxationBase.h"
43namespace Arcane::Alina
51template <
class BlockBackend,
template <
class>
class Relax>
54 typedef typename BlockBackend::value_type BlockType;
56 template <
class Backend>
61 typedef Backend backend_type;
63 typedef Relax<BlockBackend> Base;
65 typedef typename Backend::matrix matrix;
66 typedef typename Backend::vector vector;
67 typedef typename Base::params params;
68 typedef typename Backend::params backend_params;
70 typedef typename Backend::value_type value_type;
71 typedef typename Backend::col_type col_type;
72 typedef typename Backend::ptr_type ptr_type;
73 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
75 template <
class Matrix>
77 const params& prm = params(),
78 const backend_params& bprm = backend_params())
83 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
84 void apply_pre(
const Matrix& A,
89 auto F = backend::reinterpret_as_rhs<BlockType>(rhs);
90 auto X = backend::reinterpret_as_rhs<BlockType>(x);
91 auto T = backend::reinterpret_as_rhs<BlockType>(tmp);
92 base.apply_pre(A, F, X, T);
95 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
96 void apply_post(
const Matrix& A,
101 auto F = backend::reinterpret_as_rhs<BlockType>(rhs);
102 auto X = backend::reinterpret_as_rhs<BlockType>(x);
103 auto T = backend::reinterpret_as_rhs<BlockType>(tmp);
104 base.apply_post(A, F, X, T);
107 template <
class Matrix,
class Vec1,
class Vec2>
108 void apply(
const Matrix& A,
const Vec1& rhs, Vec2&& x)
const
110 auto F = backend::reinterpret_as_rhs<BlockType>(rhs);
111 auto X = backend::reinterpret_as_rhs<BlockType>(x);
115 const matrix& system_matrix()
const
117 return base.system_matrix();
120 std::shared_ptr<matrix> system_matrix_ptr()
const
122 return base.system_matrix_ptr();
142template <
class Backend,
template <
class>
class Relax>
143class RelaxationAsPreconditioner
147 typedef Backend backend_type;
149 typedef Relax<Backend> smoother;
151 typedef typename Backend::matrix matrix;
152 typedef typename Backend::vector vector;
153 typedef typename smoother::params params;
156 typedef typename Backend::value_type value_type;
157 typedef typename Backend::col_type col_type;
158 typedef typename Backend::ptr_type ptr_type;
159 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
161 template <
class Matrix>
162 RelaxationAsPreconditioner(
const Matrix& M,
163 const params& prm = params(),
164 const backend_params& bprm = backend_params())
167 init(std::make_shared<build_matrix>(M), bprm);
170 RelaxationAsPreconditioner(std::shared_ptr<build_matrix> M,
171 const params& prm = params(),
172 const backend_params& bprm = backend_params())
178 template <
class Vec1,
class Vec2>
179 void apply(
const Vec1& rhs, Vec2&& x)
const
181 S->apply(*A, rhs, x);
184 const matrix& system_matrix()
const
189 std::shared_ptr<matrix> system_matrix_ptr()
const
199 b += backend::bytes(*A);
201 b += backend::bytes(*S);
210 std::shared_ptr<matrix> A;
211 std::shared_ptr<smoother> S;
213 void init(std::shared_ptr<build_matrix> M,
const backend_params& bprm)
215 A = Backend::copy_matrix(M, bprm);
216 S = std::make_shared<smoother>(*M, prm, bprm);
219 friend std::ostream& operator<<(std::ostream& os,
const RelaxationAsPreconditioner& p)
221 os <<
"Relaxation as preconditioner" << std::endl;
222 os <<
" Unknowns: " << backend::nbRow(p.system_matrix()) << std::endl;
223 os <<
" Nonzeros: " << backend::nonzeros(p.system_matrix()) << std::endl;
224 os <<
" Memory: " << human_readable_memory(p.bytes()) << std::endl;
243template <
class Backend>
249 typedef typename Backend::value_type value_type;
250 typedef typename Backend::vector vector;
252 typedef typename math::scalar_of<value_type>::type scalar_type;
274 Int32 power_iters = 0;
282 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
degree)
283 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
higher)
284 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
lower)
285 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, power_iters)
286 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, scale)
288 p.check_params({
"degree",
"higher",
"lower",
"power_iters",
"scale" });
291 void get(
PropertyTree& p,
const std::string& path)
const
293 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
degree);
294 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
higher);
295 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
lower);
296 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, power_iters);
297 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, scale);
302 template <
class Matrix>
306 , p(Backend::create_vector(backend::nbRow(A), backend_prm))
307 , r(Backend::create_vector(backend::nbRow(A), backend_prm))
314 M = Backend::copy_vector(diagonal(A, true), backend_prm);
315 hi = spectral_radius<true>(A, prm.power_iters);
318 hi = spectral_radius<false>(A, prm.power_iters);
331 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
332 void apply_pre(
const Matrix& A,
const VectorRHS& rhs, VectorX& x, VectorTMP&)
const
337 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
338 void apply_post(
const Matrix& A,
const VectorRHS& rhs, VectorX& x, VectorTMP&)
const
343 template <
class Matrix,
class VectorRHS,
class VectorX>
344 void apply(
const Matrix& A,
const VectorRHS& rhs, VectorX& x)
const
352 size_t b = backend::bytes(*p) + backend::bytes(*r);
354 b += backend::bytes(*M);
360 std::shared_ptr<typename Backend::matrix_diagonal> M;
361 mutable std::shared_ptr<vector> p, r;
365 template <
class Matrix,
class VectorB,
class VectorX>
366 void solve(
const Matrix& A,
const VectorB& b, VectorX& x)
const
368 static const scalar_type one = math::identity<scalar_type>();
369 static const scalar_type zero = math::zero<scalar_type>();
371 scalar_type alpha = zero, beta = zero;
373 for (
unsigned k = 0; k < prm.
degree; ++k) {
374 backend::residual(b, A, x, *r);
377 backend::vmul(one, *M, *r, zero, *r);
380 alpha = math::inverse(d);
384 alpha = 2 * d * math::inverse(2 * d * d - c * c);
385 beta = alpha * d - one;
388 alpha = math::inverse(d - 0.25 * alpha * c * c);
389 beta = alpha * d - one;
392 backend::axpby(alpha, *r, beta, *p);
393 backend::axpby(one, *p, one, x);
406template <
class Backend>
410 typedef typename Backend::value_type value_type;
411 typedef typename math::scalar_of<value_type>::type scalar_type;
426 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
damping)
428 p.check_params({
"damping" });
431 void get(PropertyTree& p,
const std::string& path)
const
433 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
damping);
437 std::shared_ptr<typename Backend::matrix_diagonal> dia;
445 template <
class Matrix>
450 , dia(Backend::copy_vector(diagonal(A, true), backend_prm))
461 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
462 void apply_pre(
const Matrix& A,
const VectorRHS& rhs, VectorX& x, VectorTMP& tmp)
const
464 backend::residual(rhs, A, x, tmp);
465 backend::vmul(prm.damping, *dia, tmp, math::identity<scalar_type>(), x);
476 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
479 backend::residual(rhs, A, x, tmp);
480 backend::vmul(prm.damping, *dia, tmp, math::identity<scalar_type>(), x);
483 template <
class Matrix,
class VectorRHS,
class VectorX>
484 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
486 backend::vmul(math::identity<scalar_type>(), *dia, rhs, math::zero<scalar_type>(), x);
491 return backend::bytes(*dia);
507template <
class Backend>
522 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
serial)
524 p.check_params({
"serial" });
527 void get(PropertyTree& p,
const std::string& path)
const
529 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
serial);
536 template <
class Matrix>
541 forward = std::make_shared<parallel_sweep<true>>(A);
542 backward = std::make_shared<parallel_sweep<false>>(A);
547 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
551 serial_sweep(A, rhs, x,
true);
553 forward->sweep(rhs, x);
557 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
561 serial_sweep(A, rhs, x,
false);
563 backward->sweep(rhs, x);
566 template <
class Matrix,
class VectorRHS,
class VectorX>
567 void apply(
const Matrix& A,
const VectorRHS& rhs, VectorX& x)
const
571 serial_sweep(A, rhs, x,
true);
572 serial_sweep(A, rhs, x,
false);
575 forward->sweep(rhs, x);
576 backward->sweep(rhs, x);
584 b += forward->bytes();
586 b += backward->bytes();
592 template <
class Matrix,
class VectorRHS,
class VectorX>
593 static void serial_sweep(
const Matrix& A,
const VectorRHS& rhs, VectorX& x,
bool forward)
595 typedef typename backend::value_type<Matrix>::type val_type;
596 typedef typename math::rhs_of<val_type>::type rhs_type;
598 const ptrdiff_t n = backend::nbRow(A);
600 const ptrdiff_t beg = forward ? 0 : n - 1;
601 const ptrdiff_t end = forward ? n : -1;
602 const ptrdiff_t inc = forward ? 1 : -1;
604 for (ptrdiff_t i = beg; i != end; i += inc) {
605 val_type D = math::identity<val_type>();
609 for (
auto a = backend::row_begin(A, i); a; ++a) {
610 ptrdiff_t c = a.col();
611 val_type v = a.value();
619 x[i] = math::inverse(D) * X;
623 template <
bool forward>
624 struct parallel_sweep
626 typedef typename Backend::value_type value_type;
627 typedef typename math::rhs_of<value_type>::type rhs_type;
632 task(ptrdiff_t beg, ptrdiff_t end)
647 template <
class Matrix>
648 parallel_sweep(
const Matrix& A)
657 ptrdiff_t n = backend::nbRow(A);
664 ptrdiff_t beg = forward ? 0 : n - 1;
665 ptrdiff_t end = forward ? n : -1;
666 ptrdiff_t inc = forward ? 1 : -1;
668 for (ptrdiff_t i = beg; i != end; i += inc) {
669 ptrdiff_t l = level[i];
671 for (
auto a = backend::row_begin(A, i); a; ++a) {
672 ptrdiff_t c = a.col();
683 l = std::max(l, level[c] + 1);
687 nlev = std::max(nlev, l + 1);
691 UniqueArray<ptrdiff_t> start(nlev + 1, 0);
693 for (ptrdiff_t i = 0; i < n; ++i)
694 ++start[level[i] + 1];
696 std::partial_sum(start.begin(), start.end(), start.begin());
698 for (ptrdiff_t i = 0; i < n; ++i)
699 order[start[level[i]]++] = i;
701 std::rotate(start.begin(), start.end() - 1, start.end());
706 UniqueArray<ptrdiff_t> thread_rows(nthreads, 0);
707 UniqueArray<ptrdiff_t> thread_cols(nthreads, 0);
711 for (ptrdiff_t tid = begin; tid < (begin + size); ++tid) {
712 for (ptrdiff_t lev = 0; lev < nlev; ++lev) {
714 ptrdiff_t lev_size = start[lev + 1] - start[lev];
715 ptrdiff_t chunk_size = (lev_size + nthreads - 1) / nthreads;
717 ptrdiff_t beg = std::min(tid * chunk_size, lev_size);
718 ptrdiff_t end = std::min(beg + chunk_size, lev_size);
723 tasks[tid].push_back(
task(beg, end));
726 thread_rows[tid] += end - beg;
727 for (ptrdiff_t i = beg; i < end; ++i) {
728 ptrdiff_t j = order[i];
729 thread_cols[tid] += backend::row_nonzeros(A, j);
737 for (ptrdiff_t tid = begin; tid < (begin + size); ++tid) {
738 col[tid].reserve(thread_cols[tid]);
739 val[tid].reserve(thread_cols[tid]);
740 ord[tid].reserve(thread_rows[tid]);
741 ptr[tid].reserve(thread_rows[tid] + 1);
742 ptr[tid].push_back(0);
743 for (
task& t : tasks[tid]) {
744 ptrdiff_t loc_beg = ptr[tid].size() - 1;
745 ptrdiff_t loc_end = loc_beg;
747 for (ptrdiff_t r = t.beg; r < t.end; ++r, ++loc_end) {
748 ptrdiff_t i = order[r];
750 ord[tid].push_back(i);
752 for (
auto a = backend::row_begin(A, i); a; ++a) {
753 col[tid].push_back(a.col());
754 val[tid].push_back(a.value());
757 ptr[tid].push_back(col[tid].size());
767 template <
class Vector1,
class Vector2>
768 void sweep(
const Vector1& rhs, Vector2& x)
const
771 for (ptrdiff_t tid = 0; tid < nthreads; ++tid) {
772 for (
const task& t : tasks[tid]) {
773 for (ptrdiff_t r = t.beg; r < t.end; ++r) {
774 ptrdiff_t i = ord[tid][r];
775 ptrdiff_t beg = ptr[tid][r];
776 ptrdiff_t end = ptr[tid][r + 1];
778 value_type D = math::identity<value_type>();
782 for (ptrdiff_t j = beg; j < end; ++j) {
783 ptrdiff_t c = col[tid][j];
784 value_type v = val[tid][j];
792 x[i] = math::inverse(D) * X;
806 for (
int i = 0; i < nthreads; ++i) {
807 b +=
sizeof(
task) * tasks[i].size();
808 b += backend::bytes(ptr[i]);
809 b += backend::bytes(col[i]);
810 b += backend::bytes(val[i]);
811 b += backend::bytes(ord[i]);
818 std::shared_ptr<parallel_sweep<true>> forward;
819 std::shared_ptr<parallel_sweep<false>> backward;
831template <
class Backend>
835 typedef typename Backend::value_type value_type;
836 typedef typename Backend::col_type col_type;
837 typedef typename Backend::ptr_type ptr_type;
838 typedef typename Backend::vector vector;
839 typedef typename Backend::matrix matrix;
840 typedef typename Backend::matrix_diagonal matrix_diagonal;
842 typedef typename math::scalar_of<value_type>::type scalar_type;
859 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
damping)
860 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, solve)
862 p.check_params({
"damping",
"solve" }, {
"k" });
865 void get(PropertyTree& p,
const std::string& path)
const
867 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
damping);
868 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, solve);
873 template <
class Matrix>
877 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
878 const size_t n = backend::nbRow(A);
880 size_t Lnz = 0, Unz = 0;
882 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
883 ptrdiff_t row_beg = A.ptr[i];
884 ptrdiff_t row_end = A.ptr[i + 1];
886 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
887 ptrdiff_t c = A.col[j];
895 auto L = std::make_shared<build_matrix>();
896 auto U = std::make_shared<build_matrix>();
899 L->set_nonzeros(Lnz);
902 U->set_nonzeros(Unz);
908 auto D = std::make_shared<numa_vector<value_type>>(n,
false);
910 std::vector<value_type*> work(n, NULL);
912 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
913 ptrdiff_t row_beg = A.ptr[i];
914 ptrdiff_t row_end = A.ptr[i + 1];
916 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
917 ptrdiff_t c = A.col[j];
918 value_type v = A.val[j];
923 work[c] = L->val + Lhead;
933 work[c] = U->val + Uhead;
938 L->ptr[i + 1] = Lhead;
939 U->ptr[i + 1] = Uhead;
941 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
942 ptrdiff_t c = A.col[j];
946 precondition(c == i,
"No diagonal value in system matrix");
947 precondition(!math::is_zero((*D)[i]),
"Zero pivot in ILU");
949 (*D)[i] = math::inverse((*D)[i]);
954 value_type tl = (*work[c]) * (*D)[c];
958 for (ptrdiff_t k = U->ptr[c]; k <
static_cast<ptrdiff_t
>(U->ptr[c + 1]); ++k) {
959 value_type* w = work[U->col[k]];
961 *w -= tl * U->val[k];
969 for (ptrdiff_t j = Lhead, e = L->ptr[i + 1]; j < e; ++j) {
971 if (!math::is_zero(v)) {
972 L->col[Lhead] = L->col[j];
978 for (ptrdiff_t j = Uhead, e = U->ptr[i + 1]; j < e; ++j) {
980 if (!math::is_zero(v)) {
981 U->col[Uhead] = U->col[j];
986 L->ptr[i + 1] = Lhead;
987 U->ptr[i + 1] = Uhead;
990 for (ptrdiff_t j = row_beg; j < row_end; ++j)
991 work[A.col[j]] = NULL;
994 L->setNbNonZero(Lhead);
995 U->setNbNonZero(Uhead);
997 ilu = std::make_shared<ilu_solve>(L, U, D, prm.solve, bprm);
1001 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1004 backend::residual(rhs, A, x, tmp);
1006 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1010 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1013 backend::residual(rhs, A, x, tmp);
1015 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1019 template <
class Matrix,
class VectorRHS,
class VectorX>
1022 backend::copy(rhs, x);
1028 return ilu->bytes();
1033 std::shared_ptr<ilu_solve> ilu;
1041template <
class Backend>
1045 typedef typename Backend::value_type value_type;
1046 typedef typename Backend::col_type col_type;
1047 typedef typename Backend::ptr_type ptr_type;
1048 typedef typename Backend::matrix matrix;
1049 typedef typename Backend::matrix_diagonal matrix_diagonal;
1050 typedef typename Backend::vector vector;
1052 typedef typename math::scalar_of<value_type>::type scalar_type;
1074 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
k)
1075 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
damping)
1076 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, solve)
1078 p.check_params({
"k",
"damping",
"solve" });
1081 void get(PropertyTree& p,
const std::string& path)
const
1083 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
k);
1084 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
damping);
1085 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, solve);
1090 template <
class Matrix>
1094 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
1096 const size_t n = backend::nbRow(A);
1098 size_t Anz = backend::nonzeros(A);
1100 std::vector<ptrdiff_t> Lptr;
1101 Lptr.reserve(n + 1);
1103 std::vector<ptrdiff_t> Lcol;
1104 Lcol.reserve(Anz / 3);
1105 std::vector<value_type> Lval;
1106 Lval.reserve(Anz / 3);
1108 std::vector<ptrdiff_t> Uptr;
1109 Uptr.reserve(n + 1);
1111 std::vector<ptrdiff_t> Ucol;
1112 Ucol.reserve(Anz / 3);
1113 std::vector<value_type> Uval;
1114 Uval.reserve(Anz / 3);
1116 std::vector<int> Ulev;
1117 Ulev.reserve(Anz / 3);
1119 auto D = std::make_shared<numa_vector<value_type>>(n,
false);
1123 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
1126 for (
auto a = backend::row_begin(A, i); a; ++a) {
1127 w.add(a.col(), a.value(), 0);
1130 while (!w.q.empty()) {
1131 nonzero& a = w.next_nonzero();
1132 a.val = a.val * (*D)[a.col];
1134 for (ptrdiff_t j = Uptr[a.col], e = Uptr[a.col + 1]; j < e; ++j) {
1135 int lev = std::max(a.lev, Ulev[j]) + 1;
1136 w.add(Ucol[j], -a.val * Uval[j], lev);
1142 for (
const nonzero& e : w.nz) {
1144 Lcol.push_back(e.col);
1145 Lval.push_back(e.val);
1147 else if (e.col == i) {
1148 (*D)[i] = math::inverse(e.val);
1151 Ucol.push_back(e.col);
1152 Uval.push_back(e.val);
1153 Ulev.push_back(e.lev);
1157 Lptr.push_back(Lcol.size());
1158 Uptr.push_back(Ucol.size());
1161 ilu = std::make_shared<ilu_solve>(
1162 std::make_shared<build_matrix>(n, n, Lptr, Lcol, Lval),
1163 std::make_shared<build_matrix>(n, n, Uptr, Ucol, Uval),
1164 D, prm.solve, bprm);
1168 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1171 backend::residual(rhs, A, x, tmp);
1173 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1177 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1180 backend::residual(rhs, A, x, tmp);
1182 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1185 template <
class Matrix,
class VectorRHS,
class VectorX>
1186 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
1188 backend::copy(rhs, x);
1194 return ilu->bytes();
1199 std::shared_ptr<ilu_solve> ilu;
1211 nonzero(ptrdiff_t col,
const value_type& val,
int lev)
1217 friend bool operator<(
const nonzero& a,
const nonzero& b)
1219 return a.col < b.col;
1223 struct sparse_vector
1227 const std::deque<nonzero>& nz;
1229 comp_indices(
const std::deque<nonzero>& nz)
1233 bool operator()(
int a,
int b)
const
1235 return nz[a].col > nz[b].col;
1239 typedef std::priority_queue<int, std::vector<int>,
comp_indices>
1244 std::deque<nonzero> nz;
1245 std::vector<ptrdiff_t> idx;
1250 sparse_vector(
size_t n,
int lfil)
1257 void add(ptrdiff_t col,
const value_type& val,
int lev)
1263 nz.push_back(
nonzero(col, val, lev));
1269 nonzero& a = nz[idx[col]];
1271 a.lev = std::min(a.lev, lev);
1275 typename std::deque<nonzero>::iterator begin()
1280 typename std::deque<nonzero>::iterator end()
1285 nonzero& next_nonzero()
1294 std::sort(nz.begin(), nz.end());
1297 void reset(ptrdiff_t d)
1299 for (
const nonzero& e : nz)
1312 template <
class Matrix>
1313 std::shared_ptr<Matrix> symb_product(
const Matrix& A,
const Matrix& B)
1315 auto C = std::make_shared<Matrix>();
1317 C->set_size(A.nbRow(), B.ncols);
1319 auto A_ptr = A.ptr.data();
1320 auto A_col = A.col.data();
1321 auto B_ptr = B.ptr.data();
1322 auto B_col = B.col.data();
1323 auto C_ptr = C->ptr.data();
1327 std::vector<ptrdiff_t> marker(B.ncols, -1);
1329 for (ptrdiff_t ia = begin; ia < (begin + size); ++ia) {
1330 ptrdiff_t C_cols = 0;
1331 for (ptrdiff_t ja = A_ptr[ia], ea = A_ptr[ia + 1]; ja < ea; ++ja) {
1332 ptrdiff_t ca = A_col[ja];
1334 for (ptrdiff_t jb = B_ptr[ca], eb = B_ptr[ca + 1]; jb < eb; ++jb) {
1335 ptrdiff_t cb = B_col[jb];
1336 if (marker[cb] != ia) {
1342 C_ptr[ia + 1] = C_cols;
1346 C->set_nonzeros(C->scan_row_sizes(),
false);
1347 auto C_col = C->col.data();
1350 std::vector<ptrdiff_t> marker(B.ncols, -1);
1352 for (ptrdiff_t ia = begin; ia < (begin + size); ++ia) {
1353 ptrdiff_t row_beg = C_ptr[ia];
1354 ptrdiff_t row_end = row_beg;
1356 for (ptrdiff_t ja = A_ptr[ia], ea = A_ptr[ia + 1]; ja < ea; ++ja) {
1357 ptrdiff_t ca = A_col[ja];
1359 for (ptrdiff_t jb = B_ptr[ca], eb = B_ptr[ca + 1]; jb < eb; ++jb) {
1360 ptrdiff_t cb = B_col[jb];
1362 if (marker[cb] < row_beg) {
1363 marker[cb] = row_end;
1364 C_col[row_end] = cb;
1370 std::sort(C_col + row_beg, C_col + row_end);
1384template <
class Backend>
1388 typedef typename Backend::value_type value_type;
1406 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, k)
1408 p.check_params( {
"k",
"damping",
"solve" });
1411 void get(PropertyTree& p,
const std::string& path)
const
1413 BasePrm::get(p, path);
1414 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, k);
1419 template <
class Matrix>
1424 base = std::make_shared<Base>(A, prm, bprm);
1427 auto P = detail::symb_product(A, A);
1428 for (int k = 1; k < prm.k; ++k) {
1429 P = detail::symb_product(*P, A);
1432 ptrdiff_t n = backend::nbRow(A);
1433 P->val.resize(P->nbNonZero());
1436 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1437 ptrdiff_t p_beg = P->ptr[i];
1438 ptrdiff_t p_end = P->ptr[i + 1];
1439 ptrdiff_t a_beg = A.ptr[i];
1440 ptrdiff_t a_end = A.ptr[i + 1];
1442 std::fill(P->val + p_beg, P->val + p_end, math::zero<value_type>());
1444 for (ptrdiff_t ja = a_beg, ea = a_end, jp = p_beg, ep = p_end; ja < ea; ++ja) {
1445 ptrdiff_t ca = A.col[ja];
1446 while (jp < ep && P->col[jp] < ca)
1448 if (P->col[jp] == ca)
1449 P->val[jp] = A.val[ja];
1454 base = std::make_shared<Base>(*P, prm, bprm);
1459 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1462 base->apply_pre(A, rhs, x, tmp);
1466 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1469 base->apply_post(A, rhs, x, tmp);
1472 template <
class Matrix,
class VectorRHS,
class VectorX>
1473 void apply(
const Matrix& A,
const VectorRHS& rhs, VectorX& x)
const
1475 base->apply(A, rhs, x);
1480 return base->bytes();
1485 std::shared_ptr<Base> base;
1498template <
class Backend>
1502 typedef typename Backend::value_type value_type;
1503 typedef typename Backend::col_type col_type;
1504 typedef typename Backend::ptr_type ptr_type;
1505 typedef typename Backend::matrix matrix;
1506 typedef typename Backend::matrix_diagonal matrix_diagonal;
1507 typedef typename Backend::vector vector;
1509 typedef typename math::scalar_of<value_type>::type scalar_type;
1531 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(
p,
p)
1532 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(
p,
tau)
1533 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(
p,
damping)
1534 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(
p,
solve)
1536 p.check_params( {
"p",
"tau",
"damping",
"solve" });
1539 void get(
PropertyTree& p,
const std::string& path)
const
1541 double p2 = this->p;
1542 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, p2);
1543 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, tau);
1544 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, damping);
1545 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, solve);
1550 template <
class Matrix>
1554 const size_t n = backend::nbRow(A);
1556 size_t Lnz = 0, Unz = 0;
1558 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
1559 ptrdiff_t row_beg = A.ptr[i];
1560 ptrdiff_t row_end = A.ptr[i + 1];
1562 int lenL = 0, lenU = 0;
1563 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
1564 ptrdiff_t c = A.col[j];
1571 Lnz +=
static_cast<size_t>(lenL * prm.p);
1572 Unz +=
static_cast<size_t>(lenU * prm.p);
1575 auto L = std::make_shared<build_matrix>();
1576 auto U = std::make_shared<build_matrix>();
1579 L->set_nonzeros(Lnz);
1582 U->set_nonzeros(Unz);
1585 auto D = std::make_shared<numa_vector<value_type>>(n,
false);
1589 for (ptrdiff_t i = 0, Lhead = 0, Uhead = 0; i < static_cast<ptrdiff_t>(n); ++i) {
1595 scalar_type tol = math::zero<scalar_type>();
1597 for (
auto a = backend::row_begin(A, i); a; ++a) {
1598 w[a.col()] = a.value();
1599 tol += math::norm(a.value());
1606 tol *= prm.tau / (lenL + lenU);
1608 while (!w.q.empty()) {
1609 ptrdiff_t k = w.next_nonzero();
1610 w[k] = w[k] * (*D)[k];
1611 value_type wk = w[k];
1613 if (math::norm(wk) > tol) {
1614 for (ptrdiff_t j = U->ptr[k]; j <
static_cast<ptrdiff_t
>(U->ptr[k + 1]); ++j)
1615 w[U->col[j]] -= wk * U->val[j];
1620 static_cast<int>(lenL * prm.p),
1621 static_cast<int>(lenU * prm.p),
1622 tol, Lhead, *L, Uhead, *U, *D);
1624 L->ptr[i + 1] = Lhead;
1625 U->ptr[i + 1] = Uhead;
1628 L->setNbNonZero(L->ptr[n]);
1629 U->setNbNonZero(U->ptr[n]);
1631 ilu = std::make_shared<ilu_solve>(L, U, D, prm.solve, bprm);
1635 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1638 backend::residual(rhs, A, x, tmp);
1640 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1644 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1647 backend::residual(rhs, A, x, tmp);
1649 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1652 template <
class Matrix,
class VectorRHS,
class VectorX>
1653 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
1655 backend::copy(rhs, x);
1661 return ilu->bytes();
1666 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
1667 std::shared_ptr<ilu_solve> ilu;
1669 struct sparse_vector
1680 nonzero(ptrdiff_t col,
const value_type& val = math::zero<value_type>())
1688 const std::vector<nonzero>& nz;
1690 comp_indices(
const std::vector<nonzero>& nz)
1694 bool operator()(
int a,
int b)
const
1696 return nz[a].col > nz[b].col;
1700 typedef std::priority_queue<int, std::vector<int>,
comp_indices> priority_queue;
1702 std::vector<nonzero> nz;
1703 std::vector<ptrdiff_t> idx;
1708 sparse_vector(
size_t n)
1716 value_type operator[](ptrdiff_t i)
const
1719 return nz[idx[i]].val;
1720 return math::zero<value_type>();
1723 value_type& operator[](ptrdiff_t i)
1728 nz.push_back(nonzero(i));
1732 return nz[idx[i]].val;
1735 typename std::vector<nonzero>::iterator begin()
1740 typename std::vector<nonzero>::iterator end()
1745 ptrdiff_t next_nonzero()
1757 higher_than(scalar_type tol, ptrdiff_t dia)
1762 bool operator()(
const nonzero& v)
const
1764 return v.col == dia || math::norm(v.val) > tol;
1772 L_first(ptrdiff_t dia)
1776 bool operator()(
const nonzero& v)
const
1786 by_abs_val(ptrdiff_t dia)
1797 return math::norm(a.val) > math::norm(b.val);
1805 return a.col < b.col;
1809 void move_to(
int lp,
int up, scalar_type tol,
1810 ptrdiff_t& Lhead, build_matrix& L,
1811 ptrdiff_t& Uhead, build_matrix& U,
1814 typedef typename std::vector<nonzero>::iterator ptr;
1823 ptr m = std::partition(b, e,
L_first(dia));
1826 ptr lend = std::min(b + lp, m);
1827 ptr uend = std::min(m + up, e);
1830 std::nth_element(b, lend, m,
by_abs_val(dia));
1832 std::nth_element(m, uend, e,
by_abs_val(dia));
1835 std::sort(b, lend,
by_col());
1836 std::sort(m, uend,
by_col());
1839 for (ptr a = b; a != lend; ++a) {
1840 L.col[Lhead] = a->col;
1841 L.val[Lhead] = a->val;
1847 D[dia] = math::inverse(m->val);
1853 for (ptr a = m; a != uend; ++a) {
1854 U.col[Uhead] = a->col;
1855 U.val[Uhead] = a->val;
1861 for (
const nonzero& e : nz)
1879template <
class Backend>
1883 typedef typename Backend::value_type value_type;
1884 typedef typename Backend::matrix_diagonal matrix_diagonal;
1886 typedef typename math::scalar_of<value_type>::type scalar_type;
1891 template <
class Matrix>
1894 const size_t n = backend::nbRow(A);
1896 auto m = std::make_shared<numa_vector<value_type>>(n,
false);
1899 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1900 value_type num = math::zero<value_type>();
1901 scalar_type den = math::zero<scalar_type>();
1903 for (
auto a = backend::row_begin(A, i); a; ++a) {
1904 value_type v = a.value();
1905 scalar_type norm_v = math::norm(v);
1906 den += norm_v * norm_v;
1911 (*m)[i] = math::inverse(den) * num;
1915 M = Backend::copy_vector(m, backend_prm);
1919 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1922 static const scalar_type one = math::identity<scalar_type>();
1923 backend::residual(rhs, A, x, tmp);
1924 backend::vmul(one, *M, tmp, one, x);
1928 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1931 static const scalar_type one = math::identity<scalar_type>();
1932 backend::residual(rhs, A, x, tmp);
1933 backend::vmul(one, *M, tmp, one, x);
1936 template <
class Matrix,
class VectorRHS,
class VectorX>
1937 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
1939 backend::vmul(math::identity<scalar_type>(), *M, rhs, math::zero<scalar_type>(), x);
1944 return backend::bytes(*M);
1947 std::shared_ptr<matrix_diagonal> M;
1961template <
class Backend>
1965 typedef typename Backend::value_type value_type;
1966 typedef typename Backend::vector vector;
1968 typedef typename math::scalar_of<value_type>::type scalar_type;
1974 template <
class Matrix>
1977 typedef typename backend::value_type<Matrix>::type value_type;
1979 const size_t n = backend::nbRow(A);
1980 const size_t m = backend::nbColumn(A);
1982 auto Ainv = std::make_shared<Matrix>(A);
1985 std::vector<ptrdiff_t> marker(m, -1);
1986 std::vector<ptrdiff_t> I, J;
1987 std::vector<value_type> B, ek;
1990 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1991 ptrdiff_t row_beg = A.ptr[i];
1992 ptrdiff_t row_end = A.ptr[i + 1];
1994 I.assign(A.col + row_beg, A.col + row_end);
1997 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
1998 ptrdiff_t c = A.col[j];
2000 for (ptrdiff_t jj = A.ptr[c], ee = A.ptr[c + 1]; jj < ee; ++jj) {
2001 ptrdiff_t cc = A.col[jj];
2002 if (marker[cc] < 0) {
2008 std::sort(J.begin(), J.end());
2009 B.assign(I.size() * J.size(), math::zero<value_type>());
2010 ek.assign(J.size(), math::zero<value_type>());
2011 for (
size_t j = 0; j < J.size(); ++j) {
2013 if (J[j] ==
static_cast<ptrdiff_t
>(i))
2014 ek[j] = math::identity<value_type>();
2017 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
2018 ptrdiff_t c = A.col[j];
2020 for (
auto a = backend::row_begin(A, c); a; ++a)
2021 B[marker[a.col()] + J.size() * (j - row_beg)] = a.value();
2024 qr.solve(J.size(), I.size(), &B[0], &ek[0], &Ainv->val[row_beg],
2025 Alina::detail::col_major);
2027 for (
size_t j = 0; j < J.size(); ++j)
2032 M = Backend::copy_matrix(Ainv, backend_prm);
2036 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
2039 backend::residual(rhs, A, x, tmp);
2040 backend::spmv(math::identity<scalar_type>(), *M, tmp, math::identity<scalar_type>(), x);
2044 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
2047 backend::residual(rhs, A, x, tmp);
2048 backend::spmv(math::identity<scalar_type>(), *M, tmp, math::identity<scalar_type>(), x);
2051 template <
class Matrix,
class VectorRHS,
class VectorX>
2052 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
2054 backend::spmv(math::identity<scalar_type>(), *M, rhs, math::zero<scalar_type>(), x);
2059 return backend::bytes(*M);
2062 std::shared_ptr<typename Backend::matrix> M;
2073namespace Arcane::Alina::backend
2076template <
class Backend>
2078 typename std::enable_if<(Alina::math::static_rows<typename Backend::value_type>::value > 1)>
::type> : std::false_type
2081template <
class Backend>
2083 typename std::enable_if<
2084 !Backend::provides_row_iterator::value>
::type> : std::false_type
size_t bytes() const
Memory used in bytes.
ChebyshevRelaxation(const Matrix &A, const params &prm, const typename Backend::params &backend_prm)
Constructs smoother for the system matrix.
Solver for sparse triangular systems obtained as a result of an incomplete LU factorization.
Class to handle empty parameters list.
NUMA-aware vector container.
iterator begin()
Itérateur sur le premier élément du tableau.
Informations de base pour la gestion du multi-threading.
Informations d'exécution d'une boucle.
Matrix class, to be used by user.
Vecteur 1D de données avec sémantique par valeur (style STL).
void arccoreParallelFor(const ComplexForLoopRanges< RankValue > &loop_ranges, const ForLoopRunInfo &run_info, const LambdaType &lambda_function, const ReducerArgs &... reducer_args)
Applique en concurrence la fonction lambda lambda_function sur l'intervalle d'itération donné par loo...
std::int32_t Int32
Type entier signé sur 32 bits.
Alina::detail::empty_params params
Sparse matrix stored in CSR (Compressed Sparse Row) format.
double lower
Lowest-to-highest eigen value ratio.
double higher
highest eigen value safety upscaling.
Int32 degree
Chebyshev polynomial degree.
scalar_type damping
Damping factor.
void apply_post(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply post-relaxation.
DampedJacobiRelaxation(const Matrix &A, const params &prm, const typename Backend::params &backend_prm)
Constructs smoother for the system matrix.
void apply_pre(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply pre-relaxation.
size_t bytes() const
Memory used in bytes.
bool serial
Use serial version of the algorithm.
void apply_pre(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &) const
Apply pre-relaxation.
size_t bytes() const
Memory used in bytes.
GaussSeidelRelaxation(const Matrix &A, const params &prm, const typename Backend::params &)
Constructs smoother for the system matrix.
void apply_post(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &) const
Apply post-relaxation.
ilu_solve::params solve
Parameters for sparse triangular system solver.
scalar_type damping
Damping factor.
void apply_pre(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply pre-relaxation.
void apply(const Matrix &, const VectorRHS &rhs, VectorX &x) const
Apply post-relaxation.
void apply_post(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply post-relaxation.
ILU0Relaxation(const Matrix &A, const params &prm, const typename Backend::params &bprm)
Constructs smoother for the system matrix.
size_t bytes() const
Memory used in bytes.
ilu_solve::params solve
Parameters for sparse triangular system solver.
scalar_type damping
Damping factor.
size_t bytes() const
Memory used in bytes.
void apply_post(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply post-relaxation.
void apply_pre(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply pre-relaxation.
ILUKRelaxation(const Matrix &A, const params &prm, const typename Backend::params &bprm)
Constructs smoother for the system matrix.
void apply_pre(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply pre-relaxation.
ILUPRelaxation(const Matrix &A, const params &prm, const typename Backend::params &bprm)
Constructs smoother for the system matrix.
void apply_post(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply post-relaxation.
size_t bytes() const
Memory used in bytes.
double tau
Minimum magnitude of non-zero elements relative to the current row norm.
double damping
Damping factor.
ilu_solve::params solve
Parameters for sparse triangular system solver.
ILUTRelaxation(const Matrix &A, const params &prm, const typename Backend::params &bprm)
Constructs smoother for the system matrix.
void apply_pre(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply pre-relaxation.
void apply_post(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply post-relaxation.
size_t bytes() const
Memory used in bytes.
Converts input matrix to block format before constructing an AMG smoother.
Alina::detail::empty_params params
Relaxation parameters.
size_t bytes() const
Memory used in bytes.
void apply_pre(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply pre-relaxation.
SPAI0Relaxation(const Matrix &A, const params &, const typename Backend::params &backend_prm)
Constructs smoother for the system matrix.
void apply_post(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply post-relaxation.
Sparse approximate interface smoother.
Alina::detail::empty_params params
Relaxation parameters.
SPAI1Relaxation(const Matrix &A, const params &, const typename Backend::params &backend_prm)
Constructs smoother for the system matrix.
size_t bytes() const
Memory used in bytes.
void apply_post(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply post-relaxation.
void apply_pre(const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp) const
Apply pre-relaxation.
Is the relaxation supported by the backend?
Number of rows for statically sized matrix types.