Arcane  v4.1.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
DistributedPartition.cc
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/*---------------------------------------------------------------------------*/
9/*
10 * This file is based on the work on AMGCL library (version march 2026)
11 * which can be found at https://github.com/ddemidov/amgcl.
12 *
13 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
14 * SPDX-License-Identifier: MIT
15 */
16/*---------------------------------------------------------------------------*/
17/*---------------------------------------------------------------------------*/
18
19#include <iostream>
20#include <vector>
21#include <string>
22#include <algorithm>
23#include <numeric>
24#include <cassert>
25
26#include <boost/program_options.hpp>
27
28#include "arccore/alina/AlinaUtils.h"
29#include "arccore/alina/IO.h"
30
31extern "C" {
32#include <metis.h>
33}
34
35using namespace Arcane;
36using Alina::precondition;
37
38//---------------------------------------------------------------------------
39void pointwise_graph(int n, int block_size,
40 const std::vector<int>& ptr,
41 const std::vector<int>& col,
42 std::vector<idx_t>& pptr,
43 std::vector<idx_t>& pcol)
44{
45 int np = n / block_size;
46
47 assert(np * block_size == n);
48
49 // Create pointwise matrix
50 std::vector<int> ptr1(np + 1, 0);
51 std::vector<int> marker(np, -1);
52 for (int ip = 0, i = 0; ip < np; ++ip) {
53 for (int k = 0; k < block_size; ++k, ++i) {
54 for (int j = ptr[i]; j < ptr[i + 1]; ++j) {
55 int cp = col[j] / block_size;
56 if (marker[cp] != ip) {
57 marker[cp] = ip;
58 ++ptr1[ip + 1];
59 }
60 }
61 }
62 }
63
64 std::partial_sum(ptr1.begin(), ptr1.end(), ptr1.begin());
65 std::fill(marker.begin(), marker.end(), -1);
66
67 std::vector<int> col1(ptr1.back());
68
69 for (int ip = 0, i = 0; ip < np; ++ip) {
70 int row_beg = ptr1[ip];
71 int row_end = row_beg;
72
73 for (int k = 0; k < block_size; ++k, ++i) {
74 for (int j = ptr[i]; j < ptr[i + 1]; ++j) {
75 int cp = col[j] / block_size;
76
77 if (marker[cp] < row_beg) {
78 marker[cp] = row_end;
79 col1[row_end++] = cp;
80 }
81 }
82 }
83 }
84
85 // Transpose pointwise matrix
86 int nnz = ptr1.back();
87
88 std::vector<int> ptr2(np + 1, 0);
89 std::vector<int> col2(nnz);
90
91 for (int i = 0; i < nnz; ++i)
92 ++(ptr2[col1[i] + 1]);
93
94 std::partial_sum(ptr2.begin(), ptr2.end(), ptr2.begin());
95
96 for (int i = 0; i < np; ++i)
97 for (int j = ptr1[i]; j < ptr1[i + 1]; ++j)
98 col2[ptr2[col1[j]]++] = i;
99
100 std::rotate(ptr2.begin(), ptr2.end() - 1, ptr2.end());
101 ptr2.front() = 0;
102
103 // Merge both matrices.
104 std::fill(marker.begin(), marker.end(), -1);
105 pptr.resize(np + 1, 0);
106
107 for (int i = 0; i < np; ++i) {
108 for (int j = ptr1[i]; j < ptr1[i + 1]; ++j) {
109 int c = col1[j];
110 if (marker[c] != i) {
111 marker[c] = i;
112 ++pptr[i + 1];
113 }
114 }
115
116 for (int j = ptr2[i]; j < ptr2[i + 1]; ++j) {
117 int c = col2[j];
118 if (marker[c] != i) {
119 marker[c] = i;
120 ++pptr[i + 1];
121 }
122 }
123 }
124
125 std::partial_sum(pptr.begin(), pptr.end(), pptr.begin());
126 std::fill(marker.begin(), marker.end(), -1);
127
128 pcol.resize(pptr.back());
129
130 for (int i = 0; i < np; ++i) {
131 int row_beg = pptr[i];
132 int row_end = row_beg;
133
134 for (int j = ptr1[i]; j < ptr1[i + 1]; ++j) {
135 int c = col1[j];
136
137 if (marker[c] < row_beg) {
138 marker[c] = row_end;
139 pcol[row_end++] = c;
140 }
141 }
142
143 for (int j = ptr2[i]; j < ptr2[i + 1]; ++j) {
144 int c = col2[j];
145
146 if (marker[c] < row_beg) {
147 marker[c] = row_end;
148 pcol[row_end++] = c;
149 }
150 }
151 }
152}
153
154//---------------------------------------------------------------------------
155std::vector<idx_t>
156pointwise_partition(idx_t npart,
157 const std::vector<idx_t>& ptr,
158 const std::vector<idx_t>& col)
159{
160 idx_t nrows = ptr.size() - 1;
161
162 std::vector<idx_t> part(nrows);
163
164 if (npart == 1) {
165 std::fill(part.begin(), part.end(), 0);
166 }
167 else {
168 idx_t edgecut;
169
170#if defined(METIS_VER_MAJOR) && (METIS_VER_MAJOR >= 5)
171 idx_t nconstraints = 1;
172 METIS_PartGraphKway(
173 &nrows, //nvtxs
174 &nconstraints, //ncon -- new
175 const_cast<idx_t*>(ptr.data()), //xadj
176 const_cast<idx_t*>(col.data()), //adjncy
177 NULL, //vwgt
178 NULL, //vsize -- new
179 NULL, //adjwgt
180 &npart,
181 NULL, //real t *tpwgts,
182 NULL, // real t ubvec
183 NULL,
184 &edgecut,
185 part.data());
186#else
187 int wgtflag = 0;
188 int numflag = 0;
189 int options = 0;
190
191 METIS_PartGraphKway(
192 &nrows,
193 const_cast<int*>(ptr.data()),
194 const_cast<int*>(col.data()),
195 NULL,
196 NULL,
197 &wgtflag,
198 &numflag,
199 &npart,
200 &options,
201 &edgecut,
202 part.data());
203#endif
204 }
205
206 return part;
207}
208
209//---------------------------------------------------------------------------
210std::vector<int>
211partition(int n, int nparts, int block_size,
212 const std::vector<int>& ptr, const std::vector<int>& col)
213{
214 // Pointwise graph
215 std::vector<idx_t> pptr;
216 std::vector<idx_t> pcol;
217 pointwise_graph(n, block_size, ptr, col, pptr, pcol);
218
219 // Pointwise partition
220 std::vector<idx_t> ppart = pointwise_partition(nparts, pptr, pcol);
221
222 std::vector<int> part(n);
223 for (int i = 0; i < n; ++i)
224 part[i] = ppart[i / block_size];
225
226 return part;
227}
228
229//---------------------------------------------------------------------------
230int main(int argc, char* argv[])
231{
232 namespace po = boost::program_options;
233
234 try {
235 std::string ifile;
236 std::string ofile = "partition.mtx";
237
238 int nparts, block_size;
239
240 po::options_description desc("Options");
241
242 desc.add_options()("help,h", "show help");
243 desc.add_options()("input,i", po::value<std::string>(&ifile)->required(), "Input matrix");
244 desc.add_options()("output,o", po::value<std::string>(&ofile)->default_value(ofile), "Output file");
245 desc.add_options()("binary,B",
246 po::bool_switch()->default_value(false),
247 "When specified, treat input files as binary instead of as MatrixMarket. ");
248 desc.add_options()("nparts,n", po::value<int>(&nparts)->required(), "Number of parts");
249 desc.add_options()("block_size,b", po::value<int>(&block_size)->default_value(1), "Block size");
250
251 po::positional_options_description pd;
252 pd.add("input", 1);
253
254 po::variables_map vm;
255 po::store(po::command_line_parser(argc, argv).options(desc).positional(pd).run(), vm);
256
257 if (vm.count("help")) {
258 std::cout << desc << std::endl;
259 return 0;
260 }
261
262 po::notify(vm);
263
264 size_t rows;
265 std::vector<int> ptr, col;
266
267 bool binary = vm["binary"].as<bool>();
268
269 if (binary) {
270 std::ifstream f(ifile, std::ios::binary);
271 precondition(f.read((char*)&rows, sizeof(rows)), "Wrong file format?");
272 ptr.resize(rows + 1);
273 for (size_t i = 0; i <= rows; ++i) {
274 ptrdiff_t p;
275 precondition(f.read((char*)&p, sizeof(p)), "Wrong file format?");
276 ptr[i] = p;
277 }
278 col.resize(ptr.back());
279 for (ptrdiff_t i = 0; i < ptr.back(); ++i) {
280 ptrdiff_t p;
281 precondition(f.read((char*)&p, sizeof(p)), "Wrong file format?");
282 col[i] = p;
283 }
284 }
285 else {
286 std::vector<double> val;
287 size_t cols;
288 std::tie(rows, cols) = Alina::IO::mm_reader(ifile)(ptr, col, val);
289 precondition(rows == cols, "Non-square system matrix");
290 }
291
292 std::vector<int> part = partition(rows, nparts, block_size, ptr, col);
293
294 if (binary) {
295 std::ofstream p(ofile.c_str(), std::ios::binary);
296
297 Alina::IO::write(p, rows);
298 Alina::IO::write(p, size_t(1));
299 Alina::IO::write(p, part);
300 }
301 else {
302 Alina::IO::mm_write(ofile, &part[0], part.size());
303 }
304 }
305 catch (const std::exception& e) {
306 std::cerr << "Error: " << e.what() << std::endl;
307 return 1;
308 }
309}
Matrix market reader.
Definition IO.h:52
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-