Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_MatrixMarket_Raw_Reader.hpp
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef __Teuchos_MatrixMarket_Raw_Reader_hpp
11#define __Teuchos_MatrixMarket_Raw_Reader_hpp
12
13#include "Teuchos_MatrixMarket_Raw_Adder.hpp"
14#include "Teuchos_MatrixMarket_SymmetrizingAdder.hpp"
15#include "Teuchos_MatrixMarket_CoordDataReader.hpp"
16
17
18namespace Teuchos {
39 namespace MatrixMarket {
55 namespace Raw {
68 template<class Scalar, class Ordinal>
69 class Reader {
70 public:
77 Reader (const bool tolerant, const bool debug) :
78 tolerant_ (tolerant), debug_ (debug)
79 {
80 init ();
81 }
82
84 Reader () :
85 tolerant_ (false), debug_ (false)
86 {
87 init ();
88 }
89
98 tolerant_ (false), debug_ (false)
99 {
101 init ();
102 }
103
107 void
109 {
110 // Default parameter values.
111 bool tolerant = false;
112 bool debug = false;
113
114 // Read parameters.
115 tolerant = params->get ("Parse tolerantly", tolerant);
116 debug = params->get ("Debug mode", debug);
117
118 // No side effects on the class until ParameterList
119 // processing is complete.
120 tolerant_ = tolerant;
121 debug_ = debug;
122 }
123
127 {
128 // Default parameter values.
129 const bool tolerant = false;
130 const bool debug = false;
131
132 // Set default parameters with documentation.
133 RCP<ParameterList> params = parameterList ("Matrix Market Reader");
134 params->set ("Parse tolerantly", tolerant, "Whether to tolerate "
135 "syntax errors when parsing the Matrix Market file");
136 params->set ("Debug mode", debug, "Whether to print debugging output "
137 "to stderr, on all participating MPI processes");
138
140 }
141
167 bool
170 ArrayRCP<Scalar>& values,
171 Ordinal& numRows,
172 Ordinal& numCols,
173 const std::string& filename)
174 {
175 std::ifstream in (filename.c_str ());
176 TEUCHOS_TEST_FOR_EXCEPTION(! in, std::runtime_error,
177 "Failed to open file \"" << filename << "\" for reading.");
178 return read (rowptr, colind, values, numRows, numCols, in);
179 }
180
207 bool
210 ArrayRCP<Scalar>& values,
211 Ordinal& numRows,
212 Ordinal& numCols,
213 std::istream& in)
214 {
215 using std::cerr;
216 using std::cout;
217 using std::endl;
219
220 // This "Adder" knows how to add sparse matrix entries,
221 // given a line of data from the file. It also stores the
222 // entries and can sort them.
224 // SymmetrizingAdder "advices" (yes, I'm using that as a verb)
225 // the original Adder, so that additional entries are filled
226 // in symmetrically, if the Matrix Market banner line
227 // specified a symmetry type other than "general".
229
230 // Current line number of the input stream.
231 size_t lineNumber = 1;
232
233 // Construct the "Banner" (matrix metadata, including type
234 // and symmetry information, but not dimensions).
236 std::ostringstream err;
237 try {
238 banner = readBanner (in, lineNumber);
239 }
240 catch (std::exception& e) {
241 err << "Failed to read Matrix Market input's Banner: " << e.what();
242 if (tolerant_) {
243 if (debug_) {
244 cerr << err.str() << endl;
245 }
246 return false;
247 }
248 else {
249 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, err.str());
250 }
251 }
252
253 //
254 // Validate the metadata in the Banner.
255 //
256 bool ok = true;
257 if (banner->matrixType () != "coordinate") {
258 err << "Matrix Market input file must contain a \"coordinate\"-"
259 "format sparse matrix in order to create a sparse matrix object "
260 "from it.";
261 ok = false;
262 }
263 else if (! STS::isComplex && banner->dataType () == "complex") {
264 err << "The Matrix Market sparse matrix file contains complex-"
265 "valued data, but you are try to read the data into a sparse "
266 "matrix containing real values (your matrix's Scalar type is "
267 "real).";
268 ok = false;
269 }
270 else if (banner->dataType () != "real" &&
271 banner->dataType () != "complex") {
272 err << "Only real or complex data types (no pattern or integer "
273 "matrices) are currently supported.";
274 ok = false;
275 }
276 if (! ok) {
277 if (tolerant_) {
278 if (debug_) {
279 cerr << "Matrix Market banner is invalid: " << err.str () << endl;
280 return false;
281 }
282 }
283 else {
284 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
285 "Matrix Market banner is invalid: " << err.str ());
286 }
287 }
288 if (debug_) {
289 cerr << "Matrix Market Banner line:" << endl << *banner << endl;
290 }
291
292 // The reader will invoke the adder (see below) once for
293 // each matrix entry it reads from the input stream.
295 // We will set the adder below, after calling readDimensions().
297
298 // Read in the dimensions of the sparse matrix: (# rows, #
299 // columns, # matrix entries (counting duplicates as
300 // separate entries)). The second element of the pair tells
301 // us whether the values were gotten successfully.
302 std::pair<Tuple<Ordinal, 3>, bool> dims =
303 reader.readDimensions (in, lineNumber, tolerant_);
304 if (! dims.second) {
305 err << "Error reading Matrix Market sparse matrix file: failed to "
306 "read coordinate dimensions.";
307 if (tolerant_) {
308 if (debug_) {
309 cerr << err.str () << endl;
310 }
311 return false;
312 }
313 else {
314 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, err.str ());
315 }
316 }
317
318 // These are "expected" values read from the input stream's
319 // metadata. The actual matrix entries read from the input
320 // stream might not conform to their constraints. We allow
321 // such nonconformity only in "tolerant" mode; otherwise, we
322 // throw an exception.
323 numRows = dims.first[0];
324 numCols = dims.first[1];
325 const Ordinal numEntries = dims.first[2];
326 if (debug_) {
327 cerr << "Reported dimensions: " << numRows << " x " << numCols
328 << ", with " << numEntries << " entries (counting possible "
329 << "duplicates)." << endl;
330 }
331
332 // The "raw" adder knows about the expected matrix
333 // dimensions, but doesn't know about symmetry.
335 rcp (new raw_adder_type (numRows, numCols, numEntries,
336 tolerant_, debug_));
337 // The symmetrizing adder knows about symmetry. It mediates
338 // adding entries to the "raw" adder. We'll use the raw
339 // adder to compute the CSR arrays.
341 rcp (new adder_type (rawAdder, banner->symmType ()));
342
343 // Give the adder to the reader.
344 reader.setAdder (adder);
345
346 // Read the sparse matrix entries. "results" just tells us if
347 // and where there were any bad lines of input. The actual
348 // sparse matrix entries are stored in the (raw) Adder object.
349 std::pair<bool, std::vector<size_t> > results =
350 reader.read (in, lineNumber, tolerant_, debug_);
351
352 // Report any bad line number(s).
353 if (! results.first) {
354 err << "The Matrix Market input stream had syntax error(s)."
355 " Here is the error report." << endl;
356 reportBadness (err, results);
357 if (tolerant_) {
358 if (debug_) {
359 cerr << err.str() << endl;
360 }
361 return false;
362 }
363 else {
364 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, err.str ());
365 }
366 }
367 // Done reading the sparse matrix; now extract CSR arrays.
368 size_t numUnique, numRemoved;
372 try {
373 rawAdder->mergeAndConvertToCSR (numUnique, numRemoved, ptr, ind, val);
374 }
375 catch (std::exception& e) {
376 err << "Failed to convert sparse matrix data to CSR (compressed "
377 "sparse row) format. Reported error: " << e.what ();
378 if (tolerant_) {
379 if (debug_) {
380 cerr << err.str () << endl;
381 }
382 return false;
383 }
384 else {
385 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, err.str ());
386 }
387 }
388 rowptr = ptr;
389 colind = ind;
390 values = val;
391 return true;
392 }
393
394 private:
396 bool tolerant_;
398 bool debug_;
399
406 void init () {
407 using std::cerr;
408 using std::endl;
409
410 if (debug_) {
411 cerr << "MatrixMarket::Raw::Reader:" << endl
412 << "- Tolerant mode: " << tolerant_ << endl
413 << "- Debug mode: " << debug_ << endl;
414 }
415 }
416
430 readBanner (std::istream& in, size_t& lineNumber)
431 {
432 using std::cerr;
433 using std::endl;
434 std::string line; // The presumed banner line
435
436 // The first line of the Matrix Market file should always be
437 // the banner line. In tolerant mode, we allow comment
438 // lines before the banner line. This complicates detection
439 // of comment lines a bit.
440 if (tolerant_) {
441 // Keep reading lines until we get a noncomment line.
442 const bool maybeBannerLine = true;
443 size_t numLinesRead = 0;
444 bool commentLine = false;
445 do {
446 // Try to read a line from the input stream.
447 const bool readFailed = ! getline (in, line);
448 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
449 "Failed to get Matrix Market banner line from input, after reading "
450 << numLinesRead << "line" << (numLinesRead != 1 ? "s." : "."));
451 // We read a line from the input stream.
452 ++lineNumber;
453 ++numLinesRead;
454 size_t start, size; // Output args of checkCommentLine
455 commentLine = checkCommentLine (line, start, size, lineNumber,
456 tolerant_, maybeBannerLine);
457 } while (commentLine); // Loop until we find a noncomment line.
458 }
459 else {
460 const bool readFailed = ! getline (in, line);
461 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
462 "Failed to get Matrix Market banner line from input. This "
463 "probably means that the file is empty (contains zero lines).");
464 }
465
466 if (debug_) {
467 cerr << "Raw::Reader::readBanner: Here is the presumed banner line:"
468 << endl << line << endl;
469 }
470
471 // Assume that the noncomment line we found is the banner line.
472 RCP<Banner> banner;
473 try {
474 banner = rcp (new Banner (line, tolerant_));
475 } catch (std::exception& e) {
476 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
477 "Matrix Market file's banner line contains syntax error(s): "
478 << e.what ());
479 }
480 return rcp_const_cast<const Banner> (banner);
481 }
482
487 void
488 reportBadness (std::ostream& out,
489 const std::pair<bool, std::vector<size_t> >& results)
490 {
491 using std::endl;
492 const size_t numErrors = results.second.size();
493 const size_t maxNumErrorsToReport = 20;
494 out << numErrors << " errors when reading Matrix Market sparse "
495 "matrix file." << endl;
496 if (numErrors > maxNumErrorsToReport) {
497 out << "-- We do not report individual errors when there "
498 "are more than " << maxNumErrorsToReport << ".";
499 }
500 else if (numErrors == 1) {
501 out << "Error on line " << results.second[0] << endl;
502 }
503 else if (numErrors > 1) {
504 out << "Errors on lines {";
505 for (size_t k = 0; k < numErrors-1; ++k) {
506 out << results.second[k] << ", ";
507 }
508 out << results.second[numErrors-1] << "}" << endl;
509 }
510 }
511 }; // end of class Reader
512 } // namespace Raw
513 } // namespace MatrixMarket
514} // namespace Teuchos
515
516#endif // __Teuchos_MatrixMarket_Raw_Reader_hpp
Read a sparse matrix from a Matrix Market file into raw CSR (compressed sparse row) storage.
RCP< const ParameterList > getValidParameters() const
Get a list of valid default parameters, with documentation.
bool read(ArrayRCP< Ordinal > &rowptr, ArrayRCP< Ordinal > &colind, ArrayRCP< Scalar > &values, Ordinal &numRows, Ordinal &numCols, std::istream &in)
Read the sparse matrix from the given input stream into CSR storage.
Reader(const bool tolerant, const bool debug)
Constructor that takes Boolean parameters.
Reader(const RCP< ParameterList > &params)
Constructor that takes a ParameterList of parameters.
bool readFile(ArrayRCP< Ordinal > &rowptr, ArrayRCP< Ordinal > &colind, ArrayRCP< Scalar > &values, Ordinal &numRows, Ordinal &numCols, const std::string &filename)
Read the sparse matrix from the given file into CSR storage.
Reader()
Constructor that sets default Boolean parameters.
void setParameters(const RCP< ParameterList > &params)
Set parameters from the given ParameterList.
Smart reference counting pointer class for automatic garbage collection.
T * get() const
Get the raw C++ pointer to the underlying object.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Matrix Market file utilities.
"Raw" input of sparse matrices from Matrix Market files.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.