Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_MatrixMarket_Raw_Checker.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_Checker_hpp
11#define __Teuchos_MatrixMarket_Raw_Checker_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 {
19 namespace MatrixMarket {
20 namespace Raw {
35 template<class Scalar, class Ordinal>
36 class Checker {
37 public:
47 Checker (const bool echo, const bool tolerant, const bool debug) :
48 echo_ (echo), tolerant_ (tolerant), debug_ (debug)
49 {}
50
53 echo_ (false), tolerant_ (false), debug_ (false)
54 {}
55
67 echo_ (false), tolerant_ (false), debug_ (false)
68 {
70 }
71
75 void
77 {
78 // Default parameter values.
79 bool echo = false;
80 bool tolerant = false;
81 bool debug = false;
82
83 // Read parameters.
84 echo = params->get ("Echo to stdout", echo);
85 tolerant = params->get ("Parse tolerantly", tolerant);
86 debug = params->get ("Debug mode", debug);
87
88 // No side effects on the class until ParameterList
89 // processing is complete.
90 echo_ = echo;
91 tolerant_ = tolerant;
92 debug_ = debug;
93 }
94
96 getValidParameters () const
97 {
98 // Default parameter values.
99 const bool echo = false;
100 const bool tolerant = false;
101 const bool debug = false;
102
103 // Set default parameters with documentation.
104 RCP<ParameterList> params = parameterList ("Matrix Market Checker");
105 params->set ("Echo to stdout", echo, "Whether to echo the sparse "
106 "matrix to stdout after reading it");
107 params->set ("Parse tolerantly", tolerant, "Whether to tolerate "
108 "syntax errors when parsing the Matrix Market file");
109 params->set ("Debug mode", debug, "Whether to print debugging output "
110 "to stderr, on all participating MPI processes");
111
113 }
114
125 bool
127 const std::string& filename)
128 {
129 using std::cerr;
130 using std::endl;
131
132 const int myRank = comm.getRank ();
133 // Teuchos::broadcast doesn't accept a bool; we use an int
134 // instead, with the usual 1->true, 0->false Boolean
135 // interpretation.
136 int didReadFile = 0;
137 RCP<std::ifstream> in; // only valid on Rank 0
138 if (myRank == 0) {
139 if (debug_) {
140 cerr << "Attempting to open file \"" << filename
141 << "\" on Rank 0...";
142 }
143 in = rcp (new std::ifstream (filename.c_str()));
144 if (! *in) {
145 didReadFile = 0;
146 if (debug_) {
147 cerr << "failed." << endl;
148 }
149 }
150 else {
151 didReadFile = 1;
152 if (debug_) {
153 cerr << "succeeded." << endl;
154 }
155 }
156 }
157 Teuchos::broadcast (comm, 0, &didReadFile);
158 // All MPI processes should throw at the same time, or none.
159 TEUCHOS_TEST_FOR_EXCEPTION(! didReadFile, std::runtime_error,
160 "Failed to open input file \"" + filename + "\".");
161 // Only Rank 0 will try to dereference "in".
162 return read (comm, in);
163 }
164
175 bool
177 const RCP<std::istream>& in)
178 {
179 using std::cerr;
180 using std::endl;
181
182 const int myRank = comm.getRank ();
183 std::pair<bool, std::string> result;
184 int msgSize = 0; // Size of error message (if any)
185 if (myRank == 0) {
186 if (in.is_null()) {
187 result.first = false;
188 result.second = "Input stream is null on Rank 0";
189 }
190 else {
191 if (debug_) {
192 cerr << "About to read from input stream on Rank 0" << endl;
193 }
194 result = readOnRank0 (*in);
195 if (debug_) {
196 if (result.first) {
197 cerr << "Successfully read sparse matrix from "
198 "input stream on Rank 0" << endl;
199 }
200 else {
201 cerr << "Failed to read sparse matrix from input "
202 "stream on Rank 0" << endl;
203 }
204 }
205 }
206 if (result.first) {
207 msgSize = 0;
208 }
209 else {
210 msgSize = result.second.size();
211 }
212 }
213 int success = result.first ? 1 : 0;
214 Teuchos::broadcast (comm, 0, &success);
215 if (! success) {
216 if (! tolerant_) {
217 // Tell all ranks how long the error message is, so
218 // they can make space for it in order to receive
219 // the broadcast of the error message.
220 Teuchos::broadcast (comm, 0, &msgSize);
221
222 if (msgSize > 0) {
223 std::string errMsg (msgSize, ' ');
224 if (myRank == 0) {
225 std::copy (result.second.begin(), result.second.end(),
226 errMsg.begin());
227 }
228 Teuchos::broadcast (comm, 0, static_cast<int> (msgSize), &errMsg[0]);
229 TEUCHOS_TEST_FOR_EXCEPTION(! success, std::runtime_error, errMsg);
230 }
231 else {
232 TEUCHOS_TEST_FOR_EXCEPTION(! success, std::runtime_error,
233 "Unknown error when reading Matrix Market sparse matrix file; "
234 "the error is \"unknown\" because the error message has length 0.");
235 }
236 }
237 else if (myRank == 0) {
238 using std::cerr;
239 using std::endl;
240 cerr << "The following error occurred when reading the "
241 "sparse matrix: " << result.second << endl;
242 }
243 }
244 return success;
245 }
246
247 private:
249 bool echo_;
251 bool tolerant_;
253 bool debug_;
254
270 readBanner (std::istream& in, size_t& lineNumber)
271 {
272 using std::cerr;
273 using std::endl;
274 std::string line; // The presumed banner line
275
276 // The first line of the Matrix Market file should always be
277 // the banner line. In tolerant mode, we allow comment
278 // lines before the banner line. This complicates detection
279 // of comment lines a bit.
280 if (tolerant_) {
281 // Keep reading lines until we get a noncomment line.
282 const bool maybeBannerLine = true;
283 size_t numLinesRead = 0;
284 bool commentLine = false;
285 do {
286 // Try to read a line from the input stream.
287 const bool readFailed = ! getline (in, line);
288 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
289 "Failed to get Matrix Market banner line from input, after reading "
290 << numLinesRead << "line" << (numLinesRead != 1 ? "s." : "."));
291 // We read a line from the input stream.
292 ++lineNumber;
293 ++numLinesRead;
294 size_t start, size; // Output args of checkCommentLine
295 commentLine = checkCommentLine (line, start, size, lineNumber,
296 tolerant_, maybeBannerLine);
297 } while (commentLine); // Loop until we find a noncomment line.
298 }
299 else {
300 const bool readFailed = ! getline (in, line);
301 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
302 "Failed to get Matrix Market banner line from input. This "
303 "probably means that the file is empty (contains zero lines).");
304 }
305
306 if (debug_) {
307 cerr << "Raw::Checker::readBanner: Here is the presumed banner line:"
308 << endl << line << endl;
309 }
310
311 // Assume that the noncomment line we found is the banner line.
312 RCP<Banner> banner;
313 try {
314 banner = rcp (new Banner (line, tolerant_));
315 } catch (std::exception& e) {
316 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
317 "Matrix Market file's banner line contains syntax error(s): "
318 << e.what ());
319 }
320 return rcp_const_cast<const Banner> (banner);
321 }
322
332 std::pair<bool, std::string>
333 readOnRank0 (std::istream& in)
334 {
335 using std::cerr;
336 using std::cout;
337 using std::endl;
338 typedef ScalarTraits<Scalar> STS;
339
340 // This "Adder" knows how to add sparse matrix entries,
341 // given a line of data from the file. It also stores the
342 // entries and can sort them.
343 typedef Adder<Scalar, Ordinal> raw_adder_type;
344 // SymmetrizingAdder "advices" (yes, I'm using that as a verb)
345 // the original Adder, so that additional entries are filled
346 // in symmetrically, if the Matrix Market banner line
347 // specified a symmetry type other than "general".
348 typedef SymmetrizingAdder<raw_adder_type> adder_type;
349
350 // Current line number of the input stream.
351 size_t lineNumber = 1;
352
353 // Construct the "Banner" (matrix metadata, including type
354 // and symmetry information, but not dimensions).
355 std::ostringstream err;
356 RCP<const Banner> pBanner;
357 try {
358 pBanner = readBanner (in, lineNumber);
359 }
360 catch (std::exception& e) {
361 err << "Failed to read Matrix Market file's Banner: " << e.what();
362 return std::make_pair (false, err.str());
363 }
364 //
365 // Validate the metadata in the Banner.
366 //
367 if (pBanner->matrixType () != "coordinate") {
368 err << "Matrix Market input file must contain a \"coordinate\"-"
369 "format sparse matrix in order to create a sparse matrix object "
370 "from it.";
371 return std::make_pair (false, err.str ());
372 }
373 else if (! STS::isComplex && pBanner->dataType () == "complex") {
374 err << "The Matrix Market sparse matrix file contains complex-"
375 "valued data, but you are try to read the data into a sparse "
376 "matrix containing real values (your matrix's Scalar type is "
377 "real).";
378 return std::make_pair (false, err.str ());
379 }
380 else if (pBanner->dataType () != "real" &&
381 pBanner->dataType () != "complex") {
382 err << "Only real or complex data types (no pattern or integer "
383 "matrices) are currently supported.";
384 return std::make_pair (false, err.str ());
385 }
386 if (debug_) {
387 cerr << "Banner line:" << endl << *pBanner << endl;
388 }
389
390 // The reader will invoke the adder (see below) once for
391 // each matrix entry it reads from the input stream.
392 typedef CoordDataReader<adder_type, Ordinal, Scalar,
393 STS::isComplex> reader_type;
394 // We will set the adder below, after calling readDimensions().
395 reader_type reader;
396
397 // Read in the dimensions of the sparse matrix: (# rows, #
398 // columns, # matrix entries (counting duplicates as
399 // separate entries)). The second element of the pair tells
400 // us whether the values were gotten successfully.
401 std::pair<Tuple<Ordinal, 3>, bool> dims =
402 reader.readDimensions (in, lineNumber, tolerant_);
403 if (! dims.second) {
404 err << "Error reading Matrix Market sparse matrix "
405 "file: failed to read coordinate dimensions.";
406 return std::make_pair (false, err.str ());
407 }
408 // These are "expected" values read from the input stream's
409 // metadata. The actual matrix entries read from the input
410 // stream might not conform to their constraints. We allow
411 // such nonconformity only in "tolerant" mode; otherwise, we
412 // throw an exception.
413 const Ordinal numRows = dims.first[0];
414 const Ordinal numCols = dims.first[1];
415 const Ordinal numEntries = dims.first[2];
416 if (debug_) {
417 cerr << "Reported dimensions: " << numRows << " x " << numCols
418 << ", with " << numEntries << " entries (counting possible "
419 << "duplicates)." << endl;
420 }
421
422 // The "raw" adder knows about the expected matrix
423 // dimensions, but doesn't know about symmetry.
424 RCP<raw_adder_type> rawAdder =
425 rcp (new raw_adder_type (numRows, numCols, numEntries,
426 tolerant_, debug_));
427 // The symmetrizing adder knows about symmetry.
428 RCP<adder_type> adder =
429 rcp (new adder_type (rawAdder, pBanner->symmType ()));
430
431 // Give the adder to the reader.
432 reader.setAdder (adder);
433
434 // Read the sparse matrix entries. "results" just tells us if
435 // and where there were any bad lines of input. The actual
436 // sparse matrix entries are stored in the (raw) Adder object.
437 std::pair<bool, std::vector<size_t> > results =
438 reader.read (in, lineNumber, tolerant_, debug_);
439 if (debug_) {
440 if (results.first) {
441 cerr << "Matrix Market file successfully read" << endl;
442 }
443 else {
444 cerr << "Failed to read Matrix Market file" << endl;
445 }
446 }
447
448 // Report any bad line number(s).
449 if (! results.first) {
450 if (! tolerant_) {
451 err << "The Matrix Market input stream had syntax error(s)."
452 " Here is the error report." << endl;
453 reportBadness (err, results);
454 err << endl;
455 return std::make_pair (false, err.str ());
456 }
457 else {
458 if (debug_) {
459 reportBadness (cerr, results);
460 }
461 }
462 }
463 // We're done reading in the sparse matrix. If we're in
464 // "echo" mode, print out the matrix entries to stdout. The
465 // entries will have been symmetrized if applicable.
466 if (echo_) {
467 const bool doMerge = false;
468 const bool replace = false;
469 rawAdder->print (cout, doMerge, replace);
470 cout << endl;
471 }
472 return std::make_pair (true, err.str());
473 }
474
476 void
477 reportBadness (std::ostream& out,
478 const std::pair<bool, std::vector<size_t> >& results)
479 {
480 using std::endl;
481 const size_t numErrors = results.second.size();
482 const size_t maxNumErrorsToReport = 20;
483 out << numErrors << " errors when reading Matrix Market sparse "
484 "matrix file." << endl;
485 if (numErrors > maxNumErrorsToReport) {
486 out << "-- We do not report individual errors when there "
487 "are more than " << maxNumErrorsToReport << ".";
488 }
489 else if (numErrors == 1) {
490 out << "Error on line " << results.second[0] << endl;
491 }
492 else if (numErrors > 1) {
493 out << "Errors on lines {";
494 for (size_t k = 0; k < numErrors-1; ++k) {
495 out << results.second[k] << ", ";
496 }
497 out << results.second[numErrors-1] << "}" << endl;
498 }
499 }
500 }; // end of class Checker
501 } // namespace Raw
502 } // namespace MatrixMarket
503} // namespace Teuchos
504
505#endif // __Teuchos_MatrixMarket_Raw_Checker_hpp
Tool for debugging the syntax of a Matrix Market file containing a sparse matrix.
Checker()
Constructor that sets default Boolean parameters.
Checker(const bool echo, const bool tolerant, const bool debug)
Constructor that takes Boolean parameters.
void setParameters(const RCP< ParameterList > &params)
Set parameters from the given ParameterList.
Checker(const RCP< ParameterList > &params)
Constructor that takes a ParameterList of parameters.
bool readFile(const Teuchos::Comm< int > &comm, const std::string &filename)
Read the sparse matrix from the given file.
bool read(const Teuchos::Comm< int > &comm, const RCP< std::istream > &in)
Read the sparse matrix from the given input stream.
Smart reference counting pointer class for automatic garbage collection.
bool is_null() const
Returns true if the underlying pointer is null.
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.