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 // 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_generic_hpp
11 #define __Teuchos_MatrixMarket_generic_hpp
12 
13 #include "Teuchos_ConfigDefs.hpp"
14 #ifdef HAVE_TEUCHOS_COMPLEX
15 # include <complex>
16 #endif // HAVE_TEUCHOS_COMPLEX
17 #include <iostream>
18 #include <sstream>
19 #include <stdexcept>
20 #include <type_traits>
21 #include <vector>
22 
23 namespace Teuchos {
24  namespace MatrixMarket {
25 
31  int maxLineLength();
32 
61  TEUCHOSNUMERICS_LIB_DLL_EXPORT bool
62  checkCommentLine (const std::string& line,
63  size_t& start,
64  size_t& size,
65  const size_t lineNumber,
66  const bool tolerant,
67  const bool maybeBannerLine = false);
68 
102  template<class Ordinal>
103  bool
104  readPatternData (std::istream& istr,
105  Ordinal& rowIndex,
106  Ordinal& colIndex,
107  const size_t lineNumber,
108  const bool tolerant)
109  {
110  Ordinal the_rowIndex, the_colIndex;
111 
112  if (istr.eof() || istr.fail())
113  {
114  if (tolerant)
115  return false;
116  else
117  {
118  std::ostringstream os;
119  os << "Unable to read any data from line " << lineNumber << " of input";
120  throw std::invalid_argument(os.str());
121  }
122  }
123  istr >> the_rowIndex;
124  if (istr.fail())
125  {
126  if (tolerant)
127  return false;
128  else
129  {
130  std::ostringstream os;
131  os << "Failed to get row index from line " << lineNumber << " of input";
132  throw std::invalid_argument(os.str());
133  }
134  }
135  else if (istr.eof())
136  {
137  if (tolerant)
138  return false;
139  else
140  {
141  std::ostringstream os;
142  os << "No more data after row index on line " << lineNumber << " of input";
143  throw std::invalid_argument(os.str());
144  }
145  }
146  istr >> the_colIndex;
147  if (istr.fail())
148  {
149  if (tolerant)
150  return false;
151  else
152  {
153  std::ostringstream os;
154  os << "Failed to get column index from line " << lineNumber << " of input";
155  throw std::invalid_argument(os.str());
156  }
157  }
158  rowIndex = the_rowIndex;
159  colIndex = the_colIndex;
160  return true;
161  }
162 
201  template<class Ordinal, class Real>
202  bool
203  readRealData (std::istream& istr,
204  Ordinal& rowIndex,
205  Ordinal& colIndex,
206  Real& realValue,
207  const size_t lineNumber,
208  const bool tolerant)
209  {
210  Real the_realValue;
211  if (! readPatternData (istr, rowIndex, colIndex, lineNumber, tolerant))
212  {
213  if (tolerant)
214  return false;
215  else
216  {
217  std::ostringstream os;
218  os << "Failed to read pattern data from line " << lineNumber << " of input";
219  throw std::invalid_argument(os.str());
220  }
221  }
222  if (istr.eof())
223  {
224  if (tolerant)
225  return false;
226  else
227  {
228  std::ostringstream os;
229  os << "No more data after pattern data on line " << lineNumber << " of input";
230  throw std::invalid_argument(os.str());
231  }
232  }
233  {
234  if (std::is_same<Real, float>::value) {
235  double dblVal {};
236  istr >> dblVal;
237  the_realValue = static_cast<Real> (dblVal);
238  }
239  else {
240  istr >> the_realValue;
241  }
242  }
243  if (istr.fail())
244  {
245  if (tolerant)
246  return false;
247  else
248  {
249  std::ostringstream os;
250  os << "Failed to get real value from line " << lineNumber << " of input";
251  throw std::invalid_argument(os.str());
252  }
253  }
254  realValue = the_realValue;
255  return true;
256  }
257 
258 #ifdef HAVE_TEUCHOS_COMPLEX
259 
301  template<class Ordinal, class Real>
302  bool
303  readComplexData (std::istream& istr,
304  Ordinal& rowIndex,
305  Ordinal& colIndex,
306  Real& realPart,
307  Real& imagPart,
308  const size_t lineNumber,
309  const bool tolerant)
310  {
311  Real the_realPart, the_imagPart;
312  if (! readRealData (istr, rowIndex, colIndex, the_realPart, lineNumber, tolerant))
313  {
314  if (tolerant)
315  return false;
316  else
317  {
318  std::ostringstream os;
319  os << "Failed to read pattern data and/or real value from line "
320  << lineNumber << " of input";
321  throw std::invalid_argument(os.str());
322  }
323  }
324  if (istr.eof())
325  {
326  if (tolerant)
327  return false;
328  else
329  {
330  std::ostringstream os;
331  os << "No more data after real value on line "
332  << lineNumber << " of input";
333  throw std::invalid_argument(os.str());
334  }
335  }
336  istr >> the_imagPart;
337  if (istr.fail())
338  {
339  if (tolerant)
340  return false;
341  else
342  {
343  std::ostringstream os;
344  os << "Failed to get imaginary value from line "
345  << lineNumber << " of input";
346  throw std::invalid_argument(os.str());
347  }
348  }
349  realPart = the_realPart;
350  imagPart = the_imagPart;
351  return true;
352  }
353 #endif // HAVE_TEUCHOS_COMPLEX
354 
355  template<class Ordinal>
356  bool
357  readPatternLine (const std::string& line, // only the data-containing part
358  Ordinal& rowIndex,
359  Ordinal& colIndex,
360  const size_t lineNumber,
361  const bool tolerant)
362  {
363  // The part of the line that contains data
364  std::istringstream istr (line);
365  return readPatternData (istr, rowIndex, colIndex, lineNumber, tolerant);
366  }
367 
368  template<class Ordinal, class Real>
369  bool
370  readRealLine (const std::string& line,
371  Ordinal& rowIndex,
372  Ordinal& colIndex,
373  Real& realValue,
374  const size_t lineNumber,
375  const bool tolerant)
376  {
377  size_t start, size;
378  if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
379  return false; // It's a comment line
380  }
381  // If it's an empty line, checkCommentLine() will throw an
382  // exception if non-tolerant parsing is being performed, so
383  // we need only return false otherwise.
384  if (size == 0) {
385  if (! tolerant) {
386  throw std::logic_error("Should never get here! checkCommentLine() "
387  "is supposed to catch empty lines.");
388  }
389  else {
390  return false;
391  }
392  }
393  // The part of the line that contains data
394  std::istringstream istr (line.substr (start, size));
395  return readRealData (istr, rowIndex, colIndex, realValue, lineNumber, tolerant);
396  }
397 
398 #ifdef HAVE_TEUCHOS_COMPLEX
399  template<class Ordinal, class Real>
400  bool
401  readComplexLine (const std::string& line,
402  Ordinal& rowIndex,
403  Ordinal& colIndex,
404  Real& realPart,
405  Real& imagPart,
406  const size_t lineNumber,
407  const bool tolerant)
408  {
409  size_t start, end;
410  if (checkCommentLine (line, start, end, lineNumber, tolerant))
411  return false; // It's a comment line
412  // If it's an empty line, checkCommentLine() will throw an
413  // exception if non-tolerant parsing is being performed, so
414  // we need only return false otherwise.
415  if (end == 0)
416  {
417  if (tolerant)
418  throw std::logic_error("Should never get here! checkCommentLine() "
419  "is supposed to catch empty lines.");
420  else
421  return false;
422  }
423  // The part of the line that contains data
424  std::istringstream istr (line.substr (start, end));
425  // Read the data
426  Real the_realPart, the_imagPart;
427  const bool success =
428  readComplexData (istr, rowIndex, colIndex, the_realPart, the_imagPart,
429  lineNumber, tolerant);
430  if (success)
431  {
432  realPart = the_realPart;
433  imagPart = the_imagPart;
434  }
435  return success;
436  }
437 #endif // HAVE_TEUCHOS_COMPLEX
438 
439  template<class Ordinal, class PatternCallback>
440  std::pair<bool, std::vector<size_t> >
441  readPatternCoordinateData (std::istream& in,
442  PatternCallback add,
443  const size_t startingLineNumber,
444  const bool tolerant)
445  {
446  std::string line;
447  size_t lineNumber = startingLineNumber;
448  bool anySucceeded = false;
449  bool allSucceeded = true;
450  std::vector<size_t> badLineNumbers;
451  while (getline (in, line)) {
452  size_t start, size;
453  if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
454  continue; // it's a comment line
455  }
456  const std::string theLine = line.substr (start, size);
457 
458  Ordinal rowIndex, colIndex;
459  const bool localSuccess =
460  readPatternLine (theLine, rowIndex, colIndex,
461  lineNumber++, tolerant);
462  anySucceeded = anySucceeded || localSuccess;
463  allSucceeded = allSucceeded && localSuccess;
464  if (! localSuccess) {
465  badLineNumbers.push_back (lineNumber);
466  }
467  else {
468  // Add the newly read entry to the sparse graph.
469  add(rowIndex, colIndex);
470  }
471  }
472  if (lineNumber == startingLineNumber) {
473  anySucceeded = true; // Trivially true
474  }
475 
476  return std::make_pair (allSucceeded, badLineNumbers);
477  }
478 
479 
480  template<class Ordinal>
481  bool
482  readCoordinateDimensions (std::istream& in,
483  Ordinal& numRows,
484  Ordinal& numCols,
485  Ordinal& numNonzeros,
486  size_t& lineNumber,
487  const bool tolerant)
488  {
489  using std::endl;
490 
491  Ordinal the_numRows, the_numCols, the_numNonzeros;
492  std::string line;
493 
494  // Keep reading lines from the input stream until we find a
495  // non-comment line, or until we run out of lines. The latter
496  // is an error, since every "coordinate" format Matrix Market
497  // file must have a dimensions line after the banner (even if
498  // the matrix has zero rows or columns, or zero entries).
499  bool commentLine = true;
500  while (commentLine)
501  {
502  // Is it even valid to read from the input stream?
503  if (in.eof () || in.fail ()) {
504  if (tolerant) {
505  return false;
506  }
507  else {
508  std::ostringstream os;
509  os << "Unable to get coordinate dimensions line (at all) "
510  "from (line " << lineNumber << ") of input stream; the "
511  "input stream claims that it is at \"end-of-file\" or has "
512  "an otherwise \"fail\"ed state.";
513  throw std::invalid_argument(os.str());
514  }
515  }
516  // Try to get the next line from the input stream.
517  if (! getline (in, line)) {
518  if (tolerant) {
519  return false;
520  }
521  else {
522  std::ostringstream os;
523  os << "Failed to read coordinate dimensions line (at all) "
524  "from (line " << lineNumber << " from input stream. The "
525  "line should contain the coordinate matrix dimensions in "
526  << " the form \"<numRows> <numCols> <numNonzeros>\".";
527  throw std::invalid_argument(os.str());
528  }
529  }
530  // Is the current line a comment line? Ignore start and
531  // size; they are only useful for reading the actual matrix
532  // entries. (We could use them here as an optimization, but
533  // we've chosen not to.)
534  size_t start = 0, size = 0;
535  commentLine = checkCommentLine (line, start, size,
536  lineNumber, tolerant);
537  // This ensures that any error messages in this file are
538  // correct.
539  if (commentLine) {
540  ++lineNumber;
541  }
542  }
543 
544  // The current line is now not a comment line.
545  // Try to read the coordinate dimensions from it.
546  std::istringstream istr (line);
547  if (istr.eof () || istr.fail ()) {
548  if (tolerant) {
549  return false;
550  }
551  else {
552  std::ostringstream os;
553  os << "Unable to read any coordinate dimensions data from line "
554  << lineNumber << " of input stream. Offending line:" << endl
555  << line;
556  throw std::invalid_argument(os.str());
557  }
558  }
559  istr >> the_numRows;
560  if (istr.fail ()) {
561  if (tolerant) {
562  return false;
563  }
564  else {
565  std::ostringstream os;
566  os << "Failed to get number of rows from the coordinate "
567  "dimensions line (line " << lineNumber << " of input stream)."
568  " Offending line:" << endl << line;
569  throw std::invalid_argument(os.str());
570  }
571  }
572  else if (istr.eof ()) {
573  if (tolerant) {
574  return false;
575  }
576  else {
577  std::ostringstream os;
578  os << "No more data after number of rows, in the coordinate "
579  "dimensions line (line " << lineNumber << " of input stream)."
580  " Offending line:" << endl << line;
581  throw std::invalid_argument(os.str());
582  }
583  }
584  istr >> the_numCols;
585  if (istr.fail ()) {
586  if (tolerant) {
587  return false;
588  }
589  else {
590  std::ostringstream os;
591  os << "Failed to get number of columns from the coordinate "
592  "dimensions line (line " << lineNumber << " of input stream)."
593  " Offending line:" << endl << line;
594  throw std::invalid_argument(os.str());
595  }
596  }
597  else if (istr.eof ()) {
598  if (tolerant) {
599  return false;
600  }
601  else {
602  std::ostringstream os;
603  os << "No more data after number of columns, in the coordinate "
604  "dimensions line (line " << lineNumber << " of input stream)."
605  " Offending line:" << endl << line;
606  throw std::invalid_argument (os.str ());
607  }
608  }
609  istr >> the_numNonzeros;
610  if (istr.fail ()) {
611  if (tolerant) {
612  return false;
613  }
614  else {
615  std::ostringstream os;
616  os << "Failed to get number of nonzeros from the coordinate "
617  "dimensions line (line " << lineNumber << " of input stream)."
618  " Offending line:" << endl << line;
619  throw std::invalid_argument (os.str ());
620  }
621  }
622  numRows = the_numRows;
623  numCols = the_numCols;
624  numNonzeros = the_numNonzeros;
625  // This function only increments the line number when it reads a
626  // comment line successfully, or when it reads all the
627  // coordinate dimensions successfully.
628  ++lineNumber;
629  return true;
630  }
631 
632  } // namespace MatrixMarket
633 } // namespace Teuchos
634 
635 #endif // __Teuchos_MatrixMarket_generic_hpp
Teuchos header file which uses auto-configuration information to include necessary C++ headers...