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