Teuchos Package Browser (Single Doxygen Collection) Version of the Day
Loading...
Searching...
No Matches
Teuchos_MatrixMarket_Raw_Checker.hpp
Go to the documentation of this file.
1// @HEADER
2// ***********************************************************************
3//
4// Tpetra: Templated Linear Algebra Services Package
5// Copyright (2008) Sandia Corporation
6//
7// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8// the U.S. Government retains certain rights in this software.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are
12// met:
13//
14// 1. Redistributions of source code must retain the above copyright
15// notice, this list of conditions and the following disclaimer.
16//
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// 3. Neither the name of the Corporation nor the names of the
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36//
37// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38//
39// ************************************************************************
40// @HEADER
41
42#ifndef __Teuchos_MatrixMarket_Raw_Checker_hpp
43#define __Teuchos_MatrixMarket_Raw_Checker_hpp
44
48
49
50namespace Teuchos {
51 namespace MatrixMarket {
52 namespace Raw {
67 template<class Scalar, class Ordinal>
68 class Checker {
69 public:
79 Checker (const bool echo, const bool tolerant, const bool debug) :
81 {}
82
86 {}
87
103
107 void
109 {
110 // Default parameter values.
111 bool echo = false;
112 bool tolerant = false;
113 bool debug = false;
114
115 // Read parameters.
116 echo = params->get ("Echo to stdout", echo);
117 tolerant = params->get ("Parse tolerantly", tolerant);
118 debug = params->get ("Debug mode", debug);
119
120 // No side effects on the class until ParameterList
121 // processing is complete.
122 echo_ = echo;
124 debug_ = debug;
125 }
126
129 {
130 // Default parameter values.
131 const bool echo = false;
132 const bool tolerant = false;
133 const bool debug = false;
134
135 // Set default parameters with documentation.
136 RCP<ParameterList> params = parameterList ("Matrix Market Checker");
137 params->set ("Echo to stdout", echo, "Whether to echo the sparse "
138 "matrix to stdout after reading it");
139 params->set ("Parse tolerantly", tolerant, "Whether to tolerate "
140 "syntax errors when parsing the Matrix Market file");
141 params->set ("Debug mode", debug, "Whether to print debugging output "
142 "to stderr, on all participating MPI processes");
143
145 }
146
157 bool
159 const std::string& filename)
160 {
161 using std::cerr;
162 using std::endl;
163
164 const int myRank = comm.getRank ();
165 // Teuchos::broadcast doesn't accept a bool; we use an int
166 // instead, with the usual 1->true, 0->false Boolean
167 // interpretation.
168 int didReadFile = 0;
169 RCP<std::ifstream> in; // only valid on Rank 0
170 if (myRank == 0) {
171 if (debug_) {
172 cerr << "Attempting to open file \"" << filename
173 << "\" on Rank 0...";
174 }
175 in = rcp (new std::ifstream (filename.c_str()));
176 if (! *in) {
177 didReadFile = 0;
178 if (debug_) {
179 cerr << "failed." << endl;
180 }
181 }
182 else {
183 didReadFile = 1;
184 if (debug_) {
185 cerr << "succeeded." << endl;
186 }
187 }
188 }
189 Teuchos::broadcast (comm, 0, &didReadFile);
190 // All MPI processes should throw at the same time, or none.
191 TEUCHOS_TEST_FOR_EXCEPTION(! didReadFile, std::runtime_error,
192 "Failed to open input file \"" + filename + "\".");
193 // Only Rank 0 will try to dereference "in".
194 return read (comm, in);
195 }
196
207 bool
209 const RCP<std::istream>& in)
210 {
211 using std::cerr;
212 using std::endl;
213
214 const int myRank = comm.getRank ();
215 std::pair<bool, std::string> result;
216 int msgSize = 0; // Size of error message (if any)
217 if (myRank == 0) {
218 if (in.is_null()) {
219 result.first = false;
220 result.second = "Input stream is null on Rank 0";
221 }
222 else {
223 if (debug_) {
224 cerr << "About to read from input stream on Rank 0" << endl;
225 }
226 result = readOnRank0 (*in);
227 if (debug_) {
228 if (result.first) {
229 cerr << "Successfully read sparse matrix from "
230 "input stream on Rank 0" << endl;
231 }
232 else {
233 cerr << "Failed to read sparse matrix from input "
234 "stream on Rank 0" << endl;
235 }
236 }
237 }
238 if (result.first) {
239 msgSize = 0;
240 }
241 else {
242 msgSize = result.second.size();
243 }
244 }
245 int success = result.first ? 1 : 0;
246 Teuchos::broadcast (comm, 0, &success);
247 if (! success) {
248 if (! tolerant_) {
249 // Tell all ranks how long the error message is, so
250 // they can make space for it in order to receive
251 // the broadcast of the error message.
252 Teuchos::broadcast (comm, 0, &msgSize);
253
254 if (msgSize > 0) {
255 std::string errMsg (msgSize, ' ');
256 if (myRank == 0) {
257 std::copy (result.second.begin(), result.second.end(),
258 errMsg.begin());
259 }
260 Teuchos::broadcast (comm, 0, static_cast<int> (msgSize), &errMsg[0]);
261 TEUCHOS_TEST_FOR_EXCEPTION(! success, std::runtime_error, errMsg);
262 }
263 else {
264 TEUCHOS_TEST_FOR_EXCEPTION(! success, std::runtime_error,
265 "Unknown error when reading Matrix Market sparse matrix file; "
266 "the error is \"unknown\" because the error message has length 0.");
267 }
268 }
269 else if (myRank == 0) {
270 using std::cerr;
271 using std::endl;
272 cerr << "The following error occurred when reading the "
273 "sparse matrix: " << result.second << endl;
274 }
275 }
276 return success;
277 }
278
279 private:
281 bool echo_;
285 bool debug_;
286
302 readBanner (std::istream& in, size_t& lineNumber)
303 {
304 using std::cerr;
305 using std::endl;
306 std::string line; // The presumed banner line
307
308 // The first line of the Matrix Market file should always be
309 // the banner line. In tolerant mode, we allow comment
310 // lines before the banner line. This complicates detection
311 // of comment lines a bit.
312 if (tolerant_) {
313 // Keep reading lines until we get a noncomment line.
314 const bool maybeBannerLine = true;
315 size_t numLinesRead = 0;
316 bool commentLine = false;
317 do {
318 // Try to read a line from the input stream.
319 const bool readFailed = ! getline (in, line);
320 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
321 "Failed to get Matrix Market banner line from input, after reading "
322 << numLinesRead << "line" << (numLinesRead != 1 ? "s." : "."));
323 // We read a line from the input stream.
324 ++lineNumber;
325 ++numLinesRead;
326 size_t start, size; // Output args of checkCommentLine
329 } while (commentLine); // Loop until we find a noncomment line.
330 }
331 else {
332 const bool readFailed = ! getline (in, line);
333 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
334 "Failed to get Matrix Market banner line from input. This "
335 "probably means that the file is empty (contains zero lines).");
336 }
337
338 if (debug_) {
339 cerr << "Raw::Checker::readBanner: Here is the presumed banner line:"
340 << endl << line << endl;
341 }
342
343 // Assume that the noncomment line we found is the banner line.
345 try {
346 banner = rcp (new Banner (line, tolerant_));
347 } catch (std::exception& e) {
348 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
349 "Matrix Market file's banner line contains syntax error(s): "
350 << e.what ());
351 }
353 }
354
364 std::pair<bool, std::string>
365 readOnRank0 (std::istream& in)
366 {
367 using std::cerr;
368 using std::cout;
369 using std::endl;
370 typedef ScalarTraits<Scalar> STS;
371
372 // This "Adder" knows how to add sparse matrix entries,
373 // given a line of data from the file. It also stores the
374 // entries and can sort them.
376 // SymmetrizingAdder "advices" (yes, I'm using that as a verb)
377 // the original Adder, so that additional entries are filled
378 // in symmetrically, if the Matrix Market banner line
379 // specified a symmetry type other than "general".
381
382 // Current line number of the input stream.
383 size_t lineNumber = 1;
384
385 // Construct the "Banner" (matrix metadata, including type
386 // and symmetry information, but not dimensions).
387 std::ostringstream err;
389 try {
391 }
392 catch (std::exception& e) {
393 err << "Failed to read Matrix Market file's Banner: " << e.what();
394 return std::make_pair (false, err.str());
395 }
396 //
397 // Validate the metadata in the Banner.
398 //
399 if (pBanner->matrixType () != "coordinate") {
400 err << "Matrix Market input file must contain a \"coordinate\"-"
401 "format sparse matrix in order to create a sparse matrix object "
402 "from it.";
403 return std::make_pair (false, err.str ());
404 }
405 else if (! STS::isComplex && pBanner->dataType () == "complex") {
406 err << "The Matrix Market sparse matrix file contains complex-"
407 "valued data, but you are try to read the data into a sparse "
408 "matrix containing real values (your matrix's Scalar type is "
409 "real).";
410 return std::make_pair (false, err.str ());
411 }
412 else if (pBanner->dataType () != "real" &&
413 pBanner->dataType () != "complex") {
414 err << "Only real or complex data types (no pattern or integer "
415 "matrices) are currently supported.";
416 return std::make_pair (false, err.str ());
417 }
418 if (debug_) {
419 cerr << "Banner line:" << endl << *pBanner << endl;
420 }
421
422 // The reader will invoke the adder (see below) once for
423 // each matrix entry it reads from the input stream.
424 typedef CoordDataReader<adder_type, Ordinal, Scalar,
425 STS::isComplex> reader_type;
426 // We will set the adder below, after calling readDimensions().
428
429 // Read in the dimensions of the sparse matrix: (# rows, #
430 // columns, # matrix entries (counting duplicates as
431 // separate entries)). The second element of the pair tells
432 // us whether the values were gotten successfully.
433 std::pair<Tuple<Ordinal, 3>, bool> dims =
434 reader.readDimensions (in, lineNumber, tolerant_);
435 if (! dims.second) {
436 err << "Error reading Matrix Market sparse matrix "
437 "file: failed to read coordinate dimensions.";
438 return std::make_pair (false, err.str ());
439 }
440 // These are "expected" values read from the input stream's
441 // metadata. The actual matrix entries read from the input
442 // stream might not conform to their constraints. We allow
443 // such nonconformity only in "tolerant" mode; otherwise, we
444 // throw an exception.
445 const Ordinal numRows = dims.first[0];
446 const Ordinal numCols = dims.first[1];
447 const Ordinal numEntries = dims.first[2];
448 if (debug_) {
449 cerr << "Reported dimensions: " << numRows << " x " << numCols
450 << ", with " << numEntries << " entries (counting possible "
451 << "duplicates)." << endl;
452 }
453
454 // The "raw" adder knows about the expected matrix
455 // dimensions, but doesn't know about symmetry.
457 rcp (new raw_adder_type (numRows, numCols, numEntries,
458 tolerant_, debug_));
459 // The symmetrizing adder knows about symmetry.
461 rcp (new adder_type (rawAdder, pBanner->symmType ()));
462
463 // Give the adder to the reader.
464 reader.setAdder (adder);
465
466 // Read the sparse matrix entries. "results" just tells us if
467 // and where there were any bad lines of input. The actual
468 // sparse matrix entries are stored in the (raw) Adder object.
469 std::pair<bool, std::vector<size_t> > results =
471 if (debug_) {
472 if (results.first) {
473 cerr << "Matrix Market file successfully read" << endl;
474 }
475 else {
476 cerr << "Failed to read Matrix Market file" << endl;
477 }
478 }
479
480 // Report any bad line number(s).
481 if (! results.first) {
482 if (! tolerant_) {
483 err << "The Matrix Market input stream had syntax error(s)."
484 " Here is the error report." << endl;
486 err << endl;
487 return std::make_pair (false, err.str ());
488 }
489 else {
490 if (debug_) {
492 }
493 }
494 }
495 // We're done reading in the sparse matrix. If we're in
496 // "echo" mode, print out the matrix entries to stdout. The
497 // entries will have been symmetrized if applicable.
498 if (echo_) {
499 const bool doMerge = false;
500 const bool replace = false;
501 rawAdder->print (cout, doMerge, replace);
502 cout << endl;
503 }
504 return std::make_pair (true, err.str());
505 }
506
508 void
509 reportBadness (std::ostream& out,
510 const std::pair<bool, std::vector<size_t> >& results)
511 {
512 using std::endl;
513 const size_t numErrors = results.second.size();
514 const size_t maxNumErrorsToReport = 20;
515 out << numErrors << " errors when reading Matrix Market sparse "
516 "matrix file." << endl;
518 out << "-- We do not report individual errors when there "
519 "are more than " << maxNumErrorsToReport << ".";
520 }
521 else if (numErrors == 1) {
522 out << "Error on line " << results.second[0] << endl;
523 }
524 else if (numErrors > 1) {
525 out << "Errors on lines {";
526 for (size_t k = 0; k < numErrors-1; ++k) {
527 out << results.second[k] << ", ";
528 }
529 out << results.second[numErrors-1] << "}" << endl;
530 }
531 }
532 }; // end of class Checker
533 } // namespace Raw
534 } // namespace MatrixMarket
535} // namespace Teuchos
536
537#endif // __Teuchos_MatrixMarket_Raw_Checker_hpp
int size(const Comm< Ordinal > &comm)
Get the number of processes in the communicator.
Parse a Matrix Market banner line.
Coordinate-format sparse matrix data reader.
Tool for debugging the syntax of a Matrix Market file containing a sparse matrix.
std::pair< bool, std::string > readOnRank0(std::istream &in)
Read the sparse matrix on MPI Rank 0.
void reportBadness(std::ostream &out, const std::pair< bool, std::vector< size_t > > &results)
To be called only on MPI Rank 0.
RCP< const Teuchos::MatrixMarket::Banner > readBanner(std::istream &in, size_t &lineNumber)
Read in the Banner line from the given input stream.
bool echo_
Whether to echo the sparse matrix to stdout after reading it.
RCP< const ParameterList > getValidParameters() const
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.
bool tolerant_
Whether to parse the Matrix Market file tolerantly.
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.
bool debug_
Whether to print debugging output to stderr.
Concrete serial communicator subclass.
#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.
bool checkCommentLine(const std::string &line, size_t &start, size_t &size, const size_t lineNumber, const bool tolerant, const bool maybeBannerLine)
True if the line is a comment line, false otherwise.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.