Tpetra Matrix/Vector Services Version of the Day
MatrixMarket_generic.hpp
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //          Tpetra: Templated Linear Algebra Services Package
00005 //                 Copyright (2008) Sandia Corporation
00006 // 
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 // 
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00038 // 
00039 // ************************************************************************
00040 // @HEADER
00041 
00042 #ifndef __MatrixMarket_generic_hpp
00043 #define __MatrixMarket_generic_hpp
00044 
00045 #include "Tpetra_ConfigDefs.hpp"
00046 #ifdef HAVE_TEUCHOS_COMPLEX
00047 #  include <complex>
00048 #endif // HAVE_TEUCHOS_COMPLEX
00049 #include <iostream>
00050 #include <sstream>
00051 #include <stdexcept>
00052 
00053 namespace Tpetra {
00054   namespace MatrixMarket {
00055 
00061     int maxLineLength();
00062 
00071     bool 
00072     checkCommentLine (const std::string& line, 
00073           size_t& start, 
00074           size_t& size,
00075           const size_t lineNumber,
00076           const bool tolerant);
00077 
00111     template<class Ordinal>
00112     bool
00113     readPatternData (std::istream& istr, 
00114          Ordinal& rowIndex, 
00115          Ordinal& colIndex, 
00116          const size_t lineNumber,
00117          const bool tolerant)
00118     {
00119       Ordinal the_rowIndex, the_colIndex;
00120 
00121       if (istr.eof() || istr.fail())
00122   {
00123     if (tolerant)
00124       return false;
00125     else
00126       {
00127         std::ostringstream os;
00128         os << "Unable to read any data from line " << lineNumber << " of input";
00129         throw std::invalid_argument(os.str());
00130       }
00131   }
00132       istr >> the_rowIndex;
00133       if (istr.fail())
00134   {
00135     if (tolerant)
00136       return false;
00137     else
00138       {
00139         std::ostringstream os;
00140         os << "Failed to get row index from line " << lineNumber << " of input";
00141         throw std::invalid_argument(os.str());
00142       }
00143   }
00144       else if (istr.eof())
00145   {
00146     if (tolerant)
00147       return false;
00148     else
00149       {
00150         std::ostringstream os;
00151         os << "No more data after row index on line " << lineNumber << " of input";
00152         throw std::invalid_argument(os.str());
00153       }
00154   }
00155       istr >> the_colIndex;
00156       if (istr.fail())
00157   {
00158     if (tolerant)
00159       return false;
00160     else
00161       {
00162         std::ostringstream os;
00163         os << "Failed to get column index from line " << lineNumber << " of input";
00164         throw std::invalid_argument(os.str());
00165       }
00166   }
00167       rowIndex = the_rowIndex;
00168       colIndex = the_colIndex;
00169       return true;
00170     }
00171 
00210     template<class Ordinal, class Real>
00211     bool
00212     readRealData (std::istream& istr, 
00213       Ordinal& rowIndex, 
00214       Ordinal& colIndex, 
00215       Real& realValue, 
00216       const size_t lineNumber,
00217       const bool tolerant)
00218     {
00219       Real the_realValue;
00220       if (! readPatternData (istr, rowIndex, colIndex, lineNumber, tolerant))
00221   {
00222     if (tolerant) 
00223       return false;
00224     else
00225       {
00226         std::ostringstream os;
00227         os << "Failed to read pattern data from line " << lineNumber << " of input";
00228         throw std::invalid_argument(os.str());
00229       }
00230   }
00231       if (istr.eof())
00232   {
00233     if (tolerant)
00234       return false;
00235     else
00236       {
00237         std::ostringstream os;
00238         os << "No more data after pattern data on line " << lineNumber << " of input";
00239         throw std::invalid_argument(os.str());
00240       }
00241   }
00242       istr >> the_realValue;
00243       if (istr.fail())
00244   {
00245     if (tolerant)
00246       return false;
00247     else
00248       {
00249         std::ostringstream os;
00250         os << "Failed to get real value from line " << lineNumber << " of input";
00251         throw std::invalid_argument(os.str());
00252       }
00253   }
00254       realValue = the_realValue;
00255       return true;
00256     }
00257 
00258 #ifdef HAVE_TEUCHOS_COMPLEX
00259 
00301     template<class Ordinal, class Real>
00302     bool
00303     readComplexData (std::istream& istr, 
00304          Ordinal& rowIndex, 
00305          Ordinal& colIndex, 
00306          Real& realPart,
00307          Real& imagPart,
00308          const size_t lineNumber,
00309          const bool tolerant)
00310     {
00311       Real the_realPart, the_imagPart;
00312       if (! readRealData (istr, rowIndex, colIndex, the_realPart, lineNumber, tolerant))
00313   {
00314     if (tolerant) 
00315       return false;
00316     else
00317       {
00318         std::ostringstream os;
00319         os << "Failed to read pattern data and/or real value from line " 
00320      << lineNumber << " of input";
00321         throw std::invalid_argument(os.str());
00322       }
00323   }
00324       if (istr.eof())
00325   {
00326     if (tolerant)
00327       return false;
00328     else
00329       {
00330         std::ostringstream os;
00331         os << "No more data after real value on line " 
00332      << lineNumber << " of input";
00333         throw std::invalid_argument(os.str());
00334       }
00335   }
00336       istr >> the_imagPart;
00337       if (istr.fail())
00338   {
00339     if (tolerant)
00340       return false;
00341     else
00342       {
00343         std::ostringstream os;
00344         os << "Failed to get imaginary value from line " 
00345      << lineNumber << " of input";
00346         throw std::invalid_argument(os.str());
00347       }
00348   }
00349       realPart = the_realPart;
00350       imagPart = the_imagPart;
00351       return true;
00352     }
00353 #endif // HAVE_TEUCHOS_COMPLEX
00354 
00355     template<class Ordinal>
00356     bool
00357     readPatternLine (const std::string& line, // only the data-containing part
00358          Ordinal& rowIndex, 
00359          Ordinal& colIndex, 
00360          const size_t lineNumber,
00361          const bool tolerant)
00362     {
00363       // The part of the line that contains data
00364       std::istringstream istr (line);
00365       return readPatternData (istr, rowIndex, colIndex, lineNumber, tolerant);
00366     }
00367 
00368     template<class Ordinal, class Real>
00369     bool
00370     readRealLine (const std::string& line, 
00371       Ordinal& rowIndex, 
00372       Ordinal& colIndex, 
00373       Real& realValue, 
00374       const size_t lineNumber,
00375       const bool tolerant)
00376     {
00377       size_t start, size;
00378       if (checkCommentLine (line, start, size, lineNumber, tolerant)) 
00379   {
00380     // {
00381     //   using std::cerr;
00382     //   using std::endl;
00383     //   cerr << "Comment line: " << lineNumber << endl;
00384     // }
00385     return false; // It's a comment line
00386   }
00387       // If it's an empty line, checkCommentLine() will throw an
00388       // exception if non-tolerant parsing is being performed, so
00389       // we need only return false otherwise.
00390       if (size == 0) 
00391   {
00392     if (! tolerant)
00393       throw std::logic_error("Should never get here! checkCommentLine() "
00394            "is supposed to catch empty lines.");
00395     else
00396       {
00397         // {
00398         //   using std::cerr;
00399         //   using std::endl;
00400         //   cerr << "Empty line: " << lineNumber << endl;
00401         // }
00402         return false;
00403       }
00404   }
00405       // The part of the line that contains data
00406       std::istringstream istr (line.substr (start, size));
00407       return readRealData (istr, rowIndex, colIndex, realValue, lineNumber, tolerant);
00408     }
00409 
00410 #ifdef HAVE_TEUCHOS_COMPLEX
00411     template<class Ordinal, class Real>
00412     bool
00413     readComplexLine (const std::string& line, 
00414          Ordinal& rowIndex, 
00415          Ordinal& colIndex,
00416          Real& realPart,
00417          Real& imagPart,
00418          const size_t lineNumber,
00419          const bool tolerant)
00420     {
00421       size_t start, end;
00422       if (checkCommentLine (line, start, end, lineNumber, tolerant)) 
00423   return false; // It's a comment line
00424       // If it's an empty line, checkCommentLine() will throw an
00425       // exception if non-tolerant parsing is being performed, so
00426       // we need only return false otherwise.
00427       if (end == 0) 
00428   {
00429     if (tolerant)
00430       throw std::logic_error("Should never get here! checkCommentLine() "
00431            "is supposed to catch empty lines.");
00432     else
00433       return false;
00434   }
00435       // The part of the line that contains data
00436       std::istringstream istr (line.substr (start, end));
00437       // Read the data
00438       Real the_realPart, the_imagPart;
00439       const bool success = 
00440   readComplexData (istr, rowIndex, colIndex, the_realPart, the_imagPart, 
00441        lineNumber, tolerant);
00442       if (success)
00443   {
00444     realPart = the_realPart;
00445     imagPart = the_imagPart;
00446   }
00447       return success;
00448     }
00449 #endif // HAVE_TEUCHOS_COMPLEX
00450 
00451     template<class Ordinal, class PatternCallback>
00452     std::pair<bool, std::vector<size_t> >
00453     readPatternCoordinateData (std::istream& in, 
00454              PatternCallback add,
00455              const size_t startingLineNumber, 
00456              const bool tolerant)
00457     {
00458       std::string line;
00459       size_t lineNumber = startingLineNumber;
00460       bool anySucceeded = false;
00461       bool allSucceeded = true;
00462       std::vector<size_t> badLineNumbers; 
00463       size_t validDataLines = 0;
00464       while (getline (in, line)) {
00465   size_t start, size;
00466   if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
00467     continue; // it's a comment line
00468   }
00469   const std::string theLine = line.substr (start, size);
00470 
00471   Ordinal rowIndex, colIndex;
00472   const bool localSuccess = 
00473     readPatternLine (theLine, rowIndex, colIndex, 
00474          lineNumber++, tolerant);
00475   anySucceeded = anySucceeded || localSuccess;
00476   allSucceeded = allSucceeded && localSuccess;
00477   if (! localSuccess) {
00478     badLineNumbers.push_back (lineNumber);
00479   }
00480   else {
00481     // Add the newly read entry to the sparse graph.
00482     add (rowIndex, colIndex);
00483     ++validDataLines;
00484   }
00485       }
00486       if (lineNumber == startingLineNumber) {
00487   anySucceeded = true; // Trivially true
00488       }
00489     
00490       return std::make_pair (allSucceeded, badLineNumbers);
00491     }
00492 
00493 
00494     template<class Ordinal>
00495     bool
00496     readCoordinateDimensions (std::istream& in, 
00497             Ordinal& numRows, 
00498             Ordinal& numCols,
00499             Ordinal& numNonzeros,
00500             size_t& lineNumber,
00501             const bool tolerant)
00502     {
00503       using std::endl;
00504 
00505       Ordinal the_numRows, the_numCols, the_numNonzeros;
00506       std::string line;
00507 
00508       // Keep reading lines from the input stream until we find a
00509       // non-comment line, or until we run out of lines.  The latter
00510       // is an error, since every "coordinate" format Matrix Market
00511       // file must have a dimensions line after the banner (even if
00512       // the matrix has zero rows or columns, or zero entries).
00513       bool commentLine = true;
00514       while (commentLine)
00515   { 
00516     // Is it even valid to read from the input stream?
00517     if (in.eof() || in.fail())
00518       {
00519         if (tolerant)
00520     return false;
00521         else
00522     {
00523       std::ostringstream os;
00524       os << "Unable to get coordinate dimensions line (at all) "
00525         "from (line " << lineNumber << ") of input stream; the "
00526         "input stream claims that it is at \"end-of-file\" or has "
00527         "an otherwise \"fail\"ed state.";
00528       throw std::invalid_argument(os.str());
00529     }
00530       }
00531     // Try to get the next line from the input stream.
00532     if (! getline(in, line))
00533       {
00534         if (tolerant)
00535     return false;
00536         else
00537     {
00538       std::ostringstream os;
00539       os << "Failed to read coordinate dimensions line (at all) "
00540         "from (line " << lineNumber << " from input stream.  The "
00541         "line should contain the coordinate matrix dimensions in "
00542          << " the form \"<numRows> <numCols> <numNonzeros>\".";
00543       throw std::invalid_argument(os.str());
00544     }
00545       }
00546     // Is the current line a comment line?  Ignore start and
00547     // size; they are only useful for reading the actual matrix
00548     // entries.  (We could use them here as an optimization, but
00549     // we've chosen not to.)
00550     size_t start = 0, size = 0;
00551     commentLine = checkCommentLine (line, start, size, 
00552             lineNumber, tolerant);
00553     // This ensures that any error messages in this file are
00554     // correct.
00555     if (commentLine)
00556       lineNumber++;
00557   }
00558 
00559       // The current line is now not a comment line.
00560       // Try to read the coordinate dimensions from it.
00561       std::istringstream istr (line);
00562       if (istr.eof() || istr.fail())
00563   {
00564     if (tolerant)
00565       return false;
00566     else 
00567       {
00568         std::ostringstream os;
00569         os << "Unable to read any coordinate dimensions data from line " 
00570      << lineNumber << " of input stream.  Offending line:" << endl
00571      << line;
00572         throw std::invalid_argument(os.str());
00573       }
00574   }
00575       istr >> the_numRows;
00576       if (istr.fail())
00577   {
00578     if (tolerant)
00579       return false;
00580     else
00581       {
00582         std::ostringstream os;
00583         os << "Failed to get number of rows from the coordinate "
00584     "dimensions line (line " << lineNumber << " of input stream)."
00585     "   Offending line:" << endl << line;
00586         throw std::invalid_argument(os.str());
00587       }
00588   }
00589       else if (istr.eof())
00590   {
00591     if (tolerant)
00592       return false;
00593     else 
00594       {
00595         std::ostringstream os;
00596         os << "No more data after number of rows, in the coordinate "
00597     "dimensions line (line " << lineNumber << " of input stream)."
00598     "   Offending line:" << endl << line;
00599         throw std::invalid_argument(os.str());
00600       }
00601   }
00602       istr >> the_numCols;
00603       if (istr.fail())
00604   {
00605     if (tolerant)
00606       return false;
00607     else
00608       {
00609         std::ostringstream os;
00610         os << "Failed to get number of columns from the coordinate "
00611     "dimensions line (line " << lineNumber << " of input stream)."
00612     "   Offending line:" << endl << line;
00613         throw std::invalid_argument(os.str());
00614       }
00615   }
00616       else if (istr.eof())
00617   {
00618     if (tolerant)
00619       return false;
00620     else
00621       {
00622         std::ostringstream os;
00623         os << "No more data after number of columns, in the coordinate "
00624     "dimensions line (line " << lineNumber << " of input stream)."
00625     "   Offending line:" << endl << line;
00626         throw std::invalid_argument(os.str());
00627       }
00628   }
00629       istr >> the_numNonzeros;
00630       if (istr.fail())
00631   {
00632     if (tolerant)
00633       return false;
00634     else
00635       {
00636         std::ostringstream os;
00637         os << "Failed to get number of nonzeros from the coordinate "
00638     "dimensions line (line " << lineNumber << " of input stream)."
00639     "   Offending line:" << endl << line;
00640         throw std::invalid_argument(os.str());
00641       }
00642   }
00643       numRows = the_numRows;
00644       numCols = the_numCols;
00645       numNonzeros = the_numNonzeros;
00646       // This function only increments the line number when it reads a
00647       // comment line successfully, or when it reads all the
00648       // coordinate dimensions successfully.
00649       lineNumber++;
00650       return true;
00651     }
00652 
00653   } // namespace MatrixMarket
00654 } // namespace Tpetra
00655 
00656 #endif // __MatrixMarket_generic_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines