Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_MatrixMarket_Raw_Reader.hpp
Go to the documentation of this file.
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 
16 
17 
18 namespace 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 
97  Reader (const RCP<ParameterList>& params) :
98  tolerant_ (false), debug_ (false)
99  {
100  setParameters (params);
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 
139  return rcp_const_cast<const ParameterList> (params);
140  }
141 
167  bool
169  ArrayRCP<Ordinal>& colind,
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
209  ArrayRCP<Ordinal>& colind,
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;
218  typedef ScalarTraits<Scalar> STS;
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.
223  typedef Adder<Scalar, Ordinal> raw_adder_type;
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".
228  typedef SymmetrizingAdder<raw_adder_type> adder_type;
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).
235  RCP<const Banner> banner;
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().
296  reader_type reader;
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.
334  RCP<raw_adder_type> rawAdder =
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.
340  RCP<adder_type> adder =
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;
369  ArrayRCP<Ordinal> ptr;
370  ArrayRCP<Ordinal> ind;
371  ArrayRCP<Scalar> val;
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...
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.
void setParameters(const RCP< ParameterList > &params)
Set parameters from the given ParameterList.
RCP< const ParameterList > getValidParameters() const
Get a list of valid default parameters, with documentation.
void init()
&quot;Initialize&quot; the Reader.
Adds entries with optional symmetry to a sparse matrix.
bool debug_
Whether to print debugging output to stderr.
std::pair< Teuchos::Tuple< Ordinal, 3 >, bool > readDimensions(std::istream &in, size_t &lineNumber, const bool tolerant=false)
Read (numRows, numCols, numNonzeros).
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
T * get() const
Get the raw C++ pointer to the underlying object.
Reader(const RCP< ParameterList > &params)
Constructor that takes a ParameterList of parameters.
Coordinate-format sparse matrix data reader.
This structure defines some basic traits for a scalar field type.
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.
bool tolerant_
Whether to parse the Matrix Market file tolerantly.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
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.
RCP< const Banner > readBanner(std::istream &in, size_t &lineNumber)
Read in the Banner line from the given input stream.
A list of parameters of arbitrary type.
Reader()
Constructor that sets default Boolean parameters.
Smart reference counting pointer class for automatic garbage collection.
Reader(const bool tolerant, const bool debug)
Constructor that takes Boolean parameters.
void reportBadness(std::ostream &out, const std::pair< bool, std::vector< size_t > > &results)
Parse a Matrix Market banner line.
Reference-counted smart pointer for managing arrays.
To be used with Checker for &quot;raw&quot; sparse matrix input.