Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_MatrixMarket_generic.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_generic_hpp
43 #define __Teuchos_MatrixMarket_generic_hpp
44 
45 #include "Teuchos_ConfigDefs.hpp"
46 #ifdef HAVE_TEUCHOS_COMPLEX
47 # include <complex>
48 #endif // HAVE_TEUCHOS_COMPLEX
49 #include <iostream>
50 #include <sstream>
51 #include <stdexcept>
52 #include <type_traits>
53 #include <vector>
54 
55 namespace Teuchos {
56  namespace MatrixMarket {
57 
63  int maxLineLength();
64 
93  TEUCHOSNUMERICS_LIB_DLL_EXPORT bool
94  checkCommentLine (const std::string& line,
95  size_t& start,
96  size_t& size,
97  const size_t lineNumber,
98  const bool tolerant,
99  const bool maybeBannerLine = false);
100 
134  template<class Ordinal>
135  bool
136  readPatternData (std::istream& istr,
137  Ordinal& rowIndex,
138  Ordinal& colIndex,
139  const size_t lineNumber,
140  const bool tolerant)
141  {
142  Ordinal the_rowIndex, the_colIndex;
143 
144  if (istr.eof() || istr.fail())
145  {
146  if (tolerant)
147  return false;
148  else
149  {
150  std::ostringstream os;
151  os << "Unable to read any data from line " << lineNumber << " of input";
152  throw std::invalid_argument(os.str());
153  }
154  }
155  istr >> the_rowIndex;
156  if (istr.fail())
157  {
158  if (tolerant)
159  return false;
160  else
161  {
162  std::ostringstream os;
163  os << "Failed to get row index from line " << lineNumber << " of input";
164  throw std::invalid_argument(os.str());
165  }
166  }
167  else if (istr.eof())
168  {
169  if (tolerant)
170  return false;
171  else
172  {
173  std::ostringstream os;
174  os << "No more data after row index on line " << lineNumber << " of input";
175  throw std::invalid_argument(os.str());
176  }
177  }
178  istr >> the_colIndex;
179  if (istr.fail())
180  {
181  if (tolerant)
182  return false;
183  else
184  {
185  std::ostringstream os;
186  os << "Failed to get column index from line " << lineNumber << " of input";
187  throw std::invalid_argument(os.str());
188  }
189  }
190  rowIndex = the_rowIndex;
191  colIndex = the_colIndex;
192  return true;
193  }
194 
233  template<class Ordinal, class Real>
234  bool
235  readRealData (std::istream& istr,
236  Ordinal& rowIndex,
237  Ordinal& colIndex,
238  Real& realValue,
239  const size_t lineNumber,
240  const bool tolerant)
241  {
242  Real the_realValue;
243  if (! readPatternData (istr, rowIndex, colIndex, lineNumber, tolerant))
244  {
245  if (tolerant)
246  return false;
247  else
248  {
249  std::ostringstream os;
250  os << "Failed to read pattern data from line " << lineNumber << " of input";
251  throw std::invalid_argument(os.str());
252  }
253  }
254  if (istr.eof())
255  {
256  if (tolerant)
257  return false;
258  else
259  {
260  std::ostringstream os;
261  os << "No more data after pattern data on line " << lineNumber << " of input";
262  throw std::invalid_argument(os.str());
263  }
264  }
265  {
266  if (std::is_same<Real, float>::value) {
267  double dblVal {};
268  istr >> dblVal;
269  the_realValue = static_cast<Real> (dblVal);
270  }
271  else {
272  istr >> the_realValue;
273  }
274  }
275  if (istr.fail())
276  {
277  if (tolerant)
278  return false;
279  else
280  {
281  std::ostringstream os;
282  os << "Failed to get real value from line " << lineNumber << " of input";
283  throw std::invalid_argument(os.str());
284  }
285  }
286  realValue = the_realValue;
287  return true;
288  }
289 
290 #ifdef HAVE_TEUCHOS_COMPLEX
291 
333  template<class Ordinal, class Real>
334  bool
335  readComplexData (std::istream& istr,
336  Ordinal& rowIndex,
337  Ordinal& colIndex,
338  Real& realPart,
339  Real& imagPart,
340  const size_t lineNumber,
341  const bool tolerant)
342  {
343  Real the_realPart, the_imagPart;
344  if (! readRealData (istr, rowIndex, colIndex, the_realPart, lineNumber, tolerant))
345  {
346  if (tolerant)
347  return false;
348  else
349  {
350  std::ostringstream os;
351  os << "Failed to read pattern data and/or real value from line "
352  << lineNumber << " of input";
353  throw std::invalid_argument(os.str());
354  }
355  }
356  if (istr.eof())
357  {
358  if (tolerant)
359  return false;
360  else
361  {
362  std::ostringstream os;
363  os << "No more data after real value on line "
364  << lineNumber << " of input";
365  throw std::invalid_argument(os.str());
366  }
367  }
368  istr >> the_imagPart;
369  if (istr.fail())
370  {
371  if (tolerant)
372  return false;
373  else
374  {
375  std::ostringstream os;
376  os << "Failed to get imaginary value from line "
377  << lineNumber << " of input";
378  throw std::invalid_argument(os.str());
379  }
380  }
381  realPart = the_realPart;
382  imagPart = the_imagPart;
383  return true;
384  }
385 #endif // HAVE_TEUCHOS_COMPLEX
386 
387  template<class Ordinal>
388  bool
389  readPatternLine (const std::string& line, // only the data-containing part
390  Ordinal& rowIndex,
391  Ordinal& colIndex,
392  const size_t lineNumber,
393  const bool tolerant)
394  {
395  // The part of the line that contains data
396  std::istringstream istr (line);
397  return readPatternData (istr, rowIndex, colIndex, lineNumber, tolerant);
398  }
399 
400  template<class Ordinal, class Real>
401  bool
402  readRealLine (const std::string& line,
403  Ordinal& rowIndex,
404  Ordinal& colIndex,
405  Real& realValue,
406  const size_t lineNumber,
407  const bool tolerant)
408  {
409  size_t start, size;
410  if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
411  return false; // It's a comment line
412  }
413  // If it's an empty line, checkCommentLine() will throw an
414  // exception if non-tolerant parsing is being performed, so
415  // we need only return false otherwise.
416  if (size == 0) {
417  if (! tolerant) {
418  throw std::logic_error("Should never get here! checkCommentLine() "
419  "is supposed to catch empty lines.");
420  }
421  else {
422  return false;
423  }
424  }
425  // The part of the line that contains data
426  std::istringstream istr (line.substr (start, size));
427  return readRealData (istr, rowIndex, colIndex, realValue, lineNumber, tolerant);
428  }
429 
430 #ifdef HAVE_TEUCHOS_COMPLEX
431  template<class Ordinal, class Real>
432  bool
433  readComplexLine (const std::string& line,
434  Ordinal& rowIndex,
435  Ordinal& colIndex,
436  Real& realPart,
437  Real& imagPart,
438  const size_t lineNumber,
439  const bool tolerant)
440  {
441  size_t start, end;
442  if (checkCommentLine (line, start, end, lineNumber, tolerant))
443  return false; // It's a comment line
444  // If it's an empty line, checkCommentLine() will throw an
445  // exception if non-tolerant parsing is being performed, so
446  // we need only return false otherwise.
447  if (end == 0)
448  {
449  if (tolerant)
450  throw std::logic_error("Should never get here! checkCommentLine() "
451  "is supposed to catch empty lines.");
452  else
453  return false;
454  }
455  // The part of the line that contains data
456  std::istringstream istr (line.substr (start, end));
457  // Read the data
458  Real the_realPart, the_imagPart;
459  const bool success =
460  readComplexData (istr, rowIndex, colIndex, the_realPart, the_imagPart,
461  lineNumber, tolerant);
462  if (success)
463  {
464  realPart = the_realPart;
465  imagPart = the_imagPart;
466  }
467  return success;
468  }
469 #endif // HAVE_TEUCHOS_COMPLEX
470 
471  template<class Ordinal, class PatternCallback>
472  std::pair<bool, std::vector<size_t> >
473  readPatternCoordinateData (std::istream& in,
474  PatternCallback add,
475  const size_t startingLineNumber,
476  const bool tolerant)
477  {
478  std::string line;
479  size_t lineNumber = startingLineNumber;
480  bool anySucceeded = false;
481  bool allSucceeded = true;
482  std::vector<size_t> badLineNumbers;
483  while (getline (in, line)) {
484  size_t start, size;
485  if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
486  continue; // it's a comment line
487  }
488  const std::string theLine = line.substr (start, size);
489 
490  Ordinal rowIndex, colIndex;
491  const bool localSuccess =
492  readPatternLine (theLine, rowIndex, colIndex,
493  lineNumber++, tolerant);
494  anySucceeded = anySucceeded || localSuccess;
495  allSucceeded = allSucceeded && localSuccess;
496  if (! localSuccess) {
497  badLineNumbers.push_back (lineNumber);
498  }
499  else {
500  // Add the newly read entry to the sparse graph.
501  add(rowIndex, colIndex);
502  }
503  }
504  if (lineNumber == startingLineNumber) {
505  anySucceeded = true; // Trivially true
506  }
507 
508  return std::make_pair (allSucceeded, badLineNumbers);
509  }
510 
511 
512  template<class Ordinal>
513  bool
514  readCoordinateDimensions (std::istream& in,
515  Ordinal& numRows,
516  Ordinal& numCols,
517  Ordinal& numNonzeros,
518  size_t& lineNumber,
519  const bool tolerant)
520  {
521  using std::endl;
522 
523  Ordinal the_numRows, the_numCols, the_numNonzeros;
524  std::string line;
525 
526  // Keep reading lines from the input stream until we find a
527  // non-comment line, or until we run out of lines. The latter
528  // is an error, since every "coordinate" format Matrix Market
529  // file must have a dimensions line after the banner (even if
530  // the matrix has zero rows or columns, or zero entries).
531  bool commentLine = true;
532  while (commentLine)
533  {
534  // Is it even valid to read from the input stream?
535  if (in.eof () || in.fail ()) {
536  if (tolerant) {
537  return false;
538  }
539  else {
540  std::ostringstream os;
541  os << "Unable to get coordinate dimensions line (at all) "
542  "from (line " << lineNumber << ") of input stream; the "
543  "input stream claims that it is at \"end-of-file\" or has "
544  "an otherwise \"fail\"ed state.";
545  throw std::invalid_argument(os.str());
546  }
547  }
548  // Try to get the next line from the input stream.
549  if (! getline (in, line)) {
550  if (tolerant) {
551  return false;
552  }
553  else {
554  std::ostringstream os;
555  os << "Failed to read coordinate dimensions line (at all) "
556  "from (line " << lineNumber << " from input stream. The "
557  "line should contain the coordinate matrix dimensions in "
558  << " the form \"<numRows> <numCols> <numNonzeros>\".";
559  throw std::invalid_argument(os.str());
560  }
561  }
562  // Is the current line a comment line? Ignore start and
563  // size; they are only useful for reading the actual matrix
564  // entries. (We could use them here as an optimization, but
565  // we've chosen not to.)
566  size_t start = 0, size = 0;
567  commentLine = checkCommentLine (line, start, size,
568  lineNumber, tolerant);
569  // This ensures that any error messages in this file are
570  // correct.
571  if (commentLine) {
572  ++lineNumber;
573  }
574  }
575 
576  // The current line is now not a comment line.
577  // Try to read the coordinate dimensions from it.
578  std::istringstream istr (line);
579  if (istr.eof () || istr.fail ()) {
580  if (tolerant) {
581  return false;
582  }
583  else {
584  std::ostringstream os;
585  os << "Unable to read any coordinate dimensions data from line "
586  << lineNumber << " of input stream. Offending line:" << endl
587  << line;
588  throw std::invalid_argument(os.str());
589  }
590  }
591  istr >> the_numRows;
592  if (istr.fail ()) {
593  if (tolerant) {
594  return false;
595  }
596  else {
597  std::ostringstream os;
598  os << "Failed to get number of rows from the coordinate "
599  "dimensions line (line " << lineNumber << " of input stream)."
600  " Offending line:" << endl << line;
601  throw std::invalid_argument(os.str());
602  }
603  }
604  else if (istr.eof ()) {
605  if (tolerant) {
606  return false;
607  }
608  else {
609  std::ostringstream os;
610  os << "No more data after number of rows, in the coordinate "
611  "dimensions line (line " << lineNumber << " of input stream)."
612  " Offending line:" << endl << line;
613  throw std::invalid_argument(os.str());
614  }
615  }
616  istr >> the_numCols;
617  if (istr.fail ()) {
618  if (tolerant) {
619  return false;
620  }
621  else {
622  std::ostringstream os;
623  os << "Failed to get number of columns from the coordinate "
624  "dimensions line (line " << lineNumber << " of input stream)."
625  " Offending line:" << endl << line;
626  throw std::invalid_argument(os.str());
627  }
628  }
629  else if (istr.eof ()) {
630  if (tolerant) {
631  return false;
632  }
633  else {
634  std::ostringstream os;
635  os << "No more data after number of columns, in the coordinate "
636  "dimensions line (line " << lineNumber << " of input stream)."
637  " Offending line:" << endl << line;
638  throw std::invalid_argument (os.str ());
639  }
640  }
641  istr >> the_numNonzeros;
642  if (istr.fail ()) {
643  if (tolerant) {
644  return false;
645  }
646  else {
647  std::ostringstream os;
648  os << "Failed to get number of nonzeros from the coordinate "
649  "dimensions line (line " << lineNumber << " of input stream)."
650  " Offending line:" << endl << line;
651  throw std::invalid_argument (os.str ());
652  }
653  }
654  numRows = the_numRows;
655  numCols = the_numCols;
656  numNonzeros = the_numNonzeros;
657  // This function only increments the line number when it reads a
658  // comment line successfully, or when it reads all the
659  // coordinate dimensions successfully.
660  ++lineNumber;
661  return true;
662  }
663 
664  } // namespace MatrixMarket
665 } // namespace Teuchos
666 
667 #endif // __Teuchos_MatrixMarket_generic_hpp
Teuchos header file which uses auto-configuration information to include necessary C++ headers...