Tpetra Matrix/Vector Services Version of the Day
MatrixMarket_CoordDataReader.hpp
00001 //@HEADER
00002 // ************************************************************************
00003 // 
00004 //               Tpetra: Linear Algebra Services Package 
00005 //                 Copyright 2011 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_CoordDataReader_hpp
00043 #define __MatrixMarket_CoordDataReader_hpp
00044 
00045 #include "MatrixMarket_generic.hpp"
00046 
00047 namespace Tpetra {
00048   namespace MatrixMarket {
00049 
00057     template<class Callback, class Ordinal, class Scalar, bool isComplex = ScalarTraits<Scalar>::isComplex>
00058     class CoordDataReaderBase {
00059     private:
00061       RCP<Callback> adder_;
00062 
00063     public:
00073       CoordDataReaderBase (const RCP<Callback>& adder) : 
00074   adder_ (adder) {}
00075 
00083       CoordDataReaderBase () : adder_ (null) {}
00084 
00086       virtual ~CoordDataReaderBase () {}
00087 
00094       void setAdder (const RCP<Callback>& adder) {
00095   adder_ = adder;
00096       }
00097 
00102       virtual bool
00103       readLine (const std::string& theLine, 
00104     Ordinal& rowIndex, 
00105     Ordinal& colIndex, 
00106     Scalar& value, 
00107     const size_t lineNumber,
00108     const bool tolerant) = 0;
00109 
00126       std::pair<bool, std::vector<size_t> >
00127       read (std::istream& in, 
00128       const size_t startingLineNumber, 
00129       const bool tolerant,
00130       const bool debug = false)
00131       {
00132   using std::cerr;
00133   using std::endl;
00134   typedef ScalarTraits<Scalar> STS;
00135 
00136   if (isComplex != STS::isComplex)
00137     throw std::logic_error("Should never get here!");
00138   else if (! in)
00139     throw std::invalid_argument("Input stream is invalid");
00140 
00141   std::string line;
00142   size_t lineNumber = startingLineNumber;
00143   bool allSucceeded = true;
00144   std::vector<size_t> badLineNumbers; 
00145   size_t validDataLines = 0;
00146   while (getline (in, line))
00147     {
00148       size_t start, size;
00149       if (checkCommentLine (line, start, size, lineNumber, tolerant))
00150         {
00151     // if (debug)
00152     //  cerr << "Comment line: " << lineNumber << endl;
00153     lineNumber++;
00154     continue; // it's a comment line
00155         }
00156       const std::string theLine = line.substr (start, size);
00157       // if (debug)
00158       //   cerr << "Possible data line " << lineNumber << ": " << line << endl;
00159 
00160       Ordinal rowIndex, colIndex;
00161       Scalar value;
00162       const bool localSuccess = readLine (theLine, rowIndex, colIndex, 
00163             value, lineNumber, tolerant);
00164       lineNumber++;
00165       allSucceeded = allSucceeded && localSuccess;
00166       if (! localSuccess)
00167         badLineNumbers.push_back (lineNumber);
00168       else
00169         {
00170     (*adder_) (rowIndex, colIndex, value);
00171     validDataLines++;
00172         }
00173     }
00174   return std::make_pair (allSucceeded, badLineNumbers);
00175       }
00176 
00201       std::pair<Tuple<Ordinal, 3>, bool>
00202       readDimensions (std::istream& in, 
00203           size_t& lineNumber,
00204           const bool tolerant = false)
00205       {
00206   Tuple<Ordinal, 3> dims;
00207   // Fill in (numRows, numCols, numNonzeros) with reasonable
00208   // defaults.  If we don't succeed in reading all the data
00209   // from the current line of the input stream, the remaining
00210   // values not read will be these default values.
00211   dims[0] = 0;
00212   dims[1] = 0;
00213   dims[2] = 0;
00214 
00215   // Keep reading lines from the input stream until we find a
00216   // non-comment line, or until we run out of lines.  The latter
00217   // is an error, since every "coordinate" format Matrix Market
00218   // file must have a dimensions line after the banner (even if
00219   // the matrix has zero rows or columns, or zero entries).
00220   std::string line;
00221   bool commentLine = true;
00222   while (commentLine)
00223     {
00224       // Is it even valid to read from the input stream?
00225       if (in.eof() || in.fail())
00226         {
00227     if (tolerant)
00228       return std::make_pair (dims, false);
00229     else
00230       {
00231         std::ostringstream os;
00232         os << "Unable to get coordinate dimensions line (at all) "
00233           "from (line " << lineNumber << ") of input stream; the "
00234           "input stream claims that it is at \"end-of-file\" or has "
00235           "an otherwise \"fail\"ed state.";
00236         throw std::invalid_argument(os.str());
00237       }
00238         }
00239       // Try to get the next line from the input stream.
00240       if (getline(in, line))
00241         lineNumber++; // We did actually read a line
00242       else
00243         {
00244     if (tolerant)
00245       return std::make_pair (dims, false);
00246     else
00247       {
00248         std::ostringstream os;
00249         os << "Failed to read coordinate dimensions line (at all) "
00250           "from (line " << lineNumber << " from input stream.  The "
00251           "line should contain the coordinate matrix dimensions in "
00252            << " the form \"<numRows> <numCols> <numNonzeros>\".";
00253         throw std::invalid_argument (os.str());
00254       }
00255         }
00256       // Is the current line a comment line?  Ignore start and
00257       // size; they are only useful for reading the actual matrix
00258       // entries.  (We could use them here as an optimization, but
00259       // we've chosen not to.)
00260       size_t start = 0, size = 0;
00261       commentLine = checkCommentLine (line, start, size, 
00262               lineNumber, tolerant);
00263     }
00264   //
00265   // Read in <numRows> <numCols> <numNonzeros> from input line
00266   //
00267   std::istringstream istr (line);
00268   // Does line contain anything at all?  Can we safely read from
00269   // the input stream wrapping the line?
00270   if (istr.eof() || istr.fail())
00271     {
00272       if (tolerant)
00273         return std::make_pair (dims, false);
00274       std::ostringstream os;
00275       os << "Unable to read any data from line " << lineNumber 
00276          << " of input; the line should contain the coordinate matrix "
00277          << "dimensions \"<numRows> <numCols> <numNonzeros>\".";
00278       throw std::invalid_argument(os.str());
00279     }
00280   // Read in <numRows>
00281   {
00282     Ordinal theNumRows = 0;
00283     istr >> theNumRows;
00284     if (istr.fail())
00285       {
00286         if (tolerant)
00287     return std::make_pair (dims, false);
00288         std::ostringstream os;
00289         os << "Failed to get number of rows from line " << lineNumber 
00290      << " of input; the line should contain the coordinate matrix "
00291      << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00292         throw std::invalid_argument(os.str());
00293       }
00294     else // Capture the validly read result before checking for eof.
00295       dims[0] = theNumRows;
00296   }
00297   // There should be two more things to read.
00298   if (istr.eof())
00299     {
00300       if (tolerant)
00301         return std::make_pair (dims, false);
00302       std::ostringstream os;
00303       os << "No more data after number of rows on line " << lineNumber
00304          << " of input; the line should contain the coordinate matrix "
00305          << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00306       throw std::invalid_argument(os.str());
00307     }
00308   // Read in <numCols>
00309   {
00310     Ordinal theNumCols = 0;
00311     istr >> theNumCols;
00312     if (istr.fail())
00313       {
00314         if (tolerant)
00315     return std::make_pair (dims, false);
00316         std::ostringstream os;
00317         os << "Failed to get number of columns from line " << lineNumber 
00318      << " of input; the line should contain the coordinate matrix "
00319      << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00320         throw std::invalid_argument(os.str());
00321       }
00322     else // Capture the validly read result before checking for eof.
00323       dims[1] = theNumCols;
00324   }
00325   // There should be one more thing to read.
00326   if (istr.eof())
00327     {
00328       if (tolerant)
00329         return std::make_pair (dims, false);
00330       std::ostringstream os;
00331       os << "No more data after number of columns on line " << lineNumber
00332          << " of input; the line should contain the coordinate matrix "
00333          << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00334       throw std::invalid_argument(os.str());
00335     }
00336   // Read in <numNonzeros>
00337   {
00338     Ordinal theNumNonzeros = 0;
00339     istr >> theNumNonzeros;
00340     if (istr.fail())
00341       {
00342         if (tolerant)
00343     return std::make_pair (dims, false);
00344         std::ostringstream os;
00345         os << "Failed to get number of (structural) nonzeros from line " 
00346      << lineNumber 
00347      << " of input; the line should contain the coordinate matrix "
00348      << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00349         throw std::invalid_argument(os.str());
00350       }
00351     else // Capture the validly read result
00352       dims[2] = theNumNonzeros;
00353   }
00354   // It would be nice to validate the read-in data further.  The
00355   // only thing we can do now is test if it's negative.  However,
00356   // we don't know syntactically whether Ordinal is a signed or
00357   // unsigned type, so we shouldn't even test for negativity.
00358   return std::make_pair (dims, true);
00359       }
00360     };
00361 
00362 
00370     template<class Callback, class Ordinal, class Scalar, bool isComplex = ScalarTraits<Scalar>::isComplex>
00371     class CoordDataReader :
00372       public CoordDataReaderBase<Callback, Ordinal, Scalar, isComplex>
00373     {
00374     public:
00375       CoordDataReader (const RCP<Callback>& adder);
00376       CoordDataReader ();
00377 
00379       virtual ~CoordDataReader();
00380 
00381       bool
00382       readLine (const std::string& theLine, 
00383     Ordinal& rowIndex, 
00384     Ordinal& colIndex, 
00385     Scalar& value, 
00386     const size_t lineNumber,
00387     const bool tolerant);
00388     };
00389 
00390 #ifdef HAVE_TEUCHOS_COMPLEX
00391     template<class Callback, class Ordinal, class Scalar>
00392     class CoordDataReader<Callback, Ordinal, Scalar, true> : 
00393       public CoordDataReaderBase<Callback, Ordinal, Scalar, true>
00394     {
00395     public:
00396       CoordDataReader (const RCP<Callback>& adder) :
00397   CoordDataReaderBase<Callback, Ordinal, Scalar, true> (adder)
00398       {}
00399 
00400       CoordDataReader() : 
00401   CoordDataReaderBase<Callback, Ordinal, Scalar, true> (null)
00402       {}
00403 
00405       virtual ~CoordDataReader() {};
00406 
00407       bool
00408       readLine (const std::string& theLine, 
00409     Ordinal& rowIndex, 
00410     Ordinal& colIndex, 
00411     Scalar& value, 
00412     const size_t lineNumber,
00413     const bool tolerant)
00414       {
00415   typedef ScalarTraits<Scalar> STS;
00416   typedef typename STS::magnitudeType Real;
00417   Real realPart, imagPart;
00418   const bool localSuccess = 
00419     readComplexLine (theLine, rowIndex, colIndex, realPart, imagPart,
00420          lineNumber, tolerant);
00421   if (localSuccess)
00422     {
00423       // Assume that assignment from std::complex<Real> to
00424       // Scalar (which itself is complex-valued) is valid.
00425       // We have to do this, since the C++ compiler may not
00426       // be smart enough to assume here (when it
00427       // instantiates the templates) that Scalar is an
00428       // std::complex<Real> -- even though it has to be, if
00429       // STS::isComplex is true (which as of 31 Jan 2011,
00430       // only holds for std::complex<T>).
00431       const std::complex<Real> theValue (realPart, imagPart);
00432       value = theValue;
00433     }
00434   return localSuccess;
00435       }
00436     };
00437 #endif // HAVE_TEUCHOS_COMPLEX
00438 
00439     template<class Callback, class Ordinal, class Scalar>
00440     class CoordDataReader<Callback, Ordinal, Scalar, false> : 
00441       public CoordDataReaderBase<Callback, Ordinal, Scalar, false>
00442     {
00443     public:
00444       CoordDataReader (const RCP<Callback>& adder) :
00445   CoordDataReaderBase<Callback, Ordinal, Scalar, false> (adder)
00446       {}
00447 
00448       CoordDataReader() : 
00449   CoordDataReaderBase<Callback, Ordinal, Scalar, false> (null)
00450       {}
00451 
00453       virtual ~CoordDataReader() {};
00454 
00455       bool
00456       readLine (const std::string& theLine, 
00457     Ordinal& rowIndex, 
00458     Ordinal& colIndex, 
00459     Scalar& value, 
00460     const size_t lineNumber,
00461     const bool tolerant)
00462       {
00463   return readRealLine (theLine, rowIndex, colIndex, value, 
00464            lineNumber, tolerant);
00465       }
00466     };
00467 
00468   } // namespace MatrixMarket
00469 } // namespace Tpetra
00470 
00471 #endif // __MatrixMarket_CoordDataReader_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines