Arcane  v4.1.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
IO.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/* IO.h (C) 2000-2026 */
9/* */
10/* Readers for Matrix Market sparse matrices and dense vectors. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_IO_H
13#define ARCCORE_ALINA_IO_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17/*
18 * This file is based on the work on AMGCL library (version march 2026)
19 * which can be found at https://github.com/ddemidov/amgcl.
20 *
21 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
22 * SPDX-License-Identifier: MIT
23 */
24
25/*---------------------------------------------------------------------------*/
26/*---------------------------------------------------------------------------*/
27
28#include <climits>
29#include <vector>
30#include <string>
31#include <fstream>
32#include <sstream>
33#include <numeric>
34
35#include <type_traits>
36#include <tuple>
37
38#include "arccore/alina/AlinaUtils.h"
39#include "arccore/alina/BackendInterface.h"
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44namespace Arcane::Alina::IO
45{
46
47/*---------------------------------------------------------------------------*/
48/*---------------------------------------------------------------------------*/
49
52{
53 public:
54
56 explicit mm_reader(const std::string& fname)
57 : f(fname)
58 {
59 precondition(f, "Failed to open file \"" + fname + "\"");
60
61 // Read banner.
62 precondition(std::getline(f, line), format_error());
63
64 std::istringstream is(line);
65 std::string banner, mtx, coord, dtype, storage;
66
67 precondition(
68 is >> banner >> mtx >> coord >> dtype >> storage,
69 format_error());
70
71 precondition(banner == "%%MatrixMarket", format_error("no banner"));
72 precondition(mtx == "matrix", format_error("not a matrix"));
73
74 if (storage == "general") {
75 _symmetric = false;
76 }
77 else if (storage == "symmetric") {
78 _symmetric = true;
79 }
80 else {
81 precondition(false, "unsupported storage type");
82 }
83
84 if (coord == "coordinate") {
85 _sparse = true;
86 }
87 else if (coord == "array") {
88 _sparse = false;
89 }
90 else {
91 precondition(false, format_error("unsupported coordinate type"));
92 }
93
94 if (dtype == "real") {
95 _complex = false;
96 _integer = false;
97 }
98 else if (dtype == "complex") {
99 _complex = true;
100 _integer = false;
101 }
102 else if (dtype == "integer") {
103 _complex = false;
104 _integer = true;
105 }
106 else {
107 precondition(false, format_error("unsupported data type"));
108 }
109
110 // Skip comments.
111 do {
112 precondition(std::getline(f, line), format_error("unexpected eof"));
113 } while (line[0] == '%');
114
115 // The last line is comment-free and holds the matrix sizes
116 is.clear();
117 is.str(line);
118 precondition(is >> nrows >> ncols, format_error());
119 }
120
122 bool is_symmetric() const { return _symmetric; }
123
125 bool is_sparse() const { return _sparse; }
126
128 bool is_complex() const { return _complex; }
129
131 bool is_integer() const { return _integer; }
132
134 size_t rows() const { return nrows; }
135
137 size_t cols() const { return ncols; }
138
140 template <typename Idx, typename Val>
141 std::tuple<size_t, size_t> operator()(std::vector<Idx>& ptr,
142 std::vector<Idx>& col,
143 std::vector<Val>& val,
144 ptrdiff_t row_beg = -1,
145 ptrdiff_t row_end = -1)
146 {
147 precondition(_sparse, format_error("not a sparse matrix"));
148 precondition(Alina::is_complex<Val>::value == _complex,
149 _complex ? "attempt to read complex values into real vector" : "attempt to read real values into complex vector");
150 precondition(std::is_integral<Val>::value == _integer,
151 _integer ? "attempt to read integer values into real vector" : "attempt to read real values into integer vector");
152
153 // Read sizes
154 ptrdiff_t n, m;
155 size_t nnz;
156 std::istringstream is;
157 {
158 // line already holds the matrix sizes
159 is.clear();
160 is.str(line);
161 precondition(is >> n >> m >> nnz, format_error());
162 }
163
164 if (row_beg < 0)
165 row_beg = 0;
166 if (row_end < 0)
167 row_end = n;
168
169 precondition(row_beg >= 0 && row_end <= n,
170 "Wrong subset of rows is requested");
171
172 ptrdiff_t _nnz = _symmetric ? 2 * nnz : nnz;
173
174 if (row_beg != 0 || row_end != n)
175 _nnz *= 1.2 * (row_end - row_beg) / n;
176
177 std::vector<Idx> _row;
178 _row.reserve(_nnz);
179 std::vector<Idx> _col;
180 _col.reserve(_nnz);
181 std::vector<Val> _val;
182 _val.reserve(_nnz);
183
184 ptrdiff_t chunk = row_end - row_beg;
185
186 ptr.resize(chunk + 1);
187 std::fill(ptr.begin(), ptr.end(), 0);
188
189 for (size_t k = 0; k < nnz; ++k) {
190 precondition(std::getline(f, line), format_error("unexpected eof"));
191 is.clear();
192 is.str(line);
193
194 Idx i, j;
195 Val v;
196
197 precondition(is >> i >> j, format_error());
198
199 i -= 1;
200 j -= 1;
201
202 v = read_value<Val>(is);
203
204 if (row_beg <= i && i < row_end) {
205 ++ptr[i - row_beg + 1];
206
207 _row.push_back(i - row_beg);
208 _col.push_back(j);
209 _val.push_back(v);
210 }
211
212 if (_symmetric && i != j && row_beg <= j && j < row_end) {
213 ++ptr[j - row_beg + 1];
214
215 _row.push_back(j - row_beg);
216 _col.push_back(i);
217 _val.push_back(v);
218 }
219 }
220
221 std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());
222
223 col.resize(ptr.back());
224 val.resize(ptr.back());
225
226 for (size_t k = 0, e = val.size(); k < e; ++k) {
227 Idx i = _row[k];
228 Idx j = _col[k];
229 Val v = _val[k];
230
231 Idx head = ptr[i]++;
232 col[head] = j;
233 val[head] = v;
234 }
235
236 std::rotate(ptr.begin(), ptr.end() - 1, ptr.end());
237 ptr.front() = 0;
238
239 arccoreParallelFor(0, chunk, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
240 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
241 Idx beg = ptr[i];
242 Idx end = ptr[i + 1];
243
244 Alina::detail::sort_row(&col[0] + beg, &val[0] + beg, end - beg);
245 }
246 });
247
248 return std::make_tuple(chunk, m);
249 }
250
252 template <typename Val>
253 std::tuple<size_t, size_t> operator()(std::vector<Val>& val,
254 ptrdiff_t row_beg = -1,
255 ptrdiff_t row_end = -1)
256 {
257 precondition(!_sparse, format_error("not a dense array"));
258 precondition(Alina::is_complex<Val>::value == _complex,
259 _complex ? "attempt to read complex values into real vector" : "attempt to read real values into complex vector");
260 precondition(std::is_integral<Val>::value == _integer,
261 _integer ? "attempt to read integer values into real vector" : "attempt to read real values into integer vector");
262
263 // Read sizes
264 ptrdiff_t n, m;
265 std::istringstream is;
266 {
267 // line already holds the matrix sizes
268 is.clear();
269 is.str(line);
270 precondition(is >> n >> m, format_error());
271 }
272
273 if (row_beg < 0)
274 row_beg = 0;
275 if (row_end < 0)
276 row_end = n;
277
278 precondition(row_beg >= 0 && row_end <= n,
279 "Wrong subset of rows is requested");
280
281 val.resize((row_end - row_beg) * m);
282
283 for (ptrdiff_t j = 0; j < m; ++j) {
284 for (ptrdiff_t i = 0; i < n; ++i) {
285 precondition(std::getline(f, line), format_error("unexpected eof"));
286 if (row_beg <= i && i < row_end) {
287 is.clear();
288 is.str(line);
289 val[(i - row_beg) * m + j] = read_value<Val>(is);
290 }
291 }
292 }
293
294 return std::make_tuple(row_end - row_beg, m);
295 }
296
297 private:
298
299 std::ifstream f;
300 std::string line;
301
302 bool _sparse;
303 bool _symmetric;
304 bool _complex;
305 bool _integer;
306
307 size_t nrows, ncols;
308
309 std::string format_error(const std::string& msg = "") const
310 {
311 std::string err_string = "MatrixMarket format error";
312 if (!msg.empty())
313 err_string += " (" + msg + ")";
314 return err_string;
315 }
316
317 template <typename T>
318 typename std::enable_if<Alina::is_complex<T>::value, T>::type
319 read_value(std::istream& s)
320 {
321 typename math::scalar_of<T>::type x, y;
322 precondition(s >> x >> y, format_error());
323 return T(x, y);
324 }
325
326 template <typename T>
327 typename std::enable_if<!Alina::is_complex<T>::value, T>::type
328 read_value(std::istream& s)
329 {
330 T x;
331 if (std::is_same<T, char>::value) {
332 // Special case:
333 // We want to read 8bit integers from MatrixMarket, not chars.
334 int i;
335 precondition(s >> i, format_error());
336 x = static_cast<char>(i);
337 }
338 else {
339 precondition(s >> x, format_error());
340 }
341 return x;
342 }
343};
344
345/*---------------------------------------------------------------------------*/
346/*---------------------------------------------------------------------------*/
347
348namespace detail
349{
350 template <typename Val>
351 typename std::enable_if<is_complex<Val>::value, std::ostream&>::type
352 write_value(std::ostream& s, Val v)
353 {
354 return s << std::scientific << std::setprecision(20) << std::real(v) << " " << std::imag(v);
355 }
356
357 template <typename Val>
358 typename std::enable_if<!is_complex<Val>::value, std::ostream&>::type
359 write_value(std::ostream& s, Val v)
360 {
361 return s << std::scientific << std::setprecision(20) << v;
362 }
363
364} // namespace detail
365
366/*---------------------------------------------------------------------------*/
367/*---------------------------------------------------------------------------*/
368
370template <typename Val>
371void mm_write(const std::string& fname,
372 const Val* data,
373 size_t rows,
374 size_t cols = 1)
375{
376 std::ofstream f(fname.c_str());
377 precondition(f, "Failed to open file \"" + fname + "\" for writing");
378
379 // Banner
380 f << "%%MatrixMarket matrix array ";
381 if (is_complex<Val>::value) {
382 f << "complex ";
383 }
384 else if (std::is_integral<Val>::value) {
385 f << "integer ";
386 }
387 else {
388 f << "real ";
389 }
390 f << "general\n";
391
392 // Sizes
393 f << rows << " " << cols << "\n";
394
395 // Data
396 for (size_t j = 0; j < cols; ++j) {
397 for (size_t i = 0; i < rows; ++i) {
398 detail::write_value(f, data[i * cols + j]) << "\n";
399 }
400 }
401}
402
403/*---------------------------------------------------------------------------*/
404/*---------------------------------------------------------------------------*/
405
407template <class Matrix>
408void mm_write(const std::string& fname, const Matrix& A)
409{
410 typedef typename backend::value_type<Matrix>::type Val;
411
412 const size_t rows = backend::nbRow(A);
413 const size_t cols = backend::nbColumn(A);
414 const size_t nnz = backend::nonzeros(A);
415
416 std::ofstream f(fname.c_str());
417 precondition(f, "Failed to open file \"" + fname + "\" for writing");
418
419 // Banner
420 f << "%%MatrixMarket matrix coordinate ";
421 if (is_complex<Val>::value) {
422 f << "complex ";
423 }
424 else if (std::is_integral<Val>::value) {
425 f << "integer ";
426 }
427 else {
428 f << "real ";
429 }
430 f << "general\n";
431
432 // Sizes
433 f << rows << " " << cols << " " << nnz << "\n";
434
435 // Data
436 for (size_t i = 0; i < rows; ++i) {
437 for (auto a = backend::row_begin(A, i); a; ++a) {
438 f << i + 1 << " " << a.col() + 1 << " ";
439 detail::write_value(f, a.value()) << "\n";
440 }
441 }
442}
443
444/*---------------------------------------------------------------------------*/
445/*---------------------------------------------------------------------------*/
446
448template <class T>
449bool read(std::ifstream& f, T& val)
450{
451 return static_cast<bool>(f.read((char*)&val, sizeof(T)));
452}
453
454/*---------------------------------------------------------------------------*/
455/*---------------------------------------------------------------------------*/
456
458template <class T>
459bool read(std::ifstream& f, std::vector<T>& vec)
460{
461 return static_cast<bool>(f.read((char*)&vec[0], sizeof(T) * vec.size()));
462}
463
464/*---------------------------------------------------------------------------*/
465/*---------------------------------------------------------------------------*/
466
468template <typename IndexType>
469IndexType crs_size(const std::string& fname)
470{
471 std::ifstream f(fname.c_str(), std::ios::binary);
472 IndexType n;
473
474 precondition(f, "Failed to open matrix file");
475 precondition(read(f, n), "File I/O error");
476
477 return n;
478}
479
480/*---------------------------------------------------------------------------*/
481/*---------------------------------------------------------------------------*/
482
484template <typename SizeT, typename Ptr, typename Col, typename Val>
485void read_crs(const std::string& fname,
486 SizeT& n,
487 std::vector<Ptr>& ptr,
488 std::vector<Col>& col,
489 std::vector<Val>& val,
490 ptrdiff_t row_beg = -1,
491 ptrdiff_t row_end = -1)
492{
493 std::ifstream f(fname.c_str(), std::ios::binary);
494 precondition(f, "Failed to open matrix file");
495
496 precondition(read(f, n), "File I/O error");
497
498 if (row_beg < 0)
499 row_beg = 0;
500 if (row_end < 0)
501 row_end = n;
502
503 precondition(row_beg >= 0 && row_end <= static_cast<ptrdiff_t>(n),
504 "Wrong subset of rows is requested");
505
506 ptrdiff_t chunk = row_end - row_beg;
507
508 ptr.resize(chunk + 1);
509
510 size_t ptr_beg = sizeof(SizeT);
511 f.seekg(ptr_beg + row_beg * sizeof(Ptr));
512 precondition(read(f, ptr), "File I/O error");
513
514 Ptr nnz;
515 f.seekg(ptr_beg + n * sizeof(Ptr));
516 precondition(read(f, nnz), "File I/O error");
517
518 SizeT nnz_beg = ptr.front();
519 if (nnz_beg)
520 for (auto& p : ptr)
521 p -= nnz_beg;
522
523 col.resize(ptr.back());
524 val.resize(ptr.back());
525
526 size_t col_beg = ptr_beg + (n + 1) * sizeof(Ptr);
527 f.seekg(col_beg + nnz_beg * sizeof(Col));
528 precondition(read(f, col), "File I/O error");
529
530 f.seekg(col_beg + nnz * sizeof(Col) + nnz_beg * sizeof(Val));
531 precondition(read(f, val), "File I/O error");
532
533 arccoreParallelFor(0, chunk, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
534 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
535 Ptr beg = ptr[i];
536 Ptr end = ptr[i + 1];
537 Alina::detail::sort_row(&col[beg], &val[beg], end - beg);
538 }
539 });
540}
541
542/*---------------------------------------------------------------------------*/
543/*---------------------------------------------------------------------------*/
544
545template <typename SizeT>
546void dense_size(const std::string& fname, SizeT& n, SizeT& m)
547{
548 std::ifstream f(fname.c_str(), std::ios::binary);
549 precondition(f, "Failed to open matrix file");
550
551 precondition(read(f, n), "File I/O error");
552 precondition(read(f, m), "File I/O error");
553}
554
555/*---------------------------------------------------------------------------*/
556/*---------------------------------------------------------------------------*/
557
558template <typename SizeT, typename Val>
559void read_dense(const std::string& fname,
560 SizeT& n, SizeT& m, std::vector<Val>& v,
561 ptrdiff_t row_beg = -1, ptrdiff_t row_end = -1)
562{
563 std::ifstream f(fname.c_str(), std::ios::binary);
564 precondition(f, "Failed to open matrix file");
565
566 precondition(read(f, n), "File I/O error");
567 precondition(read(f, m), "File I/O error");
568
569 if (row_beg < 0)
570 row_beg = 0;
571 if (row_end < 0)
572 row_end = n;
573
574 precondition(row_beg >= 0 && row_end <= static_cast<ptrdiff_t>(n),
575 "Wrong subset of rows is requested");
576
577 ptrdiff_t chunk = row_end - row_beg;
578
579 v.resize(chunk * m);
580
581 f.seekg(2 * sizeof(SizeT) + row_beg * m * sizeof(Val));
582 precondition(read(f, v), "File I/O error");
583}
584
585/*---------------------------------------------------------------------------*/
586/*---------------------------------------------------------------------------*/
587
589template <class T>
590bool write(std::ofstream& f, const T& val)
591{
592 return static_cast<bool>(f.write((char*)&val, sizeof(T)));
593}
594
595/*---------------------------------------------------------------------------*/
596/*---------------------------------------------------------------------------*/
597
599template <class T>
600bool write(std::ofstream& f, const std::vector<T>& vec)
601{
602 return static_cast<bool>(f.write((char*)&vec[0], sizeof(T) * vec.size()));
603}
604
605/*---------------------------------------------------------------------------*/
606/*---------------------------------------------------------------------------*/
607
608} // namespace Arcane::Alina::IO
609
610/*---------------------------------------------------------------------------*/
611/*---------------------------------------------------------------------------*/
612
613#endif
bool is_integer() const
Matrix in the file is integer-valued.
Definition IO.h:131
size_t rows() const
Number of rows.
Definition IO.h:134
bool is_symmetric() const
Matrix in the file is symmetric.
Definition IO.h:122
std::tuple< size_t, size_t > operator()(std::vector< Idx > &ptr, std::vector< Idx > &col, std::vector< Val > &val, ptrdiff_t row_beg=-1, ptrdiff_t row_end=-1)
Read sparse matrix from the file.
Definition IO.h:141
bool is_sparse() const
Matrix in the file is sparse.
Definition IO.h:125
std::tuple< size_t, size_t > operator()(std::vector< Val > &val, ptrdiff_t row_beg=-1, ptrdiff_t row_end=-1)
Read dense array from the file.
Definition IO.h:253
mm_reader(const std::string &fname)
Open the file by name.
Definition IO.h:56
size_t cols() const
Number of rows.
Definition IO.h:137
bool is_complex() const
Matrix in the file is complex-valued.
Definition IO.h:128
Informations d'exécution d'une boucle.
void arccoreParallelFor(const ComplexForLoopRanges< RankValue > &loop_ranges, const ForLoopRunInfo &run_info, const LambdaType &lambda_function, const ReducerArgs &... reducer_args)
Applique en concurrence la fonction lambda lambda_function sur l'intervalle d'itération donné par loo...
Definition ParallelFor.h:85
std::int32_t Int32
Type entier signé sur 32 bits.