Alien  1.3.0
Developer documentation
Loading...
Searching...
No Matches
MatrixMarketReader.cc
1/*
2 * Copyright 2021 IFPEN-CEA
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 */
18
19#include <fstream>
20#include <algorithm>
21#include <cctype>
22
23#include <arccore/base/FatalErrorException.h>
24#include <arccore/message_passing/IMessagePassingMng.h>
25
26#include <alien/data/Space.h>
29
30#include <alien/move/data/MatrixData.h>
31#include <alien/move/handlers/scalar/DoKDirectMatrixBuilder.h>
32#include <alien/move/data/VectorData.h>
33#include <alien/kernels/dok/DoKVector.h>
34#include <alien/kernels/dok/DoKBackEnd.h>
35
36namespace Alien::Move
37{
38
39namespace
40{
41 std::pair<size_t, size_t> partition(size_t full_size, const Arccore::MessagePassing::IMessagePassingMng* pm)
42 {
43 auto my_rank = pm->commRank();
44 auto comm_size = pm->commSize();
45 size_t line_slice = full_size / comm_size;
46 auto start = line_slice * my_rank;
47 auto stop = line_slice * (my_rank + 1);
48 if (my_rank == comm_size - 1) {
49 stop = full_size;
50 }
51 return std::make_pair(start, stop);
52 }
53
54 void tolower(std::string& str)
55 {
56 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
57 }
58
59 class MatrixDescription
60 {
61 public:
62 MatrixDescription() = default;
63
64 int n_rows{ 0 };
65 int n_cols{ 0 };
66 size_t n_nnz{ 0 };
67 bool symmetric{ true };
68 };
69
70 std::optional<MatrixDescription> readBanner(std::istream& fstream)
71 {
72 std::string line;
73
74 MatrixDescription out;
75
76 auto try_header = true;
77
78 while (std::getline(fstream, line)) {
79 std::stringstream ss;
80 ss << line;
81
82 if (try_header) {
83 std::string matrix;
84 std::string _; // junk
85 std::string format; // (coordinate, array)
86 std::string scalar; // (pattern, real, complex, integer)
87 std::string symmetry; // (general, symmetric, skew-symmetric, hermitian)
88
89 // get matrix kind
90 ss >> matrix; // skip '%%MatrixMarket
91
92 if ("%%MatrixMarket" != matrix) {
93 continue;
94 }
95
96 ss >> _; // skip matrix
97 ss >> format;
98 ss >> scalar;
99 ss >> symmetry;
100
101 tolower(format);
102 tolower(scalar);
103 tolower(symmetry);
104
105 if ("coordinate" != format) {
106 return std::nullopt;
107 }
108
109 if ("real" != scalar) {
110 return std::nullopt;
111 }
112
113 if ("general" == symmetry) {
114 out.symmetric = false;
115 }
116 else {
117 out.symmetric = true;
118 }
119 try_header = false;
120 }
121 else if ('%' == line[0]) {
122 // skip comment
123 continue;
124 }
125 else {
126 //first line is matrix size, then done with banner
127 ss >> out.n_rows;
128 ss >> out.n_cols;
129 ss >> out.n_nnz;
130 break;
131 }
132 }
133 return std::make_optional(out);
134 }
135
136 bool readValues(std::istream& fstream, DoKDirectMatrixBuilder& builder, bool symmetric, size_t start, size_t stop)
137 {
138 for (size_t i = 0; i < start; ++i) {
139 fstream.ignore(4096, '\n');
140 }
141
142 std::string line;
143 size_t count = start;
144 while (count < stop && std::getline(fstream, line)) {
145 if ('%' == line[0]) {
146 continue;
147 }
148
149 count++;
150 int row = 0;
151 int col = 0;
152 double value = 0.0;
153 std::stringstream ss;
154 ss << line;
155 ss >> row >> col >> value;
156 builder.contribute(row - 1, col - 1, value);
157 if (symmetric && row != col) {
158 builder.contribute(col - 1, row - 1, value);
159 }
160 }
161 return true;
162 }
163
164 MatrixData createMatrixData(MatrixDescription desc, Arccore::MessagePassing::IMessagePassingMng* pm)
165 {
166 Alien::Space row_space(desc.n_rows, "RowSpace");
167 Alien::Space col_space(desc.n_cols, "ColSpace");
168 Alien::MatrixDistribution dist(
169 row_space, col_space, pm);
170 return Alien::Move::MatrixData(dist);
171 }
172
173} // namespace
174
175MatrixData ALIEN_MOVESEMANTIC_EXPORT
176readFromMatrixMarket(Arccore::MessagePassing::IMessagePassingMng* pm, const std::string& filename)
177{
178 std::ifstream stream;
179 std::array<char, 1024 * 1024> buf; // Buffer for reading
180 stream.rdbuf()->pubsetbuf(buf.data(), buf.size());
181 stream.open(filename);
182 if (!stream) {
183 throw Arccore::FatalErrorException("readFromMatrixMarket", "Unable to matrix read file");
184 }
185 auto desc = readBanner(stream);
186 if (!desc) {
187 throw Arccore::FatalErrorException("readFromMatrixMarket", "Invalid header");
188 }
189 DoKDirectMatrixBuilder builder(createMatrixData(desc.value(), pm));
190
191 auto [nnz_start, nnz_stop] = partition(desc.value().n_nnz, pm);
192 readValues(stream, builder, desc->symmetric, nnz_start, nnz_stop);
193 return builder.release();
194}
195
196VectorData ALIEN_MOVESEMANTIC_EXPORT
197readFromMatrixMarket(const VectorDistribution& distribution, const std::string& filename)
198{
199 VectorData out(distribution);
200 auto& v = out.impl()->template get<BackEnd::tag::DoK>(true);
201
202 std::ifstream stream;
203 std::array<char, 1024 * 1024> buf; // Buffer for reading
204 stream.rdbuf()->pubsetbuf(buf.data(), buf.size());
205 stream.open(filename);
206 if (!stream) {
207 throw Arccore::FatalErrorException("readFromMatrixMarket", "Unable to read vector file");
208 }
209 std::string line;
210 size_t rows = 0;
211
212 auto try_header = true;
213 while (std::getline(stream, line)) {
214 // get matrix kind
215 std::stringstream ss;
216 ss << line;
217
218 if (try_header) {
219 std::string matrix;
220 std::string _; // junk
221 std::string format; // (coordinate, array)
222 std::string scalar; // (pattern, real, complex, integer)
223
224 ss >> matrix; // skip '%%MatrixMarket
225
226 if ("%%MatrixMarket" != matrix)
227 continue;
228
229 ss >> _; // skip matrix
230 ss >> format;
231 ss >> scalar;
232 ss >> _;
233
234 tolower(format);
235 tolower(scalar);
236
237 if ("array" != format || "real" != scalar) {
238 throw Arccore::FatalErrorException("mtx vector must be in 'array' and 'real' formats.");
239 }
240 try_header = false;
241 }
242 if ('%' == line[0])
243 continue;
244
245 int vectors = 0;
246 ss >> rows;
247 ss >> vectors;
248 if (vectors != 1) {
249 throw Arccore::FatalErrorException("mtx vector reader does not support multiple vectors.");
250 }
251 if (distribution.globalSize() != rows) {
252 throw Arccore::FatalErrorException("mtx vector is not of correct size");
253 }
254 break;
255 }
256
257 auto [row_start, row_stop] = partition(rows, distribution.parallelMng());
258
259 Arccore::Int32 row = 0;
260 for (row = 0; row < row_start; ++row) {
261 stream.ignore(4096, '\n');
262 }
263
264 while (row < row_stop && std::getline(stream, line)) {
265 double value;
266 std::stringstream ss;
267 ss << line;
268 ss >> value;
269
270 v.contribute(row, value);
271 row++;
272 }
273 v.assemble();
274
275 return out;
276}
277
278} // namespace Alien::Move
MatrixDistribution.h.
Space.h.
VectorDistribution.h.
Algebraic Matrix with internal multi-representation object.
Definition MatrixData.h:40
Algebraic Vector with internal multi-representation object.
Definition VectorData.h:48