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   {
00466     size_t start, size;
00467     if (checkCommentLine (line, start, size, lineNumber, tolerant))
00468       continue; // it's a comment line
00469     const std::string theLine = line.substr (start, size);
00470 
00471     Ordinal rowIndex, colIndex;
00472     const bool localSuccess = readPatternLine (theLine, rowIndex, colIndex, lineNumber++, tolerant);
00473     anySucceeded = anySucceeded || localSuccess;
00474     allSucceeded = allSucceeded && localSuccess;
00475     if (! localSuccess)
00476       badLineNumbers.push_back (lineNumber);
00477     else
00478       {
00479         add (rowIndex, colIndex);
00480         validDataLines++;
00481       }
00482   }
00483       if (lineNumber == startingLineNumber)
00484   anySucceeded = true; // Trivially true
00485     
00486       return std::make_pair (allSucceeded, badLineNumbers);
00487     }
00488 
00489 
00490     template<class Ordinal>
00491     bool
00492     readCoordinateDimensions (std::istream& in, 
00493             Ordinal& numRows, 
00494             Ordinal& numCols,
00495             Ordinal& numNonzeros,
00496             size_t& lineNumber,
00497             const bool tolerant)
00498     {
00499       using std::endl;
00500 
00501       Ordinal the_numRows, the_numCols, the_numNonzeros;
00502       std::string line;
00503 
00504       // Keep reading lines from the input stream until we find a
00505       // non-comment line, or until we run out of lines.  The latter
00506       // is an error, since every "coordinate" format Matrix Market
00507       // file must have a dimensions line after the banner (even if
00508       // the matrix has zero rows or columns, or zero entries).
00509       bool commentLine = true;
00510       while (commentLine)
00511   { 
00512     // Is it even valid to read from the input stream?
00513     if (in.eof() || in.fail())
00514       {
00515         if (tolerant)
00516     return false;
00517         else
00518     {
00519       std::ostringstream os;
00520       os << "Unable to get coordinate dimensions line (at all) "
00521         "from (line " << lineNumber << ") of input stream; the "
00522         "input stream claims that it is at \"end-of-file\" or has "
00523         "an otherwise \"fail\"ed state.";
00524       throw std::invalid_argument(os.str());
00525     }
00526       }
00527     // Try to get the next line from the input stream.
00528     if (! getline(in, line))
00529       {
00530         if (tolerant)
00531     return false;
00532         else
00533     {
00534       std::ostringstream os;
00535       os << "Failed to read coordinate dimensions line (at all) "
00536         "from (line " << lineNumber << " from input stream.  The "
00537         "line should contain the coordinate matrix dimensions in "
00538          << " the form \"<numRows> <numCols> <numNonzeros>\".";
00539       throw std::invalid_argument(os.str());
00540     }
00541       }
00542     // Is the current line a comment line?  Ignore start and
00543     // size; they are only useful for reading the actual matrix
00544     // entries.  (We could use them here as an optimization, but
00545     // we've chosen not to.)
00546     size_t start = 0, size = 0;
00547     commentLine = checkCommentLine (line, start, size, 
00548             lineNumber, tolerant);
00549     // This ensures that any error messages in this file are
00550     // correct.
00551     if (commentLine)
00552       lineNumber++;
00553   }
00554 
00555       // The current line is now not a comment line.
00556       // Try to read the coordinate dimensions from it.
00557       std::istringstream istr (line);
00558       if (istr.eof() || istr.fail())
00559   {
00560     if (tolerant)
00561       return false;
00562     else 
00563       {
00564         std::ostringstream os;
00565         os << "Unable to read any coordinate dimensions data from line " 
00566      << lineNumber << " of input stream.  Offending line:" << endl
00567      << line;
00568         throw std::invalid_argument(os.str());
00569       }
00570   }
00571       istr >> the_numRows;
00572       if (istr.fail())
00573   {
00574     if (tolerant)
00575       return false;
00576     else
00577       {
00578         std::ostringstream os;
00579         os << "Failed to get number of rows from the coordinate "
00580     "dimensions line (line " << lineNumber << " of input stream)."
00581     "   Offending line:" << endl << line;
00582         throw std::invalid_argument(os.str());
00583       }
00584   }
00585       else if (istr.eof())
00586   {
00587     if (tolerant)
00588       return false;
00589     else 
00590       {
00591         std::ostringstream os;
00592         os << "No more data after number of rows, in the coordinate "
00593     "dimensions line (line " << lineNumber << " of input stream)."
00594     "   Offending line:" << endl << line;
00595         throw std::invalid_argument(os.str());
00596       }
00597   }
00598       istr >> the_numCols;
00599       if (istr.fail())
00600   {
00601     if (tolerant)
00602       return false;
00603     else
00604       {
00605         std::ostringstream os;
00606         os << "Failed to get number of columns from the coordinate "
00607     "dimensions line (line " << lineNumber << " of input stream)."
00608     "   Offending line:" << endl << line;
00609         throw std::invalid_argument(os.str());
00610       }
00611   }
00612       else if (istr.eof())
00613   {
00614     if (tolerant)
00615       return false;
00616     else
00617       {
00618         std::ostringstream os;
00619         os << "No more data after number of columns, in the coordinate "
00620     "dimensions line (line " << lineNumber << " of input stream)."
00621     "   Offending line:" << endl << line;
00622         throw std::invalid_argument(os.str());
00623       }
00624   }
00625       istr >> the_numNonzeros;
00626       if (istr.fail())
00627   {
00628     if (tolerant)
00629       return false;
00630     else
00631       {
00632         std::ostringstream os;
00633         os << "Failed to get number of nonzeros from the coordinate "
00634     "dimensions line (line " << lineNumber << " of input stream)."
00635     "   Offending line:" << endl << line;
00636         throw std::invalid_argument(os.str());
00637       }
00638   }
00639       numRows = the_numRows;
00640       numCols = the_numCols;
00641       numNonzeros = the_numNonzeros;
00642       // This function only increments the line number when it reads a
00643       // comment line successfully, or when it reads all the
00644       // coordinate dimensions successfully.
00645       lineNumber++;
00646       return true;
00647     }
00648 
00649   } // namespace MatrixMarket
00650 } // namespace Tpetra
00651 
00652 #endif // __MatrixMarket_generic_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines