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 UniqueArray<ptrdiff_t> loc_part_cnt(npart, 0);
254 UniqueArray<ptrdiff_t> loc_part_beg(npart, 0);
255 UniqueArray<ptrdiff_t> glo_part_cnt(npart);
256 UniqueArray<ptrdiff_t> glo_part_beg(npart + 1);
257
258 for (Idx p : part)
259 ++loc_part_cnt[p];
260 auto reduce_operation = Arcane::MessagePassing::eReduceType::ReduceSum;
261 mpScanExclusive(comm.messagePassingMng(), reduce_operation, loc_part_cnt, loc_part_beg);
262 Span<const ptrdiff_t> loc_part_cnt_view(loc_part_cnt);
263 Span<ptrdiff_t> glo_part_cnt_view(glo_part_cnt);
264 mpAllReduce(comm.messagePassingMng(), reduce_operation, loc_part_cnt_view, glo_part_cnt_view);
265 glo_part_beg[0] = 0;
266 std::partial_sum(glo_part_cnt.begin(), glo_part_cnt.end(), glo_part_beg.begin() + 1);
267
268 UniqueArray<ptrdiff_t> cnt(npart, 0);
269 for (ptrdiff_t i = 0; i < n; ++i) {
270 Idx p = part[i];
271 perm[i] = glo_part_beg[p] + loc_part_beg[p] + cnt[p]++;
272 }
273
274 ARCCORE_ALINA_TOC("perm index");
275 return std::make_tuple(glo_part_beg[std::min(npart, comm.rank)],
276 glo_part_beg[std::min(npart, comm.rank + 1)]);
277}
278
279/*---------------------------------------------------------------------------*/
280/*---------------------------------------------------------------------------*/
281
282template <class Backend, class Idx>
283std::shared_ptr<DistributedMatrix<Backend>>
284mpi_graph_perm_matrix(AlinaCommunicator comm, ptrdiff_t col_beg, ptrdiff_t col_end,
285 const std::vector<Idx>& perm)
286{
287 typedef typename Backend::value_type value_type;
288 using build_matrix = Backend::matrix;
289
290 ARCCORE_ALINA_TIC("perm matrix");
291
292 ptrdiff_t n = perm.size();
293 ptrdiff_t ncols = col_end - col_beg;
294
295 auto i_loc = std::make_shared<build_matrix>();
296 auto i_rem = std::make_shared<build_matrix>();
297
298 build_matrix& I_loc = *i_loc;
299 build_matrix& I_rem = *i_rem;
300
301 I_loc.set_size(n, ncols, false);
302 I_rem.set_size(n, 0, false);
303
304 I_loc.ptr[0] = 0;
305 I_rem.ptr[0] = 0;
306
307 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
308 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
309 ptrdiff_t j = perm[i];
310
311 if (col_beg <= j && j < col_end) {
312 I_loc.ptr[i + 1] = 1;
313 I_rem.ptr[i + 1] = 0;
314 }
315 else {
316 I_loc.ptr[i + 1] = 0;
317 I_rem.ptr[i + 1] = 1;
318 }
319 }
320 });
321
322 I_loc.set_nonzeros(I_loc.scan_row_sizes());
323 I_rem.set_nonzeros(I_rem.scan_row_sizes());
324
325 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
326 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
327 ptrdiff_t j = perm[i];
328
329 if (col_beg <= j && j < col_end) {
330 ptrdiff_t k = I_loc.ptr[i];
331 I_loc.col[k] = j - col_beg;
332 I_loc.val[k] = math::identity<value_type>();
333 }
334 else {
335 ptrdiff_t k = I_rem.ptr[i];
336 I_rem.col[k] = j;
337 I_rem.val[k] = math::identity<value_type>();
338 }
339 }
340 });
341
342 ARCCORE_ALINA_TOC("perm matrix");
343 return std::make_shared<DistributedMatrix<Backend>>(comm, i_loc, i_rem);
344}
345
346/*---------------------------------------------------------------------------*/
347/*---------------------------------------------------------------------------*/
348
349} // namespace Arcane::Alina
350
351/*---------------------------------------------------------------------------*/
352/*---------------------------------------------------------------------------*/
353
354#endif
Brief list of message exchange functions.
Distributed Matrix using message passing.
C char mpAllReduce(IMessagePassingMng *pm, eReduceType rt, char v)
C void mpScanExclusive(IMessagePassingMng *pm, eReduceType rt, Span< const char > send_buf, Span< char > receive_buf)
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.