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