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;
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([[maybe_unused]]
const AlinaContext& context,
164 const params& prm = params(),
165 const backend_params& bprm = backend_params())
168 init(std::make_shared<build_matrix>(M), bprm);
171 RelaxationAsPreconditioner([[maybe_unused]]
const AlinaContext& context,
172 std::shared_ptr<build_matrix> M,
173 const params& prm = params(),
174 const backend_params& bprm = backend_params())
180 template <
class Vec1,
class Vec2>
181 void apply(
const Vec1& rhs, Vec2&& x)
const
183 S->apply(*A, rhs, x);
186 const matrix& system_matrix()
const
191 std::shared_ptr<matrix> system_matrix_ptr()
const
201 b += backend::bytes(*A);
203 b += backend::bytes(*S);
212 std::shared_ptr<matrix> A;
213 std::shared_ptr<smoother> S;
215 void init(std::shared_ptr<build_matrix> M,
const backend_params& bprm)
217 A = Backend::copy_matrix(M, bprm);
218 S = std::make_shared<smoother>(*M, prm, bprm);
221 friend std::ostream& operator<<(std::ostream& os,
const RelaxationAsPreconditioner& p)
223 os <<
"Relaxation as preconditioner" << std::endl;
224 os <<
" Unknowns: " << backend::nbRow(p.system_matrix()) << std::endl;
225 os <<
" Nonzeros: " << backend::nonzeros(p.system_matrix()) << std::endl;
226 os <<
" Memory: " << human_readable_memory(p.bytes()) << std::endl;
245template <
class Backend>
251 typedef typename Backend::value_type value_type;
252 typedef typename Backend::vector vector;
254 typedef typename math::scalar_of<value_type>::type scalar_type;
276 Int32 power_iters = 0;
284 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
degree)
285 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
higher)
286 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
lower)
287 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, power_iters)
288 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, scale)
290 p.check_params({
"degree",
"higher",
"lower",
"power_iters",
"scale" });
293 void get(
PropertyTree& p,
const std::string& path)
const
295 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
degree);
296 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
higher);
297 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
lower);
298 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, power_iters);
299 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, scale);
304 template <
class Matrix>
308 , p(Backend::create_vector(backend::nbRow(A), backend_prm))
309 , r(Backend::create_vector(backend::nbRow(A), backend_prm))
316 M = Backend::copy_vector(diagonal(A, true), backend_prm);
317 hi = spectral_radius<true>(A, prm.power_iters);
320 hi = spectral_radius<false>(A, prm.power_iters);
333 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
334 void apply_pre(
const Matrix& A,
const VectorRHS& rhs, VectorX& x, VectorTMP&)
const
339 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
340 void apply_post(
const Matrix& A,
const VectorRHS& rhs, VectorX& x, VectorTMP&)
const
345 template <
class Matrix,
class VectorRHS,
class VectorX>
346 void apply(
const Matrix& A,
const VectorRHS& rhs, VectorX& x)
const
354 size_t b = backend::bytes(*p) + backend::bytes(*r);
356 b += backend::bytes(*M);
362 std::shared_ptr<typename Backend::matrix_diagonal> M;
363 mutable std::shared_ptr<vector> p, r;
367 template <
class Matrix,
class VectorB,
class VectorX>
368 void solve(
const Matrix& A,
const VectorB& b, VectorX& x)
const
370 static const scalar_type one = math::identity<scalar_type>();
371 static const scalar_type zero = math::zero<scalar_type>();
373 scalar_type alpha = zero, beta = zero;
375 for (
unsigned k = 0; k < prm.
degree; ++k) {
376 backend::residual(b, A, x, *r);
379 backend::vmul(one, *M, *r, zero, *r);
382 alpha = math::inverse(d);
386 alpha = 2 * d * math::inverse(2 * d * d - c * c);
387 beta = alpha * d - one;
390 alpha = math::inverse(d - 0.25 * alpha * c * c);
391 beta = alpha * d - one;
394 backend::axpby(alpha, *r, beta, *p);
395 backend::axpby(one, *p, one, x);
408template <
class Backend>
412 typedef typename Backend::value_type value_type;
413 typedef typename math::scalar_of<value_type>::type scalar_type;
428 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
damping)
430 p.check_params({
"damping" });
433 void get(PropertyTree& p,
const std::string& path)
const
435 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
damping);
439 std::shared_ptr<typename Backend::matrix_diagonal> dia;
447 template <
class Matrix>
452 , dia(Backend::copy_vector(diagonal(A, true), backend_prm))
463 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
464 void apply_pre(
const Matrix& A,
const VectorRHS& rhs, VectorX& x, VectorTMP& tmp)
const
466 backend::residual(rhs, A, x, tmp);
467 backend::vmul(prm.damping, *dia, tmp, math::identity<scalar_type>(), x);
478 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
481 backend::residual(rhs, A, x, tmp);
482 backend::vmul(prm.damping, *dia, tmp, math::identity<scalar_type>(), x);
485 template <
class Matrix,
class VectorRHS,
class VectorX>
486 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
488 backend::vmul(math::identity<scalar_type>(), *dia, rhs, math::zero<scalar_type>(), x);
493 return backend::bytes(*dia);
509template <
class Backend>
524 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
serial)
526 p.check_params({
"serial" });
529 void get(PropertyTree& p,
const std::string& path)
const
531 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
serial);
538 template <
class Matrix>
543 forward = std::make_shared<parallel_sweep<true>>(A);
544 backward = std::make_shared<parallel_sweep<false>>(A);
549 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
553 serial_sweep(A, rhs, x,
true);
555 forward->sweep(rhs, x);
559 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
563 serial_sweep(A, rhs, x,
false);
565 backward->sweep(rhs, x);
568 template <
class Matrix,
class VectorRHS,
class VectorX>
569 void apply(
const Matrix& A,
const VectorRHS& rhs, VectorX& x)
const
573 serial_sweep(A, rhs, x,
true);
574 serial_sweep(A, rhs, x,
false);
577 forward->sweep(rhs, x);
578 backward->sweep(rhs, x);
586 b += forward->bytes();
588 b += backward->bytes();
594 template <
class Matrix,
class VectorRHS,
class VectorX>
595 static void serial_sweep(
const Matrix& A,
const VectorRHS& rhs, VectorX& x,
bool forward)
597 typedef typename backend::value_type<Matrix>::type val_type;
598 typedef typename math::rhs_of<val_type>::type rhs_type;
600 const ptrdiff_t n = backend::nbRow(A);
602 const ptrdiff_t beg = forward ? 0 : n - 1;
603 const ptrdiff_t end = forward ? n : -1;
604 const ptrdiff_t inc = forward ? 1 : -1;
606 for (ptrdiff_t i = beg; i != end; i += inc) {
607 val_type D = math::identity<val_type>();
611 for (
auto a = backend::row_begin(A, i); a; ++a) {
612 ptrdiff_t c = a.col();
613 val_type v = a.value();
621 x[i] = math::inverse(D) * X;
625 template <
bool forward>
626 struct parallel_sweep
628 typedef typename Backend::value_type value_type;
629 typedef typename math::rhs_of<value_type>::type rhs_type;
634 task(ptrdiff_t beg, ptrdiff_t end)
649 template <
class Matrix>
650 parallel_sweep(
const Matrix& A)
659 ptrdiff_t n = backend::nbRow(A);
666 ptrdiff_t beg = forward ? 0 : n - 1;
667 ptrdiff_t end = forward ? n : -1;
668 ptrdiff_t inc = forward ? 1 : -1;
670 for (ptrdiff_t i = beg; i != end; i += inc) {
671 ptrdiff_t l = level[i];
673 for (
auto a = backend::row_begin(A, i); a; ++a) {
674 ptrdiff_t c = a.col();
685 l = std::max(l, level[c] + 1);
689 nlev = std::max(nlev, l + 1);
693 UniqueArray<ptrdiff_t> start(nlev + 1, 0);
695 for (ptrdiff_t i = 0; i < n; ++i)
696 ++start[level[i] + 1];
698 std::partial_sum(start.begin(), start.end(), start.begin());
700 for (ptrdiff_t i = 0; i < n; ++i)
701 order[start[level[i]]++] = i;
703 std::rotate(start.begin(), start.end() - 1, start.end());
708 UniqueArray<ptrdiff_t> thread_rows(nthreads, 0);
709 UniqueArray<ptrdiff_t> thread_cols(nthreads, 0);
713 for (ptrdiff_t tid = begin; tid < (begin + size); ++tid) {
714 for (ptrdiff_t lev = 0; lev < nlev; ++lev) {
716 ptrdiff_t lev_size = start[lev + 1] - start[lev];
717 ptrdiff_t chunk_size = (lev_size + nthreads - 1) / nthreads;
719 ptrdiff_t beg = std::min(tid * chunk_size, lev_size);
720 ptrdiff_t end = std::min(beg + chunk_size, lev_size);
725 tasks[tid].push_back(
task(beg, end));
728 thread_rows[tid] += end - beg;
729 for (ptrdiff_t i = beg; i < end; ++i) {
730 ptrdiff_t j = order[i];
731 thread_cols[tid] += backend::row_nonzeros(A, j);
739 for (ptrdiff_t tid = begin; tid < (begin + size); ++tid) {
740 col[tid].reserve(thread_cols[tid]);
741 val[tid].reserve(thread_cols[tid]);
742 ord[tid].reserve(thread_rows[tid]);
743 ptr[tid].reserve(thread_rows[tid] + 1);
744 ptr[tid].push_back(0);
745 for (
task& t : tasks[tid]) {
746 ptrdiff_t loc_beg = ptr[tid].size() - 1;
747 ptrdiff_t loc_end = loc_beg;
749 for (ptrdiff_t r = t.beg; r < t.end; ++r, ++loc_end) {
750 ptrdiff_t i = order[r];
752 ord[tid].push_back(i);
754 for (
auto a = backend::row_begin(A, i); a; ++a) {
755 col[tid].push_back(a.col());
756 val[tid].push_back(a.value());
759 ptr[tid].push_back(col[tid].size());
769 template <
class Vector1,
class Vector2>
770 void sweep(
const Vector1& rhs, Vector2& x)
const
773 for (ptrdiff_t tid = 0; tid < nthreads; ++tid) {
774 for (
const task& t : tasks[tid]) {
775 for (ptrdiff_t r = t.beg; r < t.end; ++r) {
776 ptrdiff_t i = ord[tid][r];
777 ptrdiff_t beg = ptr[tid][r];
778 ptrdiff_t end = ptr[tid][r + 1];
780 value_type D = math::identity<value_type>();
784 for (ptrdiff_t j = beg; j < end; ++j) {
785 ptrdiff_t c = col[tid][j];
786 value_type v = val[tid][j];
794 x[i] = math::inverse(D) * X;
808 for (
int i = 0; i < nthreads; ++i) {
809 b +=
sizeof(
task) * tasks[i].size();
810 b += backend::bytes(ptr[i]);
811 b += backend::bytes(col[i]);
812 b += backend::bytes(val[i]);
813 b += backend::bytes(ord[i]);
820 std::shared_ptr<parallel_sweep<true>> forward;
821 std::shared_ptr<parallel_sweep<false>> backward;
833template <
class Backend>
837 typedef typename Backend::value_type value_type;
838 typedef typename Backend::col_type col_type;
839 typedef typename Backend::ptr_type ptr_type;
840 typedef typename Backend::vector vector;
841 typedef typename Backend::matrix matrix;
842 typedef typename Backend::matrix_diagonal matrix_diagonal;
844 typedef typename math::scalar_of<value_type>::type scalar_type;
861 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
damping)
862 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, solve)
864 p.check_params({
"damping",
"solve" }, {
"k" });
867 void get(PropertyTree& p,
const std::string& path)
const
869 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
damping);
870 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, solve);
875 template <
class Matrix>
879 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
880 const size_t n = backend::nbRow(A);
882 size_t Lnz = 0, Unz = 0;
884 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
885 ptrdiff_t row_beg = A.ptr[i];
886 ptrdiff_t row_end = A.ptr[i + 1];
888 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
889 ptrdiff_t c = A.col[j];
897 auto L = std::make_shared<build_matrix>();
898 auto U = std::make_shared<build_matrix>();
901 L->set_nonzeros(Lnz);
904 U->set_nonzeros(Unz);
910 auto D = std::make_shared<numa_vector<value_type>>(n,
false);
914 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
915 ptrdiff_t row_beg = A.ptr[i];
916 ptrdiff_t row_end = A.ptr[i + 1];
918 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
919 ptrdiff_t c = A.col[j];
920 value_type v = A.val[j];
925 work[c] = L->val + Lhead;
935 work[c] = U->val + Uhead;
940 L->ptr[i + 1] = Lhead;
941 U->ptr[i + 1] = Uhead;
943 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
944 ptrdiff_t c = A.col[j];
948 precondition(c == i,
"No diagonal value in system matrix");
949 precondition(!math::is_zero((*D)[i]),
"Zero pivot in ILU");
951 (*D)[i] = math::inverse((*D)[i]);
956 value_type tl = (*work[c]) * (*D)[c];
960 for (ptrdiff_t k = U->ptr[c]; k <
static_cast<ptrdiff_t
>(U->ptr[c + 1]); ++k) {
961 value_type* w = work[U->col[k]];
963 *w -= tl * U->val[k];
971 for (ptrdiff_t j = Lhead, e = L->ptr[i + 1]; j < e; ++j) {
973 if (!math::is_zero(v)) {
974 L->col[Lhead] = L->col[j];
980 for (ptrdiff_t j = Uhead, e = U->ptr[i + 1]; j < e; ++j) {
982 if (!math::is_zero(v)) {
983 U->col[Uhead] = U->col[j];
988 L->ptr[i + 1] = Lhead;
989 U->ptr[i + 1] = Uhead;
992 for (ptrdiff_t j = row_beg; j < row_end; ++j)
993 work[A.col[j]] =
nullptr;
996 L->setNbNonZero(Lhead);
997 U->setNbNonZero(Uhead);
999 ilu = std::make_shared<ilu_solve>(L, U, D, prm.solve, bprm);
1003 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1006 backend::residual(rhs, A, x, tmp);
1008 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1012 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1015 backend::residual(rhs, A, x, tmp);
1017 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1021 template <
class Matrix,
class VectorRHS,
class VectorX>
1024 backend::copy(rhs, x);
1030 return ilu->bytes();
1035 std::shared_ptr<ilu_solve> ilu;
1043template <
class Backend>
1047 typedef typename Backend::value_type value_type;
1048 typedef typename Backend::col_type col_type;
1049 typedef typename Backend::ptr_type ptr_type;
1050 typedef typename Backend::matrix matrix;
1051 typedef typename Backend::matrix_diagonal matrix_diagonal;
1052 typedef typename Backend::vector vector;
1054 typedef typename math::scalar_of<value_type>::type scalar_type;
1076 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
k)
1077 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
damping)
1078 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, solve)
1080 p.check_params({
"k",
"damping",
"solve" });
1083 void get(PropertyTree& p,
const std::string& path)
const
1085 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
k);
1086 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
damping);
1087 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, solve);
1092 template <
class Matrix>
1096 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
1098 const size_t n = backend::nbRow(A);
1100 size_t Anz = backend::nonzeros(A);
1121 auto D = std::make_shared<numa_vector<value_type>>(n,
false);
1125 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
1128 for (
auto a = backend::row_begin(A, i); a; ++a) {
1129 w.add(a.col(), a.value(), 0);
1132 while (!w.q.empty()) {
1133 nonzero& a = w.next_nonzero();
1134 a.val = a.val * (*D)[a.col];
1136 for (ptrdiff_t j = Uptr[a.col], e = Uptr[a.col + 1]; j < e; ++j) {
1137 int lev = std::max(a.lev, Ulev[j]) + 1;
1138 w.add(Ucol[j], -a.val * Uval[j], lev);
1144 for (
const nonzero& e : w.nz) {
1149 else if (e.col == i) {
1150 (*D)[i] = math::inverse(e.val);
1163 ilu = std::make_shared<ilu_solve>(
1164 std::make_shared<build_matrix>(n, n, Lptr, Lcol, Lval),
1165 std::make_shared<build_matrix>(n, n, Uptr, Ucol, Uval),
1166 D, prm.solve, bprm);
1170 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1173 backend::residual(rhs, A, x, tmp);
1175 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1179 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1182 backend::residual(rhs, A, x, tmp);
1184 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1187 template <
class Matrix,
class VectorRHS,
class VectorX>
1188 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
1190 backend::copy(rhs, x);
1196 return ilu->bytes();
1201 std::shared_ptr<ilu_solve> ilu;
1213 nonzero(ptrdiff_t col,
const value_type& val,
int lev)
1219 friend bool operator<(
const nonzero& a,
const nonzero& b)
1221 return a.col < b.col;
1225 struct sparse_vector
1229 const std::deque<nonzero>& nz;
1231 comp_indices(
const std::deque<nonzero>& nz)
1235 bool operator()(
int a,
int b)
const
1237 return nz[a].col > nz[b].col;
1241 typedef std::priority_queue<int, UniqueArray<int>,
comp_indices>
1246 std::deque<nonzero> nz;
1252 sparse_vector(
size_t n,
int lfil)
1259 void add(ptrdiff_t col,
const value_type& val,
int lev)
1271 nonzero& a = nz[idx[col]];
1273 a.lev = std::min(a.lev, lev);
1277 typename std::deque<nonzero>::iterator begin()
1282 typename std::deque<nonzero>::iterator end()
1287 nonzero& next_nonzero()
1296 std::sort(nz.begin(), nz.end());
1299 void reset(ptrdiff_t d)
1301 for (
const nonzero& e : nz)
1314 template <
class Matrix>
1315 std::shared_ptr<Matrix> symb_product(
const Matrix& A,
const Matrix& B)
1317 auto C = std::make_shared<Matrix>();
1319 C->set_size(A.nbRow(), B.ncols);
1321 auto A_ptr = A.ptr.data();
1322 auto A_col = A.col.data();
1323 auto B_ptr = B.ptr.data();
1324 auto B_col = B.col.data();
1325 auto C_ptr = C->ptr.data();
1329 UniqueArray<ptrdiff_t> marker(B.ncols, -1);
1331 for (ptrdiff_t ia = begin; ia < (begin + size); ++ia) {
1332 ptrdiff_t C_cols = 0;
1333 for (ptrdiff_t ja = A_ptr[ia], ea = A_ptr[ia + 1]; ja < ea; ++ja) {
1334 ptrdiff_t ca = A_col[ja];
1336 for (ptrdiff_t jb = B_ptr[ca], eb = B_ptr[ca + 1]; jb < eb; ++jb) {
1337 ptrdiff_t cb = B_col[jb];
1338 if (marker[cb] != ia) {
1344 C_ptr[ia + 1] = C_cols;
1348 C->set_nonzeros(C->scan_row_sizes(),
false);
1349 auto C_col = C->col.data();
1352 UniqueArray<ptrdiff_t> marker(B.ncols, -1);
1354 for (ptrdiff_t ia = begin; ia < (begin + size); ++ia) {
1355 ptrdiff_t row_beg = C_ptr[ia];
1356 ptrdiff_t row_end = row_beg;
1358 for (ptrdiff_t ja = A_ptr[ia], ea = A_ptr[ia + 1]; ja < ea; ++ja) {
1359 ptrdiff_t ca = A_col[ja];
1361 for (ptrdiff_t jb = B_ptr[ca], eb = B_ptr[ca + 1]; jb < eb; ++jb) {
1362 ptrdiff_t cb = B_col[jb];
1364 if (marker[cb] < row_beg) {
1365 marker[cb] = row_end;
1366 C_col[row_end] = cb;
1372 std::sort(C_col + row_beg, C_col + row_end);
1386template <
class Backend>
1390 typedef typename Backend::value_type value_type;
1408 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, k)
1410 p.check_params( {
"k",
"damping",
"solve" });
1413 void get(PropertyTree& p,
const std::string& path)
const
1415 BasePrm::get(p, path);
1416 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, k);
1421 template <
class Matrix>
1426 base = std::make_shared<Base>(A, prm, bprm);
1429 auto P = detail::symb_product(A, A);
1430 for (int k = 1; k < prm.k; ++k) {
1431 P = detail::symb_product(*P, A);
1434 ptrdiff_t n = backend::nbRow(A);
1435 P->val.resize(P->nbNonZero());
1438 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1439 ptrdiff_t p_beg = P->ptr[i];
1440 ptrdiff_t p_end = P->ptr[i + 1];
1441 ptrdiff_t a_beg = A.ptr[i];
1442 ptrdiff_t a_end = A.ptr[i + 1];
1444 std::fill(P->val + p_beg, P->val + p_end, math::zero<value_type>());
1446 for (ptrdiff_t ja = a_beg, ea = a_end, jp = p_beg, ep = p_end; ja < ea; ++ja) {
1447 ptrdiff_t ca = A.col[ja];
1448 while (jp < ep && P->col[jp] < ca)
1450 if (P->col[jp] == ca)
1451 P->val[jp] = A.val[ja];
1456 base = std::make_shared<Base>(*P, prm, bprm);
1461 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1464 base->apply_pre(A, rhs, x, tmp);
1468 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1471 base->apply_post(A, rhs, x, tmp);
1474 template <
class Matrix,
class VectorRHS,
class VectorX>
1475 void apply(
const Matrix& A,
const VectorRHS& rhs, VectorX& x)
const
1477 base->apply(A, rhs, x);
1482 return base->bytes();
1487 std::shared_ptr<Base> base;
1500template <
class Backend>
1504 typedef typename Backend::value_type value_type;
1505 typedef typename Backend::col_type col_type;
1506 typedef typename Backend::ptr_type ptr_type;
1507 typedef typename Backend::matrix matrix;
1508 typedef typename Backend::matrix_diagonal matrix_diagonal;
1509 typedef typename Backend::vector vector;
1511 typedef typename math::scalar_of<value_type>::type scalar_type;
1533 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(
p,
p)
1534 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(
p,
tau)
1535 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(
p,
damping)
1536 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(
p,
solve)
1538 p.check_params( {
"p",
"tau",
"damping",
"solve" });
1541 void get(
PropertyTree& p,
const std::string& path)
const
1543 double p2 = this->p;
1544 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, p2);
1545 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, tau);
1546 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, damping);
1547 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, solve);
1552 template <
class Matrix>
1556 const size_t n = backend::nbRow(A);
1558 size_t Lnz = 0, Unz = 0;
1560 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
1561 ptrdiff_t row_beg = A.ptr[i];
1562 ptrdiff_t row_end = A.ptr[i + 1];
1564 int lenL = 0, lenU = 0;
1565 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
1566 ptrdiff_t c = A.col[j];
1573 Lnz +=
static_cast<size_t>(lenL * prm.p);
1574 Unz +=
static_cast<size_t>(lenU * prm.p);
1577 auto L = std::make_shared<build_matrix>();
1578 auto U = std::make_shared<build_matrix>();
1581 L->set_nonzeros(Lnz);
1584 U->set_nonzeros(Unz);
1587 auto D = std::make_shared<numa_vector<value_type>>(n,
false);
1591 for (ptrdiff_t i = 0, Lhead = 0, Uhead = 0; i < static_cast<ptrdiff_t>(n); ++i) {
1597 scalar_type tol = math::zero<scalar_type>();
1599 for (
auto a = backend::row_begin(A, i); a; ++a) {
1600 w[a.col()] = a.value();
1601 tol += math::norm(a.value());
1608 tol *= prm.tau / (lenL + lenU);
1610 while (!w.q.empty()) {
1611 ptrdiff_t k = w.next_nonzero();
1612 w[k] = w[k] * (*D)[k];
1613 value_type wk = w[k];
1615 if (math::norm(wk) > tol) {
1616 for (ptrdiff_t j = U->ptr[k]; j <
static_cast<ptrdiff_t
>(U->ptr[k + 1]); ++j)
1617 w[U->col[j]] -= wk * U->val[j];
1622 static_cast<int>(lenL * prm.p),
1623 static_cast<int>(lenU * prm.p),
1624 tol, Lhead, *L, Uhead, *U, *D);
1626 L->ptr[i + 1] = Lhead;
1627 U->ptr[i + 1] = Uhead;
1630 L->setNbNonZero(L->ptr[n]);
1631 U->setNbNonZero(U->ptr[n]);
1633 ilu = std::make_shared<ilu_solve>(L, U, D, prm.solve, bprm);
1637 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1640 backend::residual(rhs, A, x, tmp);
1642 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1646 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1649 backend::residual(rhs, A, x, tmp);
1651 backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
1654 template <
class Matrix,
class VectorRHS,
class VectorX>
1655 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
1657 backend::copy(rhs, x);
1663 return ilu->bytes();
1668 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
1669 std::shared_ptr<ilu_solve> ilu;
1671 struct sparse_vector
1682 nonzero(ptrdiff_t col,
const value_type& val = math::zero<value_type>())
1696 bool operator()(
int a,
int b)
const
1698 return nz[a].col > nz[b].col;
1702 typedef std::priority_queue<int, UniqueArray<int>,
comp_indices> priority_queue;
1710 sparse_vector(
size_t n)
1718 value_type operator[](ptrdiff_t i)
const
1721 return nz[idx[i]].val;
1722 return math::zero<value_type>();
1725 value_type& operator[](ptrdiff_t i)
1734 return nz[idx[i]].val;
1737 typename UniqueArray<nonzero>::iterator begin()
1742 typename UniqueArray<nonzero>::iterator end()
1747 ptrdiff_t next_nonzero()
1759 higher_than(scalar_type tol, ptrdiff_t dia)
1764 bool operator()(
const nonzero& v)
const
1766 return v.col == dia || math::norm(v.val) > tol;
1774 L_first(ptrdiff_t dia)
1778 bool operator()(
const nonzero& v)
const
1788 by_abs_val(ptrdiff_t dia)
1799 return math::norm(a.val) > math::norm(b.val);
1807 return a.col < b.col;
1811 void move_to(
int lp,
int up, scalar_type tol,
1812 ptrdiff_t& Lhead, build_matrix& L,
1813 ptrdiff_t& Uhead, build_matrix& U,
1825 ptr m = std::partition(b, e,
L_first(dia));
1828 ptr lend = std::min(b + lp, m);
1829 ptr uend = std::min(m + up, e);
1832 std::nth_element(b, lend, m,
by_abs_val(dia));
1834 std::nth_element(m, uend, e,
by_abs_val(dia));
1837 std::sort(b, lend,
by_col());
1838 std::sort(m, uend,
by_col());
1841 for (ptr a = b; a != lend; ++a) {
1842 L.col[Lhead] = a->col;
1843 L.val[Lhead] = a->val;
1849 D[dia] = math::inverse(m->val);
1855 for (ptr a = m; a != uend; ++a) {
1856 U.col[Uhead] = a->col;
1857 U.val[Uhead] = a->val;
1863 for (
const nonzero& e : nz)
1881template <
class Backend>
1885 typedef typename Backend::value_type value_type;
1886 typedef typename Backend::matrix_diagonal matrix_diagonal;
1888 typedef typename math::scalar_of<value_type>::type scalar_type;
1893 template <
class Matrix>
1896 const size_t n = backend::nbRow(A);
1898 auto m = std::make_shared<numa_vector<value_type>>(n,
false);
1901 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1902 value_type num = math::zero<value_type>();
1903 scalar_type den = math::zero<scalar_type>();
1905 for (
auto a = backend::row_begin(A, i); a; ++a) {
1906 value_type v = a.value();
1907 scalar_type norm_v = math::norm(v);
1908 den += norm_v * norm_v;
1913 (*m)[i] = math::inverse(den) * num;
1917 M = Backend::copy_vector(m, backend_prm);
1921 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1924 static const scalar_type one = math::identity<scalar_type>();
1925 backend::residual(rhs, A, x, tmp);
1926 backend::vmul(one, *M, tmp, one, x);
1930 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
1933 static const scalar_type one = math::identity<scalar_type>();
1934 backend::residual(rhs, A, x, tmp);
1935 backend::vmul(one, *M, tmp, one, x);
1938 template <
class Matrix,
class VectorRHS,
class VectorX>
1939 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
1941 backend::vmul(math::identity<scalar_type>(), *M, rhs, math::zero<scalar_type>(), x);
1946 return backend::bytes(*M);
1949 std::shared_ptr<matrix_diagonal> M;
1963template <
class Backend>
1967 typedef typename Backend::value_type value_type;
1968 typedef typename Backend::vector vector;
1970 typedef typename math::scalar_of<value_type>::type scalar_type;
1976 template <
class Matrix>
1979 typedef typename backend::value_type<Matrix>::type value_type;
1981 const size_t n = backend::nbRow(A);
1982 const size_t m = backend::nbColumn(A);
1984 auto Ainv = std::make_shared<Matrix>(A);
1992 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1993 ptrdiff_t row_beg = A.ptr[i];
1994 ptrdiff_t row_end = A.ptr[i + 1];
1996 I.
assign(A.col + row_beg, A.col + row_end);
1999 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
2000 ptrdiff_t c = A.col[j];
2002 for (ptrdiff_t jj = A.ptr[c], ee = A.ptr[c + 1]; jj < ee; ++jj) {
2003 ptrdiff_t cc = A.col[jj];
2004 if (marker[cc] < 0) {
2011 B.assign(I.
size() * J.
size(), math::zero<value_type>());
2012 ek.
assign(J.
size(), math::zero<value_type>());
2013 for (
size_t j = 0; j < J.
size(); ++j) {
2015 if (J[j] ==
static_cast<ptrdiff_t
>(i))
2016 ek[j] = math::identity<value_type>();
2019 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
2020 ptrdiff_t c = A.col[j];
2022 for (
auto a = backend::row_begin(A, c); a; ++a)
2023 B[marker[a.col()] + J.
size() * (j - row_beg)] = a.value();
2026 qr.solve(J.
size(), I.
size(), &B[0], &ek[0], &Ainv->val[row_beg],
2027 Alina::detail::col_major);
2029 for (
size_t j = 0; j < J.
size(); ++j)
2034 M = Backend::copy_matrix(Ainv, backend_prm);
2038 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
2041 backend::residual(rhs, A, x, tmp);
2042 backend::spmv(math::identity<scalar_type>(), *M, tmp, math::identity<scalar_type>(), x);
2046 template <
class Matrix,
class VectorRHS,
class VectorX,
class VectorTMP>
2049 backend::residual(rhs, A, x, tmp);
2050 backend::spmv(math::identity<scalar_type>(), *M, tmp, math::identity<scalar_type>(), x);
2053 template <
class Matrix,
class VectorRHS,
class VectorX>
2054 void apply(
const Matrix&,
const VectorRHS& rhs, VectorX& x)
const
2056 backend::spmv(math::identity<scalar_type>(), *M, rhs, math::zero<scalar_type>(), x);
2061 return backend::bytes(*M);
2064 std::shared_ptr<typename Backend::matrix> M;
2075namespace Arcane::Alina::backend
2078template <
class Backend>
2080 typename std::enable_if<(Alina::math::static_rows<typename Backend::value_type>::value > 1)>
::type> : std::false_type
2083template <
class Backend>
2085 typename std::enable_if<
2086 !Backend::provides_row_iterator::value>
::type> : std::false_type
Integer size() const
Number of elements in the vector.
ArrayIterator< pointer > iterator
Type of the iterator over an array element.
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 store parameters as a hierarchical key/value tree.
Class to handle empty parameter list.
NUMA-aware vector container.
void clear()
Removes the elements from the array.
iterator begin()
Iterator over the first element of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
void push_back(ConstReferenceType val)
Adds the element val to the end of the array.
void assign(InputIterator first, InputIterator last)
Replaces the contents of the instance with copies of those in the range [first, \alast).
iterator end()
Iterator over the first element after the end of the array.
Basic information for multi-threading management.
Loop execution information.
Matrix class, to be used by user.
1D data vector with value semantics (STL style).
void arccoreParallelFor(const ComplexForLoopRanges< RankValue, IndexType_ > &loop_ranges, const ForLoopRunInfo &run_info, const LambdaType &lambda_function, const ReducerArgs &... reducer_args)
Applies the lambda function lambda_function concurrently over the iteration interval given by loop_ra...
std::int32_t Int32
Signed integer type of 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.