30 template<
typename T> constexpr
auto always_false_v =
false;
32 template<
typename T> concept floating_t = std::is_same_v<T, float> || std::is_same_v<T, double>;
33 template<
typename T> concept complex_t = std::is_same_v<T, std::complex<typename T::value_type>> && floating_t<typename T::value_type>;
34 template<
typename T> concept data_t = floating_t<T> || complex_t<T>;
35 template<
typename T> concept index_t = std::is_same_v<T, std::int32_t> || std::is_same_v<T, std::int64_t>;
37 template<
typename T> concept has_mem = requires(T t) { requires data_t<std::remove_pointer_t<decltype(t.mem())>>; };
38 template<
typename T> concept has_memptr = requires(T t) { requires data_t<std::remove_pointer_t<decltype(t.memptr())>>; };
39 template<
typename T> concept has_data_method = requires(T t) { requires data_t<std::remove_pointer_t<decltype(t.data())>>; };
40 template<
typename T> concept has_data_member = requires(T t) { requires data_t<std::remove_pointer_t<decltype(t.data)>>; };
41 template<
typename T> concept has_iterator = requires(T t) {
42 requires std::ranges::contiguous_range<T>;
43 requires data_t<std::remove_reference_t<decltype(*t.begin())>>;
45 template<
typename T> concept has_data_pointer = has_mem<T> || has_memptr<T> || has_data_method<T> || has_iterator<T>;
47 template<
typename T> concept full_container_t = requires(T t) { requires index_t<decltype(t.n_rows)> && index_t<decltype(t.n_cols)> && has_data_pointer<T>; };
48 template<
typename T> concept band_container_t = requires(T t) { requires index_t<decltype(t.kl)> && index_t<decltype(t.ku)> && full_container_t<T>; };
49 template<
typename T> concept band_symm_container_t = requires(T t) { requires index_t<decltype(t.klu)> && full_container_t<T>; };
52 static_assert(!std::is_same_v<T, T>,
"not defined");
68 template<data_t DT, index_t IT>
struct base_mat {
70 using index_type = IT;
78 base_mat(
const IT rows,
const IT cols, DT*
const ptr,
const bool dist =
false)
82 , distributed(dist) {}
94 band_mat(
const IT rows,
const IT cols,
const IT kl,
const IT ku, DT*
const ptr,
const bool dist =
false)
105 band_symm_mat(
const IT rows,
const IT cols,
const IT klu, DT*
const ptr,
const bool dist =
false)
110 template<
typename T> concept wrapper_t = requires(T t) {
111 requires std::is_same_v<T, full_mat<typename T::data_type, typename T::index_type>> || std::is_same_v<T, band_mat<typename T::data_type, typename T::index_type>> || std::is_same_v<T, band_symm_mat<typename T::data_type, typename T::index_type>>;
114 template<index_t IT>
using desc = std::array<IT, 9>;
117 #ifdef EZP_RELEASE_ONCE
119 static std::atomic_bool RELEASED;
123 #ifdef EZP_RELEASE_ONCE
124 #define EZP_ENSURE_SAFE_EXIT std::atomic_bool ezp::blacs_base::RELEASED = false;
128 static constexpr IT ZERO{0}, ONE{1};
130 static std::atomic_bool FINALIZE;
132 IT _rank{-1}, _size{-1};
135 blacs_env() { blacs_pinfo(&_rank, &_size); }
138 #ifdef EZP_RELEASE_ONCE
139 if(RELEASED.exchange(
true))
return;
141 blacs_exit(FINALIZE ? &ZERO : &ONE);
153 auto rank()
const {
return _rank; }
154 auto size()
const {
return _size; }
157 template<index_t IT> std::atomic_bool blacs_env<IT>::FINALIZE{
true};
170 template<index_t IT =
int_t>
const auto& get_env() {
171 static const blacs_env<IT> scoped_env;
177 static constexpr IT ZERO{0}, ONE{1}, NEGONE{-1};
178 static constexpr
char SCOPE =
'A', TOP =
' ';
185 blacs_get(&NEGONE, &ZERO, &context);
186 blacs_gridinit(&context, &layout, &n_rows, &n_cols);
187 blacs_pinfo(&rank, &size);
188 blacs_gridinfo(&context, &n_rows, &n_cols, &my_row, &my_col);
192 if(context >= 0) blacs_gridexit(&context);
211 template<data_t DT>
auto copy_to(
const DT* A,
const IT* desc_a, DT* B,
const IT* desc_b) {
213 if(std::is_same_v<DT, double>) {
215 pdgemr2d(desc_a + 2, desc_a + 3, (E*)A, &ONE, &ONE, desc_a, (E*)B, &ONE, &ONE, desc_b, &context);
217 else if(std::is_same_v<DT, float>) {
219 psgemr2d(desc_a + 2, desc_a + 3, (E*)A, &ONE, &ONE, desc_a, (E*)B, &ONE, &ONE, desc_b, &context);
221 else if(std::is_same_v<DT, complex16>) {
223 pzgemr2d(desc_a + 2, desc_a + 3, (E*)A, &ONE, &ONE, desc_a, (E*)B, &ONE, &ONE, desc_b, &context);
225 else if(std::is_same_v<DT, complex8>) {
227 pcgemr2d(desc_a + 2, desc_a + 3, (E*)A, &ONE, &ONE, desc_a, (E*)B, &ONE, &ONE, desc_b, &context);
233 IT n_rows, n_cols, context{-1}, rank{-1}, size{-1}, my_row{-1}, my_col{-1};
242 const auto& env = get_env<IT>();
243 n_rows = std::max(IT{1},
static_cast<IT
>(std::sqrt(env.size())));
244 n_cols = env.size() / n_rows;
251 , n_cols(
cols) { init(); }
254 : layout(other.layout)
255 , n_rows(other.n_rows)
256 , n_cols(other.n_cols) { init(); }
275 auto desc_g(
const IT num_rows,
const IT num_cols) {
278 descinit(desc_t.data(), &num_rows, &num_cols, &num_rows, &num_cols, &ZERO, &ZERO, &context, &num_rows, &info);
300 const auto loc_lead = std::max(IT{1}, lead);
301 descinit(desc_t.data(), &num_rows, &num_cols, &
row_block, &
col_block, &ZERO, &ZERO, &context, &loc_lead, &info);
306 auto desc_l(
const IT num_rows,
const IT num_cols,
const IT block,
const IT lead) {
return desc_l(num_rows, num_cols, block, block, lead); }
308 template<data_t DT>
auto scatter(
const full_mat<DT, IT>& A,
const desc<IT>& desc_a, std::vector<DT>& B,
const desc<IT>& desc_b) {
309 if(!A.distributed)
return copy_to(A.data, desc_a.data(), B.data(), desc_b.data());
311 for(
auto i = 0u; i < B.size(); ++i) B[i] = A.data[i];
314 template<data_t DT>
auto gather(
const std::vector<DT>& A,
const desc<IT>& desc_a,
const full_mat<DT, IT>& B,
const desc<IT>& desc_b) {
315 if(!B.distributed)
return copy_to(A.data(), desc_a.data(), B.data, desc_b.data());
317 for(
auto i = 0u; i < A.size(); ++i) B.data[i] = A[i];
320 auto copy_to(
const IT* A,
const IT* desc_a, IT* B,
const IT* desc_b) { pigemr2d(desc_a + 2, desc_a + 3, A, &ONE, &ONE, desc_a, B, &ONE, &ONE, desc_b, &context); }
322 [[nodiscard]]
bool is_valid()
const {
return my_row >= 0 && my_col >= 0; }
327 auto row_block(
const IT n)
const {
return std::max(IT{1}, n / n_rows); }
332 auto col_block(
const IT n)
const {
return std::max(IT{1}, n / n_cols); }
344 auto rows(
const IT n,
const IT nb)
const {
return numroc(&n, &nb, &my_row, &ZERO, &n_rows); }
356 auto cols(
const IT n,
const IT nb)
const {
return numroc(&n, &nb, &my_col, &ZERO, &n_cols); }
372 igamx2d(&context, &SCOPE, &TOP, &ONE, &ONE, &number, &ONE,
nullptr,
nullptr, &NEGONE, &NEGONE, &NEGONE);
390 igamn2d(&context, &SCOPE, &TOP, &ONE, &ONE, &number, &ONE,
nullptr,
nullptr, &NEGONE, &NEGONE, &NEGONE);
Definition: traits.hpp:116
Definition: traits.hpp:176
IT amn(IT number) const
Perform the global amn operation.
Definition: traits.hpp:389
auto desc_l(const IT num_rows, const IT num_cols, const IT row_block, const IT col_block, const IT lead)
Generates a descriptor for a local matrix.
Definition: traits.hpp:297
auto rows(const IT n, const IT nb) const
Computes the number of local rows of the current process.
Definition: traits.hpp:344
auto col_block(const IT n) const
Computes the column block size.
Definition: traits.hpp:332
auto row_block(const IT n) const
Computes the row block size.
Definition: traits.hpp:327
IT amx(IT number) const
Perform the global amx operation.
Definition: traits.hpp:371
auto cols(const IT n, const IT nb) const
Computes the number of local columns of the current process.
Definition: traits.hpp:356
auto desc_g(const IT num_rows, const IT num_cols)
Generates a descriptor for a global matrix.
Definition: traits.hpp:275
Definition: traits.hpp:127
static void do_not_manage_mpi()
Disables the management of MPI (Message Passing Interface) finalization.
Definition: traits.hpp:151
Definition: traits.hpp:51
Definition: traits.hpp:89
Definition: traits.hpp:100
Definition: traits.hpp:68
Definition: traits.hpp:85