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