Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
MatrixPartitionUtils.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* MatrixPartitionUtils.h (C) 2000-2026 */
9/* */
10/* Utils for matrix repartitioning. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_MATRIXPARTITIONUTILS_H
13#define ARCCORE_ALINA_MATRIXPARTITIONUTILS_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16/*
17 * This file is based on the work on AMGCL library (version march 2026)
18 * which can be found at https://github.com/ddemidov/amgcl.
19 *
20 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
21 * SPDX-License-Identifier: MIT
22 */
23/*---------------------------------------------------------------------------*/
24/*---------------------------------------------------------------------------*/
25
26#include "arccore/alina/BackendInterface.h"
27#include "arccore/alina/DistributedMatrix.h"
28
30
31#include <vector>
32#include <algorithm>
33#include <numeric>
34
35#include <tuple>
36
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
39
40namespace Arcane::Alina
41{
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
45
46template <class Backend, class Ptr, class Col> void
47mpi_symm_graph(const DistributedMatrix<Backend>& A,
48 std::vector<Ptr>& ptr, std::vector<Col>& col)
49{
50 using build_matrix = Backend::matrix;
51
52 ARCCORE_ALINA_TIC("symm graph");
53
54 build_matrix& A_loc = *A.local();
55 build_matrix& A_rem = *A.remote();
56
57 ptrdiff_t n = A_loc.nbRow();
58 ptrdiff_t row_beg = A.loc_col_shift();
59
60 auto T = transpose(A);
61
62 build_matrix& T_loc = *T->local();
63 build_matrix& T_rem = *T->remote();
64
65 // Build symmetric graph
66 ptr.resize(n + 1, 0);
67
68 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
69 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
70 using Alina::detail::sort_row;
71
72 ptrdiff_t A_loc_beg = A_loc.ptr[i];
73 ptrdiff_t A_loc_end = A_loc.ptr[i + 1];
74
75 ptrdiff_t A_rem_beg = A_rem.ptr[i];
76 ptrdiff_t A_rem_end = A_rem.ptr[i + 1];
77
78 ptrdiff_t T_loc_beg = T_loc.ptr[i];
79 ptrdiff_t T_loc_end = T_loc.ptr[i + 1];
80
81 ptrdiff_t T_rem_beg = T_rem.ptr[i];
82 ptrdiff_t T_rem_end = T_rem.ptr[i + 1];
83
84 sort_row(A_loc.col + A_loc_beg, A_loc.val + A_loc_beg, A_loc_end - A_loc_beg);
85 sort_row(A_rem.col + A_rem_beg, A_rem.val + A_rem_beg, A_rem_end - A_rem_beg);
86
87 sort_row(T_loc.col + T_loc_beg, T_loc.val + T_loc_beg, T_loc_end - T_loc_beg);
88 sort_row(T_rem.col + T_rem_beg, T_rem.val + T_rem_beg, T_rem_end - T_rem_beg);
89
90 Ptr row_width = 0;
91
92 for (ptrdiff_t ja = A_loc_beg, jt = T_loc_beg; ja < A_loc_end || jt < T_loc_end;) {
93 ptrdiff_t c;
94 if (ja == A_loc_end) {
95 c = T_loc.col[jt];
96 ++jt;
97 }
98 else if (jt == T_loc_end) {
99 c = A_loc.col[ja];
100 ++ja;
101 }
102 else {
103 ptrdiff_t ca = A_loc.col[ja];
104 ptrdiff_t ct = T_loc.col[jt];
105 if (ca < ct) {
106 c = ca;
107 ++ja;
108 }
109 else if (ca == ct) {
110 c = ca;
111 ++ja;
112 ++jt;
113 }
114 else {
115 c = ct;
116 ++jt;
117 }
118 }
119
120 if (c != i)
121 ++row_width;
122 }
123
124 for (ptrdiff_t ja = A_rem_beg, jt = T_rem_beg; ja < A_rem_end || jt < T_rem_end;) {
125 if (ja == A_rem_end) {
126 ++jt;
127 }
128 else if (jt == T_rem_end) {
129 ++ja;
130 }
131 else {
132 ptrdiff_t ca = A_rem.col[ja];
133 ptrdiff_t ct = T_rem.col[jt];
134 if (ca < ct) {
135 ++ja;
136 }
137 else if (ca == ct) {
138 ++ja;
139 ++jt;
140 }
141 else {
142 ++jt;
143 }
144 }
145
146 ++row_width;
147 }
148
149 ptr[i + 1] = row_width;
150 }
151 });
152
153 std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());
154
155 col.resize(ptr.back());
156 if (col.empty())
157 col.reserve(1); // So that col.data() is not NULL
158
159 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
160 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
161 ptrdiff_t A_loc_beg = A_loc.ptr[i];
162 ptrdiff_t A_loc_end = A_loc.ptr[i + 1];
163
164 ptrdiff_t A_rem_beg = A_rem.ptr[i];
165 ptrdiff_t A_rem_end = A_rem.ptr[i + 1];
166
167 ptrdiff_t T_loc_beg = T_loc.ptr[i];
168 ptrdiff_t T_loc_end = T_loc.ptr[i + 1];
169
170 ptrdiff_t T_rem_beg = T_rem.ptr[i];
171 ptrdiff_t T_rem_end = T_rem.ptr[i + 1];
172
173 Ptr head = ptr[i];
174
175 for (ptrdiff_t ja = A_loc_beg, jt = T_loc_beg; ja < A_loc_end || jt < T_loc_end;) {
176 ptrdiff_t c;
177 if (ja == A_loc_end) {
178 c = T_loc.col[jt];
179 ++jt;
180 }
181 else if (jt == T_loc_end) {
182 c = A_loc.col[ja];
183 ++ja;
184 }
185 else {
186 ptrdiff_t ca = A_loc.col[ja];
187 ptrdiff_t ct = T_loc.col[jt];
188
189 if (ca < ct) {
190 c = ca;
191 ++ja;
192 }
193 else if (ca == ct) {
194 c = ca;
195 ++ja;
196 ++jt;
197 }
198 else {
199 c = ct;
200 ++jt;
201 }
202 }
203 if (c != i)
204 col[head++] = c + row_beg;
205 }
206
207 for (ptrdiff_t ja = A_rem_beg, jt = T_rem_beg; ja < A_rem_end || jt < T_rem_end;) {
208 if (ja == A_rem_end) {
209 col[head] = T_rem.col[jt];
210 ++jt;
211 }
212 else if (jt == T_rem_end) {
213 col[head] = A_rem.col[ja];
214 ++ja;
215 }
216 else {
217 ptrdiff_t ca = A_rem.col[ja];
218 ptrdiff_t ct = T_rem.col[jt];
219
220 if (ca < ct) {
221 col[head] = ca;
222 ++ja;
223 }
224 else if (ca == ct) {
225 col[head] = ca;
226 ++ja;
227 ++jt;
228 }
229 else {
230 col[head] = ct;
231 ++jt;
232 }
233 }
234 ++head;
235 }
236 }
237 });
238
239 ARCCORE_ALINA_TOC("symm graph");
240}
241
242/*---------------------------------------------------------------------------*/
243/*---------------------------------------------------------------------------*/
244
245template <class Idx> std::tuple<ptrdiff_t, ptrdiff_t>
246mpi_graph_perm_index(AlinaCommunicator comm, int npart, const std::vector<Idx>& part,
247 std::vector<ptrdiff_t>& perm)
248{
249 ARCCORE_ALINA_TIC("perm index");
250 ptrdiff_t n = part.size();
251 perm.resize(n);
252
253 std::vector<ptrdiff_t> loc_part_cnt(npart, 0);
254 std::vector<ptrdiff_t> loc_part_beg(npart, 0);
255 std::vector<ptrdiff_t> glo_part_cnt(npart);
256 std::vector<ptrdiff_t> glo_part_beg(npart + 1);
257
258 for (Idx p : part)
259 ++loc_part_cnt[p];
260 MPI_Datatype ptr_datatype = MPI_LONG_LONG;
261 MPI_Exscan(loc_part_cnt.data(), loc_part_beg.data(), npart, ptr_datatype, MPI_SUM, comm.mpiCommunicator());
262
263 Span<const ptrdiff_t> loc_part_cnt_view(loc_part_cnt.data(), npart);
264 Span<ptrdiff_t> glo_part_cnt_view(glo_part_cnt.data(), npart);
265 glo_part_cnt_view.copy(loc_part_cnt_view);
266 mpAllReduce(comm.messagePassingMng(), Arcane::MessagePassing::eReduceType::ReduceSum, glo_part_cnt_view);
267 glo_part_beg[0] = 0;
268 std::partial_sum(glo_part_cnt.begin(), glo_part_cnt.end(), glo_part_beg.begin() + 1);
269
270 std::vector<ptrdiff_t> cnt(npart, 0);
271 for (ptrdiff_t i = 0; i < n; ++i) {
272 Idx p = part[i];
273 perm[i] = glo_part_beg[p] + loc_part_beg[p] + cnt[p]++;
274 }
275
276 ARCCORE_ALINA_TOC("perm index");
277 return std::make_tuple(
278 glo_part_beg[std::min(npart, comm.rank)],
279 glo_part_beg[std::min(npart, comm.rank + 1)]);
280}
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
284
285template <class Backend, class Idx>
286std::shared_ptr<DistributedMatrix<Backend>>
287mpi_graph_perm_matrix(AlinaCommunicator comm, ptrdiff_t col_beg, ptrdiff_t col_end,
288 const std::vector<Idx>& perm)
289{
290 typedef typename Backend::value_type value_type;
291 using build_matrix = Backend::matrix;
292
293 ARCCORE_ALINA_TIC("perm matrix");
294
295 ptrdiff_t n = perm.size();
296 ptrdiff_t ncols = col_end - col_beg;
297
298 auto i_loc = std::make_shared<build_matrix>();
299 auto i_rem = std::make_shared<build_matrix>();
300
301 build_matrix& I_loc = *i_loc;
302 build_matrix& I_rem = *i_rem;
303
304 I_loc.set_size(n, ncols, false);
305 I_rem.set_size(n, 0, false);
306
307 I_loc.ptr[0] = 0;
308 I_rem.ptr[0] = 0;
309
310 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
311 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
312 ptrdiff_t j = perm[i];
313
314 if (col_beg <= j && j < col_end) {
315 I_loc.ptr[i + 1] = 1;
316 I_rem.ptr[i + 1] = 0;
317 }
318 else {
319 I_loc.ptr[i + 1] = 0;
320 I_rem.ptr[i + 1] = 1;
321 }
322 }
323 });
324
325 I_loc.set_nonzeros(I_loc.scan_row_sizes());
326 I_rem.set_nonzeros(I_rem.scan_row_sizes());
327
328 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
329 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
330 ptrdiff_t j = perm[i];
331
332 if (col_beg <= j && j < col_end) {
333 ptrdiff_t k = I_loc.ptr[i];
334 I_loc.col[k] = j - col_beg;
335 I_loc.val[k] = math::identity<value_type>();
336 }
337 else {
338 ptrdiff_t k = I_rem.ptr[i];
339 I_rem.col[k] = j;
340 I_rem.val[k] = math::identity<value_type>();
341 }
342 }
343 });
344
345 ARCCORE_ALINA_TOC("perm matrix");
346 return std::make_shared<DistributedMatrix<Backend>>(comm, i_loc, i_rem);
347}
348
349/*---------------------------------------------------------------------------*/
350/*---------------------------------------------------------------------------*/
351
352} // namespace Arcane::Alina
353
354/*---------------------------------------------------------------------------*/
355/*---------------------------------------------------------------------------*/
356
357#endif
Brief list of message exchange functions.
Distributed Matrix using message passing.
C char mpAllReduce(IMessagePassingMng *pm, eReduceType rt, char v)
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...
Definition ParallelFor.h:86
std::int32_t Int32
Signed integer type of 32 bits.
Convenience wrapper around MPI_Comm.