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_CoordDataReader.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_CoordDataReader_hpp
11 #define __Teuchos_MatrixMarket_CoordDataReader_hpp
12 
14 #include "Teuchos_RCP.hpp"
15 #include "Teuchos_ScalarTraits.hpp"
16 #include "Teuchos_Tuple.hpp"
17 
18 
19 namespace Teuchos {
20  namespace MatrixMarket {
67  template<class Callback, class Ordinal>
69  protected:
72 
73  public:
85  adder_ (adder) {}
86 
95 
97  virtual ~CoordDataReaderBase () {}
98 
105  void setAdder (const Teuchos::RCP<Callback>& adder) {
106  adder_ = adder;
107  }
108 
109  protected:
136  virtual bool
137  readLine (const std::string& theLine,
138  const size_t lineNumber,
139  const bool tolerant) = 0;
140 
141  public:
142 
170  virtual std::pair<bool, std::vector<size_t> >
171  read (std::istream& in,
172  const size_t startingLineNumber,
173  const bool tolerant,
174  const bool debug = false)
175  {
176  (void) debug; // silence unused input argument warning
177  TEUCHOS_TEST_FOR_EXCEPTION(! in, std::invalid_argument,
178  "Input stream is invalid.");
179 
180  std::string line;
181  size_t lineNumber = startingLineNumber;
182  bool allSucceeded = true;
183  std::vector<size_t> badLineNumbers;
184  while (getline (in, line)) {
185  size_t start, size;
186  if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
187  ++lineNumber;
188  continue; // it's a comment line
189  }
190  const std::string theLine = line.substr (start, size);
191 
192  const bool localSuccess = readLine (theLine, lineNumber, tolerant);
193  ++lineNumber;
194  allSucceeded = allSucceeded && localSuccess;
195  if (! localSuccess) {
196  badLineNumbers.push_back (lineNumber);
197  }
198  }
199  return std::make_pair (allSucceeded, badLineNumbers);
200  }
201 
225  std::pair<Teuchos::Tuple<Ordinal, 3>, bool>
226  readDimensions (std::istream& in,
227  size_t& lineNumber,
228  const bool tolerant = false)
229  {
231  // Fill in (numRows, numCols, numNonzeros) with reasonable
232  // defaults. If we don't succeed in reading all the data
233  // from the current line of the input stream, the remaining
234  // values not read will be these default values.
235  dims[0] = 0;
236  dims[1] = 0;
237  dims[2] = 0;
238 
239  // Keep reading lines from the input stream until we find a
240  // non-comment line, or until we run out of lines. The latter
241  // is an error, since every "coordinate" format Matrix Market
242  // file must have a dimensions line after the banner (even if
243  // the matrix has zero rows or columns, or zero entries).
244  std::string line;
245  bool commentLine = true;
246  while (commentLine) {
247  // Is it even valid to read from the input stream?
248  if (in.eof() || in.fail()) {
249  if (tolerant) {
250  return std::make_pair (dims, false);
251  }
252  else {
253  std::ostringstream os;
254  os << "Unable to get coordinate dimensions line (at all) "
255  "from (line " << lineNumber << ") of input stream; the "
256  "input stream claims that it is at \"end-of-file\" or has "
257  "an otherwise \"fail\"ed state.";
258  throw std::invalid_argument(os.str());
259  }
260  }
261  // Try to get the next line from the input stream.
262  if (getline(in, line)) {
263  lineNumber++; // We did actually read a line
264  }
265  else {
266  if (tolerant) {
267  return std::make_pair (dims, false);
268  }
269  else {
270  std::ostringstream os;
271  os << "Failed to read coordinate dimensions line (at all) "
272  "from (line " << lineNumber << " from input stream. The "
273  "line should contain the coordinate matrix dimensions in "
274  << " the form \"<numRows> <numCols> <numNonzeros>\".";
275  throw std::invalid_argument (os.str());
276  }
277  }
278  // Is the current line a comment line? Ignore start and
279  // size; they are only useful for reading the actual matrix
280  // entries. (We could use them here as an optimization, but
281  // we've chosen not to.)
282  size_t start = 0, size = 0;
283  commentLine = checkCommentLine (line, start, size,
284  lineNumber, tolerant);
285  }
286  //
287  // Read in <numRows> <numCols> <numNonzeros> from input line
288  //
289  std::istringstream istr (line);
290  // Does line contain anything at all? Can we safely read from
291  // the input stream wrapping the line?
292  if (istr.eof() || istr.fail()) {
293  if (tolerant) {
294  return std::make_pair (dims, false);
295  }
296  std::ostringstream os;
297  os << "Unable to read any data from line " << lineNumber
298  << " of input; the line should contain the coordinate matrix "
299  << "dimensions \"<numRows> <numCols> <numNonzeros>\".";
300  throw std::invalid_argument(os.str());
301  }
302  // Read in <numRows>
303  {
304  Ordinal theNumRows = 0;
305  istr >> theNumRows;
306  if (istr.fail()) {
307  if (tolerant) {
308  return std::make_pair (dims, false);
309  }
310  std::ostringstream os;
311  os << "Failed to get number of rows from line " << lineNumber
312  << " of input; the line should contain the coordinate matrix "
313  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
314  throw std::invalid_argument(os.str());
315  }
316  else { // Capture the validly read result before checking for eof.
317  dims[0] = theNumRows;
318  }
319  }
320  // There should be two more things to read.
321  if (istr.eof()) {
322  if (tolerant) {
323  return std::make_pair (dims, false);
324  }
325  std::ostringstream os;
326  os << "No more data after number of rows on line " << lineNumber
327  << " of input; the line should contain the coordinate matrix "
328  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
329  throw std::invalid_argument(os.str());
330  }
331  // Read in <numCols>
332  {
333  Ordinal theNumCols = 0;
334  istr >> theNumCols;
335  if (istr.fail()) {
336  if (tolerant) {
337  return std::make_pair (dims, false);
338  }
339  std::ostringstream os;
340  os << "Failed to get number of columns from line " << lineNumber
341  << " of input; the line should contain the coordinate matrix "
342  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
343  throw std::invalid_argument(os.str());
344  }
345  else { // Capture the validly read result before checking for eof.
346  dims[1] = theNumCols;
347  }
348  }
349  // There should be one more thing to read.
350  if (istr.eof()) {
351  if (tolerant) {
352  return std::make_pair (dims, false);
353  }
354  std::ostringstream os;
355  os << "No more data after number of columns on line " << lineNumber
356  << " of input; the line should contain the coordinate matrix "
357  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
358  throw std::invalid_argument(os.str());
359  }
360  // Read in <numNonzeros>
361  {
362  Ordinal theNumNonzeros = 0;
363  istr >> theNumNonzeros;
364  if (istr.fail()) {
365  if (tolerant) {
366  return std::make_pair (dims, false);
367  }
368  std::ostringstream os;
369  os << "Failed to get number of (structural) nonzeros from line "
370  << lineNumber
371  << " of input; the line should contain the coordinate matrix "
372  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
373  throw std::invalid_argument(os.str());
374  }
375  else { // Capture the validly read result
376  dims[2] = theNumNonzeros;
377  }
378  }
379  // It would be nice to validate the read-in data further. The
380  // only thing we can do now is test if it's negative. However,
381  // we don't know syntactically whether Ordinal is a signed or
382  // unsigned type, so we shouldn't even test for negativity.
383  return std::make_pair (dims, true);
384  }
385  };
386 
421  template<class Callback,
422  class Ordinal,
423  class Scalar,
425  class CoordDataReader : public CoordDataReaderBase<Callback, Ordinal> {
426  public:
440 
448  CoordDataReader ();
449 
451  virtual ~CoordDataReader();
452 
453  protected:
454  bool
455  readLine (const std::string& theLine,
456  const size_t lineNumber,
457  const bool tolerant);
458  };
459 
460 #ifdef HAVE_TEUCHOS_COMPLEX
461  // Partial specialization for complex Scalar types.
462  template<class Callback, class Ordinal, class Scalar>
463  class CoordDataReader<Callback, Ordinal, Scalar, true> :
464  public CoordDataReaderBase<Callback, Ordinal> {
465  public:
466  CoordDataReader (const Teuchos::RCP<Callback>& adder) :
467  CoordDataReaderBase<Callback, Ordinal> (adder)
468  {}
469 
470  CoordDataReader() :
471  CoordDataReaderBase<Callback, Ordinal> (null)
472  {}
473 
474  virtual ~CoordDataReader() {};
475 
476  protected:
477  bool
478  readLine (const std::string& theLine,
479  const size_t lineNumber,
480  const bool tolerant)
481  {
482  typedef Teuchos::ScalarTraits<Scalar> STS;
483  typedef typename STS::magnitudeType Real;
484 
485  Ordinal rowIndex;
486  Ordinal colIndex;
487  Scalar value;
488 
489  Real realPart, imagPart;
490  const bool localSuccess =
491  readComplexLine (theLine, rowIndex, colIndex, realPart, imagPart,
492  lineNumber, tolerant);
493  if (localSuccess) {
494  // Assume that assignment from std::complex<Real> to Scalar
495  // (which itself is complex-valued) is valid. We have to do
496  // this, since the C++ compiler may not be smart enough to
497  // assume here (when it instantiates the templates) that
498  // Scalar is an std::complex<Real> -- even though it has to
499  // be, if STS::isComplex is true (which as of 31 Jan 2011,
500  // only holds for std::complex<T>).
501  value = std::complex<Real> (realPart, imagPart);
502 
503  // Now that we've read in the (i, j, A_ij) triple
504  // successfully, we can add the entry to the sparse matrix.
505  (*(this->adder_)) (rowIndex, colIndex, value);
506  }
507  return localSuccess;
508  }
509  };
510 #endif // HAVE_TEUCHOS_COMPLEX
511 
512  // Partial specialization for real Scalar types.
513  template<class Callback, class Ordinal, class Scalar>
514  class CoordDataReader<Callback, Ordinal, Scalar, false> :
515  public CoordDataReaderBase<Callback, Ordinal> {
516  public:
518  CoordDataReaderBase<Callback, Ordinal> (adder)
519  {}
520 
522  CoordDataReaderBase<Callback, Ordinal> (null)
523  {}
524 
525  virtual ~CoordDataReader() {};
526 
527  protected:
528  bool
529  readLine (const std::string& theLine,
530  const size_t lineNumber,
531  const bool tolerant)
532  {
533  Ordinal rowIndex;
534  Ordinal colIndex;
535  Scalar value;
536  const bool localSuccess = readRealLine (theLine, rowIndex, colIndex,
537  value, lineNumber, tolerant);
538  if (localSuccess) {
539  // Now that we've read in the (i, j, A_ij) triple
540  // successfully, we can add the entry to the sparse matrix.
541  (*(this->adder_)) (rowIndex, colIndex, value);
542  }
543  return localSuccess;
544  }
545  };
546 
547 
570  template<class Callback, class Ordinal>
571  class CoordPatternReader : public CoordDataReaderBase<Callback, Ordinal> {
572  public:
586  CoordDataReaderBase<Callback, Ordinal> (adder)
587  {}
588 
597  CoordDataReaderBase<Callback, Ordinal> (null)
598  {}
599 
601  virtual ~CoordPatternReader() {};
602 
603  protected:
604  bool
605  readLine (const std::string& theLine,
606  const size_t lineNumber,
607  const bool tolerant)
608  {
609  Ordinal rowIndex;
610  Ordinal colIndex;
611  const bool localSuccess =
612  readPatternLine (theLine, rowIndex, colIndex, lineNumber, tolerant);
613  if (localSuccess) {
614  // Now that we've read in the (i, j) pair successfully, we
615  // can add the entry to the sparse graph.
616  (*(this->adder_)) (rowIndex, colIndex);
617  }
618  return localSuccess;
619  }
620  };
621 
622  } // namespace MatrixMarket
623 } // namespace Teuchos
624 
625 #endif // __Teuchos_MatrixMarket_CoordDataReader_hpp
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.
virtual std::pair< bool, std::vector< size_t > > read(std::istream &in, const size_t startingLineNumber, const bool tolerant, const bool debug=false)
Read in all the data from the given input stream.
CoordDataReader()
No-argument constructor.
bool readLine(const std::string &theLine, const size_t lineNumber, const bool tolerant)
Read in the data from a single line of the input stream.
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.
virtual ~CoordPatternReader()
Virtual destructor for safety and happy compilers.
CoordDataReaderBase(const Teuchos::RCP< Callback > &adder)
Constructor with &quot;adder&quot; argument.
Coordinate-format sparse matrix data reader.
This structure defines some basic traits for a scalar field type.
Statically sized simple array (tuple) class.
bool readLine(const std::string &theLine, const size_t lineNumber, const bool tolerant)
Read in the data from a single line of the input stream.
CoordPatternReader(const Teuchos::RCP< Callback > &adder)
Constructor with &quot;adder&quot; argument.
bool readPatternLine(const std::string &line, Ordinal &rowIndex, Ordinal &colIndex, const size_t lineNumber, const bool tolerant)
bool readLine(const std::string &theLine, const size_t lineNumber, const bool tolerant)
Read in the data from a single line of the input stream.
virtual bool readLine(const std::string &theLine, const size_t lineNumber, const bool tolerant)=0
Read in the data from a single line of the input stream.
bool readRealLine(const std::string &line, Ordinal &rowIndex, Ordinal &colIndex, Real &realValue, const size_t lineNumber, const bool tolerant)
virtual ~CoordDataReader()
Virtual destructor for safety and happy compilers.
void setAdder(const Teuchos::RCP< Callback > &adder)
Set the Adder object.
Defines basic traits for the scalar field type.
Teuchos::RCP< Callback > adder_
Closure that knows how to add entries to the sparse graph or matrix.
Common functionality of a coordinate-format sparse matrix or graph data reader.
virtual ~CoordDataReaderBase()
Virtual destructor for safety and happy compilers.
Reference-counted pointer class and non-member templated function implementations.