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  size_t validDataLines = 0;
484  while (getline (in, line)) {
485  size_t start, size;
486  if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
487  continue; // it's a comment line
488  }
489  const std::string theLine = line.substr (start, size);
490 
491  Ordinal rowIndex, colIndex;
492  const bool localSuccess =
493  readPatternLine (theLine, rowIndex, colIndex,
494  lineNumber++, tolerant);
495  anySucceeded = anySucceeded || localSuccess;
496  allSucceeded = allSucceeded && localSuccess;
497  if (! localSuccess) {
498  badLineNumbers.push_back (lineNumber);
499  }
500  else {
501  // Add the newly read entry to the sparse graph.
502  add (rowIndex, colIndex);
503  ++validDataLines;
504  }
505  }
506  if (lineNumber == startingLineNumber) {
507  anySucceeded = true; // Trivially true
508  }
509 
510  return std::make_pair (allSucceeded, badLineNumbers);
511  }
512 
513 
514  template<class Ordinal>
515  bool
516  readCoordinateDimensions (std::istream& in,
517  Ordinal& numRows,
518  Ordinal& numCols,
519  Ordinal& numNonzeros,
520  size_t& lineNumber,
521  const bool tolerant)
522  {
523  using std::endl;
524 
525  Ordinal the_numRows, the_numCols, the_numNonzeros;
526  std::string line;
527 
528  // Keep reading lines from the input stream until we find a
529  // non-comment line, or until we run out of lines. The latter
530  // is an error, since every "coordinate" format Matrix Market
531  // file must have a dimensions line after the banner (even if
532  // the matrix has zero rows or columns, or zero entries).
533  bool commentLine = true;
534  while (commentLine)
535  {
536  // Is it even valid to read from the input stream?
537  if (in.eof () || in.fail ()) {
538  if (tolerant) {
539  return false;
540  }
541  else {
542  std::ostringstream os;
543  os << "Unable to get coordinate dimensions line (at all) "
544  "from (line " << lineNumber << ") of input stream; the "
545  "input stream claims that it is at \"end-of-file\" or has "
546  "an otherwise \"fail\"ed state.";
547  throw std::invalid_argument(os.str());
548  }
549  }
550  // Try to get the next line from the input stream.
551  if (! getline (in, line)) {
552  if (tolerant) {
553  return false;
554  }
555  else {
556  std::ostringstream os;
557  os << "Failed to read coordinate dimensions line (at all) "
558  "from (line " << lineNumber << " from input stream. The "
559  "line should contain the coordinate matrix dimensions in "
560  << " the form \"<numRows> <numCols> <numNonzeros>\".";
561  throw std::invalid_argument(os.str());
562  }
563  }
564  // Is the current line a comment line? Ignore start and
565  // size; they are only useful for reading the actual matrix
566  // entries. (We could use them here as an optimization, but
567  // we've chosen not to.)
568  size_t start = 0, size = 0;
569  commentLine = checkCommentLine (line, start, size,
570  lineNumber, tolerant);
571  // This ensures that any error messages in this file are
572  // correct.
573  if (commentLine) {
574  ++lineNumber;
575  }
576  }
577 
578  // The current line is now not a comment line.
579  // Try to read the coordinate dimensions from it.
580  std::istringstream istr (line);
581  if (istr.eof () || istr.fail ()) {
582  if (tolerant) {
583  return false;
584  }
585  else {
586  std::ostringstream os;
587  os << "Unable to read any coordinate dimensions data from line "
588  << lineNumber << " of input stream. Offending line:" << endl
589  << line;
590  throw std::invalid_argument(os.str());
591  }
592  }
593  istr >> the_numRows;
594  if (istr.fail ()) {
595  if (tolerant) {
596  return false;
597  }
598  else {
599  std::ostringstream os;
600  os << "Failed to get number of rows from the coordinate "
601  "dimensions line (line " << lineNumber << " of input stream)."
602  " Offending line:" << endl << line;
603  throw std::invalid_argument(os.str());
604  }
605  }
606  else if (istr.eof ()) {
607  if (tolerant) {
608  return false;
609  }
610  else {
611  std::ostringstream os;
612  os << "No more data after number of rows, in the coordinate "
613  "dimensions line (line " << lineNumber << " of input stream)."
614  " Offending line:" << endl << line;
615  throw std::invalid_argument(os.str());
616  }
617  }
618  istr >> the_numCols;
619  if (istr.fail ()) {
620  if (tolerant) {
621  return false;
622  }
623  else {
624  std::ostringstream os;
625  os << "Failed to get number of columns from the coordinate "
626  "dimensions line (line " << lineNumber << " of input stream)."
627  " Offending line:" << endl << line;
628  throw std::invalid_argument(os.str());
629  }
630  }
631  else if (istr.eof ()) {
632  if (tolerant) {
633  return false;
634  }
635  else {
636  std::ostringstream os;
637  os << "No more data after number of columns, in the coordinate "
638  "dimensions line (line " << lineNumber << " of input stream)."
639  " Offending line:" << endl << line;
640  throw std::invalid_argument (os.str ());
641  }
642  }
643  istr >> the_numNonzeros;
644  if (istr.fail ()) {
645  if (tolerant) {
646  return false;
647  }
648  else {
649  std::ostringstream os;
650  os << "Failed to get number of nonzeros from the coordinate "
651  "dimensions line (line " << lineNumber << " of input stream)."
652  " Offending line:" << endl << line;
653  throw std::invalid_argument (os.str ());
654  }
655  }
656  numRows = the_numRows;
657  numCols = the_numCols;
658  numNonzeros = the_numNonzeros;
659  // This function only increments the line number when it reads a
660  // comment line successfully, or when it reads all the
661  // coordinate dimensions successfully.
662  ++lineNumber;
663  return true;
664  }
665 
666  } // namespace MatrixMarket
667 } // namespace Teuchos
668 
669 #endif // __Teuchos_MatrixMarket_generic_hpp
Teuchos header file which uses auto-configuration information to include necessary C++ headers...