Teuchos - Trilinos Tools Package Version of the Day
Teuchos_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 __Teuchos_MatrixMarket_generic_hpp
00043 #define __Teuchos_MatrixMarket_generic_hpp
00044 
00045 #include "Teuchos_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 
00054 namespace Teuchos {
00055   namespace MatrixMarket {
00056 
00062     int maxLineLength();
00063 
00092     TEUCHOS_LIB_DLL_EXPORT bool
00093     checkCommentLine (const std::string& line,
00094                       size_t& start,
00095                       size_t& size,
00096                       const size_t lineNumber,
00097                       const bool tolerant,
00098                       const bool maybeBannerLine = false);
00099 
00133     template<class Ordinal>
00134     bool
00135     readPatternData (std::istream& istr,
00136                      Ordinal& rowIndex,
00137                      Ordinal& colIndex,
00138                      const size_t lineNumber,
00139                      const bool tolerant)
00140     {
00141       Ordinal the_rowIndex, the_colIndex;
00142 
00143       if (istr.eof() || istr.fail())
00144         {
00145           if (tolerant)
00146             return false;
00147           else
00148             {
00149               std::ostringstream os;
00150               os << "Unable to read any data from line " << lineNumber << " of input";
00151               throw std::invalid_argument(os.str());
00152             }
00153         }
00154       istr >> the_rowIndex;
00155       if (istr.fail())
00156         {
00157           if (tolerant)
00158             return false;
00159           else
00160             {
00161               std::ostringstream os;
00162               os << "Failed to get row index from line " << lineNumber << " of input";
00163               throw std::invalid_argument(os.str());
00164             }
00165         }
00166       else if (istr.eof())
00167         {
00168           if (tolerant)
00169             return false;
00170           else
00171             {
00172               std::ostringstream os;
00173               os << "No more data after row index on line " << lineNumber << " of input";
00174               throw std::invalid_argument(os.str());
00175             }
00176         }
00177       istr >> the_colIndex;
00178       if (istr.fail())
00179         {
00180           if (tolerant)
00181             return false;
00182           else
00183             {
00184               std::ostringstream os;
00185               os << "Failed to get column index from line " << lineNumber << " of input";
00186               throw std::invalid_argument(os.str());
00187             }
00188         }
00189       rowIndex = the_rowIndex;
00190       colIndex = the_colIndex;
00191       return true;
00192     }
00193 
00232     template<class Ordinal, class Real>
00233     bool
00234     readRealData (std::istream& istr,
00235                   Ordinal& rowIndex,
00236                   Ordinal& colIndex,
00237                   Real& realValue,
00238                   const size_t lineNumber,
00239                   const bool tolerant)
00240     {
00241       Real the_realValue;
00242       if (! readPatternData (istr, rowIndex, colIndex, lineNumber, tolerant))
00243         {
00244           if (tolerant)
00245             return false;
00246           else
00247             {
00248               std::ostringstream os;
00249               os << "Failed to read pattern data from line " << lineNumber << " of input";
00250               throw std::invalid_argument(os.str());
00251             }
00252         }
00253       if (istr.eof())
00254         {
00255           if (tolerant)
00256             return false;
00257           else
00258             {
00259               std::ostringstream os;
00260               os << "No more data after pattern data on line " << lineNumber << " of input";
00261               throw std::invalid_argument(os.str());
00262             }
00263         }
00264       istr >> the_realValue;
00265       if (istr.fail())
00266         {
00267           if (tolerant)
00268             return false;
00269           else
00270             {
00271               std::ostringstream os;
00272               os << "Failed to get real value from line " << lineNumber << " of input";
00273               throw std::invalid_argument(os.str());
00274             }
00275         }
00276       realValue = the_realValue;
00277       return true;
00278     }
00279 
00280 #ifdef HAVE_TEUCHOS_COMPLEX
00281 
00323     template<class Ordinal, class Real>
00324     bool
00325     readComplexData (std::istream& istr,
00326                      Ordinal& rowIndex,
00327                      Ordinal& colIndex,
00328                      Real& realPart,
00329                      Real& imagPart,
00330                      const size_t lineNumber,
00331                      const bool tolerant)
00332     {
00333       Real the_realPart, the_imagPart;
00334       if (! readRealData (istr, rowIndex, colIndex, the_realPart, lineNumber, tolerant))
00335         {
00336           if (tolerant)
00337             return false;
00338           else
00339             {
00340               std::ostringstream os;
00341               os << "Failed to read pattern data and/or real value from line "
00342                  << lineNumber << " of input";
00343               throw std::invalid_argument(os.str());
00344             }
00345         }
00346       if (istr.eof())
00347         {
00348           if (tolerant)
00349             return false;
00350           else
00351             {
00352               std::ostringstream os;
00353               os << "No more data after real value on line "
00354                  << lineNumber << " of input";
00355               throw std::invalid_argument(os.str());
00356             }
00357         }
00358       istr >> the_imagPart;
00359       if (istr.fail())
00360         {
00361           if (tolerant)
00362             return false;
00363           else
00364             {
00365               std::ostringstream os;
00366               os << "Failed to get imaginary value from line "
00367                  << lineNumber << " of input";
00368               throw std::invalid_argument(os.str());
00369             }
00370         }
00371       realPart = the_realPart;
00372       imagPart = the_imagPart;
00373       return true;
00374     }
00375 #endif // HAVE_TEUCHOS_COMPLEX
00376 
00377     template<class Ordinal>
00378     bool
00379     readPatternLine (const std::string& line, // only the data-containing part
00380                      Ordinal& rowIndex,
00381                      Ordinal& colIndex,
00382                      const size_t lineNumber,
00383                      const bool tolerant)
00384     {
00385       // The part of the line that contains data
00386       std::istringstream istr (line);
00387       return readPatternData (istr, rowIndex, colIndex, lineNumber, tolerant);
00388     }
00389 
00390     template<class Ordinal, class Real>
00391     bool
00392     readRealLine (const std::string& line,
00393                   Ordinal& rowIndex,
00394                   Ordinal& colIndex,
00395                   Real& realValue,
00396                   const size_t lineNumber,
00397                   const bool tolerant)
00398     {
00399       size_t start, size;
00400       if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
00401         return false; // It's a comment line
00402       }
00403       // If it's an empty line, checkCommentLine() will throw an
00404       // exception if non-tolerant parsing is being performed, so
00405       // we need only return false otherwise.
00406       if (size == 0) {
00407         if (! tolerant) {
00408           throw std::logic_error("Should never get here! checkCommentLine() "
00409                                  "is supposed to catch empty lines.");
00410         }
00411         else {
00412           return false;
00413         }
00414       }
00415       // The part of the line that contains data
00416       std::istringstream istr (line.substr (start, size));
00417       return readRealData (istr, rowIndex, colIndex, realValue, lineNumber, tolerant);
00418     }
00419 
00420 #ifdef HAVE_TEUCHOS_COMPLEX
00421     template<class Ordinal, class Real>
00422     bool
00423     readComplexLine (const std::string& line,
00424                      Ordinal& rowIndex,
00425                      Ordinal& colIndex,
00426                      Real& realPart,
00427                      Real& imagPart,
00428                      const size_t lineNumber,
00429                      const bool tolerant)
00430     {
00431       size_t start, end;
00432       if (checkCommentLine (line, start, end, lineNumber, tolerant))
00433         return false; // It's a comment line
00434       // If it's an empty line, checkCommentLine() will throw an
00435       // exception if non-tolerant parsing is being performed, so
00436       // we need only return false otherwise.
00437       if (end == 0)
00438         {
00439           if (tolerant)
00440             throw std::logic_error("Should never get here! checkCommentLine() "
00441                                    "is supposed to catch empty lines.");
00442           else
00443             return false;
00444         }
00445       // The part of the line that contains data
00446       std::istringstream istr (line.substr (start, end));
00447       // Read the data
00448       Real the_realPart, the_imagPart;
00449       const bool success =
00450         readComplexData (istr, rowIndex, colIndex, the_realPart, the_imagPart,
00451                          lineNumber, tolerant);
00452       if (success)
00453         {
00454           realPart = the_realPart;
00455           imagPart = the_imagPart;
00456         }
00457       return success;
00458     }
00459 #endif // HAVE_TEUCHOS_COMPLEX
00460 
00461     template<class Ordinal, class PatternCallback>
00462     std::pair<bool, std::vector<size_t> >
00463     readPatternCoordinateData (std::istream& in,
00464                                PatternCallback add,
00465                                const size_t startingLineNumber,
00466                                const bool tolerant)
00467     {
00468       std::string line;
00469       size_t lineNumber = startingLineNumber;
00470       bool anySucceeded = false;
00471       bool allSucceeded = true;
00472       std::vector<size_t> badLineNumbers;
00473       size_t validDataLines = 0;
00474       while (getline (in, line)) {
00475         size_t start, size;
00476         if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
00477           continue; // it's a comment line
00478         }
00479         const std::string theLine = line.substr (start, size);
00480 
00481         Ordinal rowIndex, colIndex;
00482         const bool localSuccess =
00483           readPatternLine (theLine, rowIndex, colIndex,
00484                            lineNumber++, tolerant);
00485         anySucceeded = anySucceeded || localSuccess;
00486         allSucceeded = allSucceeded && localSuccess;
00487         if (! localSuccess) {
00488           badLineNumbers.push_back (lineNumber);
00489         }
00490         else {
00491           // Add the newly read entry to the sparse graph.
00492           add (rowIndex, colIndex);
00493           ++validDataLines;
00494         }
00495       }
00496       if (lineNumber == startingLineNumber) {
00497         anySucceeded = true; // Trivially true
00498       }
00499 
00500       return std::make_pair (allSucceeded, badLineNumbers);
00501     }
00502 
00503 
00504     template<class Ordinal>
00505     bool
00506     readCoordinateDimensions (std::istream& in,
00507                               Ordinal& numRows,
00508                               Ordinal& numCols,
00509                               Ordinal& numNonzeros,
00510                               size_t& lineNumber,
00511                               const bool tolerant)
00512     {
00513       using std::endl;
00514 
00515       Ordinal the_numRows, the_numCols, the_numNonzeros;
00516       std::string line;
00517 
00518       // Keep reading lines from the input stream until we find a
00519       // non-comment line, or until we run out of lines.  The latter
00520       // is an error, since every "coordinate" format Matrix Market
00521       // file must have a dimensions line after the banner (even if
00522       // the matrix has zero rows or columns, or zero entries).
00523       bool commentLine = true;
00524       while (commentLine)
00525         {
00526           // Is it even valid to read from the input stream?
00527           if (in.eof () || in.fail ()) {
00528             if (tolerant) {
00529               return false;
00530             }
00531             else {
00532               std::ostringstream os;
00533               os << "Unable to get coordinate dimensions line (at all) "
00534                 "from (line " << lineNumber << ") of input stream; the "
00535                 "input stream claims that it is at \"end-of-file\" or has "
00536                 "an otherwise \"fail\"ed state.";
00537               throw std::invalid_argument(os.str());
00538             }
00539           }
00540           // Try to get the next line from the input stream.
00541           if (! getline (in, line)) {
00542             if (tolerant) {
00543               return false;
00544             }
00545             else {
00546               std::ostringstream os;
00547               os << "Failed to read coordinate dimensions line (at all) "
00548                 "from (line " << lineNumber << " from input stream.  The "
00549                 "line should contain the coordinate matrix dimensions in "
00550                  << " the form \"<numRows> <numCols> <numNonzeros>\".";
00551               throw std::invalid_argument(os.str());
00552             }
00553           }
00554           // Is the current line a comment line?  Ignore start and
00555           // size; they are only useful for reading the actual matrix
00556           // entries.  (We could use them here as an optimization, but
00557           // we've chosen not to.)
00558           size_t start = 0, size = 0;
00559           commentLine = checkCommentLine (line, start, size,
00560                                           lineNumber, tolerant);
00561           // This ensures that any error messages in this file are
00562           // correct.
00563           if (commentLine) {
00564             ++lineNumber;
00565           }
00566         }
00567 
00568       // The current line is now not a comment line.
00569       // Try to read the coordinate dimensions from it.
00570       std::istringstream istr (line);
00571       if (istr.eof () || istr.fail ()) {
00572         if (tolerant) {
00573           return false;
00574         }
00575         else {
00576           std::ostringstream os;
00577           os << "Unable to read any coordinate dimensions data from line "
00578              << lineNumber << " of input stream.  Offending line:" << endl
00579              << line;
00580           throw std::invalid_argument(os.str());
00581         }
00582       }
00583       istr >> the_numRows;
00584       if (istr.fail ()) {
00585         if (tolerant) {
00586           return false;
00587         }
00588         else {
00589           std::ostringstream os;
00590           os << "Failed to get number of rows from the coordinate "
00591             "dimensions line (line " << lineNumber << " of input stream)."
00592             "   Offending line:" << endl << line;
00593           throw std::invalid_argument(os.str());
00594         }
00595       }
00596       else if (istr.eof ()) {
00597         if (tolerant) {
00598           return false;
00599         }
00600         else {
00601           std::ostringstream os;
00602           os << "No more data after number of rows, in the coordinate "
00603             "dimensions line (line " << lineNumber << " of input stream)."
00604             "   Offending line:" << endl << line;
00605           throw std::invalid_argument(os.str());
00606         }
00607       }
00608       istr >> the_numCols;
00609       if (istr.fail ()) {
00610         if (tolerant) {
00611           return false;
00612         }
00613         else {
00614           std::ostringstream os;
00615           os << "Failed to get number of columns from the coordinate "
00616             "dimensions line (line " << lineNumber << " of input stream)."
00617             "   Offending line:" << endl << line;
00618           throw std::invalid_argument(os.str());
00619         }
00620       }
00621       else if (istr.eof ()) {
00622         if (tolerant) {
00623           return false;
00624         }
00625         else {
00626           std::ostringstream os;
00627           os << "No more data after number of columns, in the coordinate "
00628             "dimensions line (line " << lineNumber << " of input stream)."
00629             "   Offending line:" << endl << line;
00630           throw std::invalid_argument (os.str ());
00631         }
00632       }
00633       istr >> the_numNonzeros;
00634       if (istr.fail ()) {
00635         if (tolerant) {
00636           return false;
00637         }
00638         else {
00639           std::ostringstream os;
00640           os << "Failed to get number of nonzeros from the coordinate "
00641             "dimensions line (line " << lineNumber << " of input stream)."
00642             "   Offending line:" << endl << line;
00643           throw std::invalid_argument (os.str ());
00644         }
00645       }
00646       numRows = the_numRows;
00647       numCols = the_numCols;
00648       numNonzeros = the_numNonzeros;
00649       // This function only increments the line number when it reads a
00650       // comment line successfully, or when it reads all the
00651       // coordinate dimensions successfully.
00652       ++lineNumber;
00653       return true;
00654     }
00655 
00656   } // namespace MatrixMarket
00657 } // namespace Teuchos
00658 
00659 #endif // __Teuchos_MatrixMarket_generic_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines