Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_MatrixMarket_Raw_Checker.hpp
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
45#include "Teuchos_MatrixMarket_Raw_Adder.hpp"
46#include "Teuchos_MatrixMarket_SymmetrizingAdder.hpp"
47#include "Teuchos_MatrixMarket_CoordDataReader.hpp"
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) :
80 echo_ (echo), tolerant_ (tolerant), debug_ (debug)
81 {}
82
85 echo_ (false), tolerant_ (false), debug_ (false)
86 {}
87
98 Checker (const RCP<ParameterList>& params) :
99 echo_ (false), tolerant_ (false), debug_ (false)
100 {
101 setParameters (params);
102 }
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;
123 tolerant_ = tolerant;
124 debug_ = debug;
125 }
126
128 getValidParameters () const
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
144 return rcp_const_cast<const ParameterList> (params);
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_;
283 bool tolerant_;
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
327 commentLine = checkCommentLine (line, start, size, lineNumber,
328 tolerant_, maybeBannerLine);
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.
344 RCP<Banner> banner;
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 }
352 return rcp_const_cast<const Banner> (banner);
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.
375 typedef Adder<Scalar, Ordinal> raw_adder_type;
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".
380 typedef SymmetrizingAdder<raw_adder_type> adder_type;
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;
388 RCP<const Banner> pBanner;
389 try {
390 pBanner = readBanner (in, lineNumber);
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().
427 reader_type reader;
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.
456 RCP<raw_adder_type> rawAdder =
457 rcp (new raw_adder_type (numRows, numCols, numEntries,
458 tolerant_, debug_));
459 // The symmetrizing adder knows about symmetry.
460 RCP<adder_type> adder =
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 =
470 reader.read (in, lineNumber, tolerant_, debug_);
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;
485 reportBadness (err, results);
486 err << endl;
487 return std::make_pair (false, err.str ());
488 }
489 else {
490 if (debug_) {
491 reportBadness (cerr, results);
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;
517 if (numErrors > maxNumErrorsToReport) {
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
Abstract interface for distributed-memory communication.
virtual int getRank() const =0
Returns the rank of this process.
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.