Teuchos - Trilinos Tools Package  Version of the Day
Teuchos_MatrixMarket_CoordDataReader.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_CoordDataReader_hpp
43 #define __Teuchos_MatrixMarket_CoordDataReader_hpp
44 
45 #include "Teuchos_MatrixMarket_generic.hpp"
46 #include "Teuchos_RCP.hpp"
47 #include "Teuchos_ScalarTraits.hpp"
48 #include "Teuchos_Tuple.hpp"
49 
50 
51 namespace Teuchos {
52  namespace MatrixMarket {
99  template<class Callback, class Ordinal>
101  protected:
104 
105  public:
117  adder_ (adder) {}
118 
127 
129  virtual ~CoordDataReaderBase () {}
130 
137  void setAdder (const Teuchos::RCP<Callback>& adder) {
138  adder_ = adder;
139  }
140 
141  protected:
168  virtual bool
169  readLine (const std::string& theLine,
170  const size_t lineNumber,
171  const bool tolerant) = 0;
172 
173  public:
174 
202  virtual std::pair<bool, std::vector<size_t> >
203  read (std::istream& in,
204  const size_t startingLineNumber,
205  const bool tolerant,
206  const bool debug = false)
207  {
208  (void) debug; // silence unused input argument warning
209  TEUCHOS_TEST_FOR_EXCEPTION(! in, std::invalid_argument,
210  "Input stream is invalid.");
211 
212  std::string line;
213  size_t lineNumber = startingLineNumber;
214  bool allSucceeded = true;
215  std::vector<size_t> badLineNumbers;
216  size_t validDataLines = 0;
217  while (getline (in, line)) {
218  size_t start, size;
219  if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
220  ++lineNumber;
221  continue; // it's a comment line
222  }
223  const std::string theLine = line.substr (start, size);
224 
225  const bool localSuccess = readLine (theLine, lineNumber, tolerant);
226  ++lineNumber;
227  allSucceeded = allSucceeded && localSuccess;
228  if (! localSuccess) {
229  badLineNumbers.push_back (lineNumber);
230  }
231  else {
232  ++validDataLines;
233  }
234  }
235  return std::make_pair (allSucceeded, badLineNumbers);
236  }
237 
261  std::pair<Teuchos::Tuple<Ordinal, 3>, bool>
262  readDimensions (std::istream& in,
263  size_t& lineNumber,
264  const bool tolerant = false)
265  {
267  // Fill in (numRows, numCols, numNonzeros) with reasonable
268  // defaults. If we don't succeed in reading all the data
269  // from the current line of the input stream, the remaining
270  // values not read will be these default values.
271  dims[0] = 0;
272  dims[1] = 0;
273  dims[2] = 0;
274 
275  // Keep reading lines from the input stream until we find a
276  // non-comment line, or until we run out of lines. The latter
277  // is an error, since every "coordinate" format Matrix Market
278  // file must have a dimensions line after the banner (even if
279  // the matrix has zero rows or columns, or zero entries).
280  std::string line;
281  bool commentLine = true;
282  while (commentLine) {
283  // Is it even valid to read from the input stream?
284  if (in.eof() || in.fail()) {
285  if (tolerant) {
286  return std::make_pair (dims, false);
287  }
288  else {
289  std::ostringstream os;
290  os << "Unable to get coordinate dimensions line (at all) "
291  "from (line " << lineNumber << ") of input stream; the "
292  "input stream claims that it is at \"end-of-file\" or has "
293  "an otherwise \"fail\"ed state.";
294  throw std::invalid_argument(os.str());
295  }
296  }
297  // Try to get the next line from the input stream.
298  if (getline(in, line)) {
299  lineNumber++; // We did actually read a line
300  }
301  else {
302  if (tolerant) {
303  return std::make_pair (dims, false);
304  }
305  else {
306  std::ostringstream os;
307  os << "Failed to read coordinate dimensions line (at all) "
308  "from (line " << lineNumber << " from input stream. The "
309  "line should contain the coordinate matrix dimensions in "
310  << " the form \"<numRows> <numCols> <numNonzeros>\".";
311  throw std::invalid_argument (os.str());
312  }
313  }
314  // Is the current line a comment line? Ignore start and
315  // size; they are only useful for reading the actual matrix
316  // entries. (We could use them here as an optimization, but
317  // we've chosen not to.)
318  size_t start = 0, size = 0;
319  commentLine = checkCommentLine (line, start, size,
320  lineNumber, tolerant);
321  }
322  //
323  // Read in <numRows> <numCols> <numNonzeros> from input line
324  //
325  std::istringstream istr (line);
326  // Does line contain anything at all? Can we safely read from
327  // the input stream wrapping the line?
328  if (istr.eof() || istr.fail()) {
329  if (tolerant) {
330  return std::make_pair (dims, false);
331  }
332  std::ostringstream os;
333  os << "Unable to read any data from line " << lineNumber
334  << " of input; the line should contain the coordinate matrix "
335  << "dimensions \"<numRows> <numCols> <numNonzeros>\".";
336  throw std::invalid_argument(os.str());
337  }
338  // Read in <numRows>
339  {
340  Ordinal theNumRows = 0;
341  istr >> theNumRows;
342  if (istr.fail()) {
343  if (tolerant) {
344  return std::make_pair (dims, false);
345  }
346  std::ostringstream os;
347  os << "Failed to get number of rows from line " << lineNumber
348  << " of input; the line should contain the coordinate matrix "
349  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
350  throw std::invalid_argument(os.str());
351  }
352  else { // Capture the validly read result before checking for eof.
353  dims[0] = theNumRows;
354  }
355  }
356  // There should be two more things to read.
357  if (istr.eof()) {
358  if (tolerant) {
359  return std::make_pair (dims, false);
360  }
361  std::ostringstream os;
362  os << "No more data after number of rows on line " << lineNumber
363  << " of input; the line should contain the coordinate matrix "
364  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
365  throw std::invalid_argument(os.str());
366  }
367  // Read in <numCols>
368  {
369  Ordinal theNumCols = 0;
370  istr >> theNumCols;
371  if (istr.fail()) {
372  if (tolerant) {
373  return std::make_pair (dims, false);
374  }
375  std::ostringstream os;
376  os << "Failed to get number of columns from line " << lineNumber
377  << " of input; the line should contain the coordinate matrix "
378  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
379  throw std::invalid_argument(os.str());
380  }
381  else { // Capture the validly read result before checking for eof.
382  dims[1] = theNumCols;
383  }
384  }
385  // There should be one more thing to read.
386  if (istr.eof()) {
387  if (tolerant) {
388  return std::make_pair (dims, false);
389  }
390  std::ostringstream os;
391  os << "No more data after number of columns on line " << lineNumber
392  << " of input; the line should contain the coordinate matrix "
393  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
394  throw std::invalid_argument(os.str());
395  }
396  // Read in <numNonzeros>
397  {
398  Ordinal theNumNonzeros = 0;
399  istr >> theNumNonzeros;
400  if (istr.fail()) {
401  if (tolerant) {
402  return std::make_pair (dims, false);
403  }
404  std::ostringstream os;
405  os << "Failed to get number of (structural) nonzeros from line "
406  << lineNumber
407  << " of input; the line should contain the coordinate matrix "
408  << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
409  throw std::invalid_argument(os.str());
410  }
411  else { // Capture the validly read result
412  dims[2] = theNumNonzeros;
413  }
414  }
415  // It would be nice to validate the read-in data further. The
416  // only thing we can do now is test if it's negative. However,
417  // we don't know syntactically whether Ordinal is a signed or
418  // unsigned type, so we shouldn't even test for negativity.
419  return std::make_pair (dims, true);
420  }
421  };
422 
457  template<class Callback,
458  class Ordinal,
459  class Scalar,
461  class CoordDataReader : public CoordDataReaderBase<Callback, Ordinal> {
462  public:
476 
485 
487  virtual ~CoordDataReader();
488 
489  protected:
490  bool
491  readLine (const std::string& theLine,
492  const size_t lineNumber,
493  const bool tolerant);
494  };
495 
496 #ifdef HAVE_TEUCHOS_COMPLEX
497  // Partial specialization for complex Scalar types.
498  template<class Callback, class Ordinal, class Scalar>
499  class CoordDataReader<Callback, Ordinal, Scalar, true> :
500  public CoordDataReaderBase<Callback, Ordinal> {
501  public:
502  CoordDataReader (const Teuchos::RCP<Callback>& adder) :
503  CoordDataReaderBase<Callback, Ordinal> (adder)
504  {}
505 
506  CoordDataReader() :
507  CoordDataReaderBase<Callback, Ordinal> (null)
508  {}
509 
510  virtual ~CoordDataReader() {};
511 
512  protected:
513  bool
514  readLine (const std::string& theLine,
515  const size_t lineNumber,
516  const bool tolerant)
517  {
518  typedef Teuchos::ScalarTraits<Scalar> STS;
519  typedef typename STS::magnitudeType Real;
520 
521  Ordinal rowIndex;
522  Ordinal colIndex;
523  Scalar value;
524 
525  Real realPart, imagPart;
526  const bool localSuccess =
527  readComplexLine (theLine, rowIndex, colIndex, realPart, imagPart,
528  lineNumber, tolerant);
529  if (localSuccess) {
530  // Assume that assignment from std::complex<Real> to Scalar
531  // (which itself is complex-valued) is valid. We have to do
532  // this, since the C++ compiler may not be smart enough to
533  // assume here (when it instantiates the templates) that
534  // Scalar is an std::complex<Real> -- even though it has to
535  // be, if STS::isComplex is true (which as of 31 Jan 2011,
536  // only holds for std::complex<T>).
537  value = std::complex<Real> (realPart, imagPart);
538 
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 #endif // HAVE_TEUCHOS_COMPLEX
547 
548  // Partial specialization for real Scalar types.
549  template<class Callback, class Ordinal, class Scalar>
550  class CoordDataReader<Callback, Ordinal, Scalar, false> :
551  public CoordDataReaderBase<Callback, Ordinal> {
552  public:
553  CoordDataReader (const Teuchos::RCP<Callback>& adder) :
554  CoordDataReaderBase<Callback, Ordinal> (adder)
555  {}
556 
557  CoordDataReader() :
558  CoordDataReaderBase<Callback, Ordinal> (null)
559  {}
560 
561  virtual ~CoordDataReader() {};
562 
563  protected:
564  bool
565  readLine (const std::string& theLine,
566  const size_t lineNumber,
567  const bool tolerant)
568  {
569  Ordinal rowIndex;
570  Ordinal colIndex;
571  Scalar value;
572  const bool localSuccess = readRealLine (theLine, rowIndex, colIndex,
573  value, lineNumber, tolerant);
574  if (localSuccess) {
575  // Now that we've read in the (i, j, A_ij) triple
576  // successfully, we can add the entry to the sparse matrix.
577  (*(this->adder_)) (rowIndex, colIndex, value);
578  }
579  return localSuccess;
580  }
581  };
582 
583 
606  template<class Callback, class Ordinal>
607  class CoordPatternReader : public CoordDataReaderBase<Callback, Ordinal> {
608  public:
622  CoordDataReaderBase<Callback, Ordinal> (adder)
623  {}
624 
633  CoordDataReaderBase<Callback, Ordinal> (null)
634  {}
635 
637  virtual ~CoordPatternReader() {};
638 
639  protected:
640  bool
641  readLine (const std::string& theLine,
642  const size_t lineNumber,
643  const bool tolerant)
644  {
645  Ordinal rowIndex;
646  Ordinal colIndex;
647  const bool localSuccess =
648  readPatternLine (theLine, rowIndex, colIndex, lineNumber, tolerant);
649  if (localSuccess) {
650  // Now that we've read in the (i, j) pair successfully, we
651  // can add the entry to the sparse graph.
652  (*(this->adder_)) (rowIndex, colIndex);
653  }
654  return localSuccess;
655  }
656  };
657 
658  } // namespace MatrixMarket
659 } // namespace Teuchos
660 
661 #endif // __Teuchos_MatrixMarket_CoordDataReader_hpp
Reference-counted pointer class and non-member templated function implementations.
Defines basic traits for the scalar field type.
Common functionality of a coordinate-format sparse matrix or graph data reader.
virtual ~CoordDataReaderBase()
Virtual destructor for safety and happy compilers.
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.
Teuchos::RCP< Callback > adder_
Closure that knows how to add entries to the sparse graph or matrix.
CoordDataReaderBase(const Teuchos::RCP< Callback > &adder)
Constructor with "adder" argument.
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.
std::pair< Teuchos::Tuple< Ordinal, 3 >, bool > readDimensions(std::istream &in, size_t &lineNumber, const bool tolerant=false)
Read (numRows, numCols, numNonzeros).
void setAdder(const Teuchos::RCP< Callback > &adder)
Set the Adder object.
Coordinate-format sparse matrix data reader.
CoordDataReader()
No-argument constructor.
virtual ~CoordDataReader()
Virtual destructor for safety and happy compilers.
CoordDataReader(const Teuchos::RCP< Callback > &adder)
Constructor with "adder" argument.
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 "adder" argument.
virtual ~CoordPatternReader()
Virtual destructor for safety and happy compilers.
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.
Statically sized simple array (tuple) class.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Matrix Market file utilities.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
This structure defines some basic traits for a scalar field type.