Tpetra Matrix/Vector Services Version of the Day
MatrixMarket_CoordDataReader.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_CoordDataReader_hpp
00043 #define __MatrixMarket_CoordDataReader_hpp
00044 
00045 #include "MatrixMarket_generic.hpp"
00046 
00047 namespace Tpetra {
00048   namespace MatrixMarket {
00049 
00062     template<class Callback, class Ordinal> 
00063     class CoordDataReaderBase {
00064     protected:
00066       RCP<Callback> adder_;
00067 
00068     public:
00079       CoordDataReaderBase (const RCP<Callback>& adder) : 
00080   adder_ (adder) {}
00081 
00089       CoordDataReaderBase () : adder_ (null) {}
00090 
00092       virtual ~CoordDataReaderBase () {}
00093 
00100       void setAdder (const RCP<Callback>& adder) {
00101   adder_ = adder;
00102       }
00103 
00104     protected:
00105 
00132       virtual bool
00133       readLine (const std::string& theLine, 
00134     const size_t lineNumber,
00135     const bool tolerant) = 0;
00136 
00137     public:
00138 
00166       virtual std::pair<bool, std::vector<size_t> >
00167       read (std::istream& in, 
00168       const size_t startingLineNumber, 
00169       const bool tolerant,
00170       const bool debug = false)
00171       {
00172   (void) debug; // silence unused input argument warning
00173   TEUCHOS_TEST_FOR_EXCEPTION(! in, std::invalid_argument, 
00174           "Input stream is invalid.");
00175 
00176   std::string line;
00177   size_t lineNumber = startingLineNumber;
00178   bool allSucceeded = true;
00179   std::vector<size_t> badLineNumbers; 
00180   size_t validDataLines = 0;
00181   while (getline (in, line)) {
00182     size_t start, size;
00183     if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
00184       ++lineNumber;
00185       continue; // it's a comment line
00186     }
00187     const std::string theLine = line.substr (start, size);
00188 
00189     const bool localSuccess = readLine (theLine, lineNumber, tolerant);
00190     ++lineNumber;
00191     allSucceeded = allSucceeded && localSuccess;
00192     if (! localSuccess) {
00193       badLineNumbers.push_back (lineNumber);
00194     }
00195     else {
00196       ++validDataLines;
00197     }
00198   }
00199   return std::make_pair (allSucceeded, badLineNumbers);
00200       }
00201 
00226       std::pair<Tuple<Ordinal, 3>, bool>
00227       readDimensions (std::istream& in, 
00228           size_t& lineNumber,
00229           const bool tolerant = false)
00230       {
00231   Tuple<Ordinal, 3> dims;
00232   // Fill in (numRows, numCols, numNonzeros) with reasonable
00233   // defaults.  If we don't succeed in reading all the data
00234   // from the current line of the input stream, the remaining
00235   // values not read will be these default values.
00236   dims[0] = 0;
00237   dims[1] = 0;
00238   dims[2] = 0;
00239 
00240   // Keep reading lines from the input stream until we find a
00241   // non-comment line, or until we run out of lines.  The latter
00242   // is an error, since every "coordinate" format Matrix Market
00243   // file must have a dimensions line after the banner (even if
00244   // the matrix has zero rows or columns, or zero entries).
00245   std::string line;
00246   bool commentLine = true;
00247   while (commentLine) {
00248     // Is it even valid to read from the input stream?
00249     if (in.eof() || in.fail()) {
00250       if (tolerant) {
00251         return std::make_pair (dims, false);
00252       }
00253       else {
00254         std::ostringstream os;
00255         os << "Unable to get coordinate dimensions line (at all) "
00256     "from (line " << lineNumber << ") of input stream; the "
00257     "input stream claims that it is at \"end-of-file\" or has "
00258     "an otherwise \"fail\"ed state.";
00259         throw std::invalid_argument(os.str());
00260       }
00261     }
00262     // Try to get the next line from the input stream.
00263     if (getline(in, line)) {
00264       lineNumber++; // We did actually read a line
00265     }
00266     else {
00267       if (tolerant) {
00268         return std::make_pair (dims, false);
00269       }
00270       else {
00271         std::ostringstream os;
00272         os << "Failed to read coordinate dimensions line (at all) "
00273     "from (line " << lineNumber << " from input stream.  The "
00274     "line should contain the coordinate matrix dimensions in "
00275      << " the form \"<numRows> <numCols> <numNonzeros>\".";
00276         throw std::invalid_argument (os.str());
00277       }
00278     }
00279     // Is the current line a comment line?  Ignore start and
00280     // size; they are only useful for reading the actual matrix
00281     // entries.  (We could use them here as an optimization, but
00282     // we've chosen not to.)
00283     size_t start = 0, size = 0;
00284     commentLine = checkCommentLine (line, start, size, 
00285             lineNumber, tolerant);
00286   }
00287   //
00288   // Read in <numRows> <numCols> <numNonzeros> from input line
00289   //
00290   std::istringstream istr (line);
00291   // Does line contain anything at all?  Can we safely read from
00292   // the input stream wrapping the line?
00293   if (istr.eof() || istr.fail()) {
00294     if (tolerant) {
00295       return std::make_pair (dims, false);
00296     }
00297     std::ostringstream os;
00298     os << "Unable to read any data from line " << lineNumber 
00299        << " of input; the line should contain the coordinate matrix "
00300        << "dimensions \"<numRows> <numCols> <numNonzeros>\".";
00301     throw std::invalid_argument(os.str());
00302   }
00303   // Read in <numRows>
00304   {
00305     Ordinal theNumRows = 0;
00306     istr >> theNumRows;
00307     if (istr.fail()) {
00308       if (tolerant) {
00309         return std::make_pair (dims, false);
00310       }
00311       std::ostringstream os;
00312       os << "Failed to get number of rows from line " << lineNumber 
00313          << " of input; the line should contain the coordinate matrix "
00314          << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00315       throw std::invalid_argument(os.str());
00316     }
00317     else { // Capture the validly read result before checking for eof.
00318       dims[0] = theNumRows;
00319     }
00320   }
00321   // There should be two more things to read.
00322   if (istr.eof()) {
00323     if (tolerant) {
00324       return std::make_pair (dims, false);
00325     }
00326     std::ostringstream os;
00327     os << "No more data after number of rows on line " << lineNumber
00328        << " of input; the line should contain the coordinate matrix "
00329        << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00330     throw std::invalid_argument(os.str());
00331   }
00332   // Read in <numCols>
00333   {
00334     Ordinal theNumCols = 0;
00335     istr >> theNumCols;
00336     if (istr.fail()) {
00337       if (tolerant) {
00338         return std::make_pair (dims, false);
00339       }
00340       std::ostringstream os;
00341       os << "Failed to get number of columns from line " << lineNumber 
00342          << " of input; the line should contain the coordinate matrix "
00343          << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00344       throw std::invalid_argument(os.str());
00345     }
00346     else { // Capture the validly read result before checking for eof.
00347       dims[1] = theNumCols;
00348     }
00349   }
00350   // There should be one more thing to read.
00351   if (istr.eof()) {
00352     if (tolerant) {
00353       return std::make_pair (dims, false);
00354     }
00355     std::ostringstream os;
00356     os << "No more data after number of columns on line " << lineNumber
00357        << " of input; the line should contain the coordinate matrix "
00358        << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00359     throw std::invalid_argument(os.str());
00360   }
00361   // Read in <numNonzeros>
00362   {
00363     Ordinal theNumNonzeros = 0;
00364     istr >> theNumNonzeros;
00365     if (istr.fail()) {
00366       if (tolerant) {
00367         return std::make_pair (dims, false);
00368       }
00369       std::ostringstream os;
00370       os << "Failed to get number of (structural) nonzeros from line " 
00371          << lineNumber 
00372          << " of input; the line should contain the coordinate matrix "
00373          << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00374       throw std::invalid_argument(os.str());
00375     }
00376     else { // Capture the validly read result
00377       dims[2] = theNumNonzeros;
00378     }
00379   }
00380   // It would be nice to validate the read-in data further.  The
00381   // only thing we can do now is test if it's negative.  However,
00382   // we don't know syntactically whether Ordinal is a signed or
00383   // unsigned type, so we shouldn't even test for negativity.
00384   return std::make_pair (dims, true);
00385       }
00386     };
00387 
00395     template<class Callback, 
00396        class Ordinal, 
00397        class Scalar, 
00398        bool isComplex = ScalarTraits<Scalar>::isComplex>
00399     class CoordDataReader : public CoordDataReaderBase<Callback, Ordinal> {
00400     public:
00401       CoordDataReader (const RCP<Callback>& adder);
00402       CoordDataReader ();
00403 
00405       virtual ~CoordDataReader();
00406 
00407     protected:
00408       bool
00409       readLine (const std::string& theLine, 
00410     const size_t lineNumber,
00411     const bool tolerant);
00412     };
00413 
00414 #ifdef HAVE_TEUCHOS_COMPLEX
00415     // Specialization for complex Scalar types.
00416     template<class Callback, class Ordinal, class Scalar>
00417     class CoordDataReader<Callback, Ordinal, Scalar, true> : 
00418       public CoordDataReaderBase<Callback, Ordinal> {
00419     public:
00420       CoordDataReader (const RCP<Callback>& adder) :
00421   CoordDataReaderBase<Callback, Ordinal> (adder)
00422       {}
00423 
00424       CoordDataReader() : 
00425   CoordDataReaderBase<Callback, Ordinal> (null)
00426       {}
00427 
00429       virtual ~CoordDataReader() {};
00430 
00431     protected:
00432       bool
00433       readLine (const std::string& theLine, 
00434     const size_t lineNumber,
00435     const bool tolerant)
00436       {
00437   typedef ScalarTraits<Scalar> STS;
00438   typedef typename STS::magnitudeType Real;
00439 
00440   Ordinal rowIndex;
00441   Ordinal colIndex;
00442   Scalar value;
00443 
00444   Real realPart, imagPart;
00445   const bool localSuccess = 
00446     readComplexLine (theLine, rowIndex, colIndex, realPart, imagPart,
00447          lineNumber, tolerant);
00448   if (localSuccess) {
00449     // Assume that assignment from std::complex<Real> to Scalar
00450     // (which itself is complex-valued) is valid.  We have to do
00451     // this, since the C++ compiler may not be smart enough to
00452     // assume here (when it instantiates the templates) that
00453     // Scalar is an std::complex<Real> -- even though it has to
00454     // be, if STS::isComplex is true (which as of 31 Jan 2011,
00455     // only holds for std::complex<T>).
00456     value = std::complex<Real> (realPart, imagPart);
00457 
00458     // Now that we've read in the (i, j, A_ij) triple
00459     // successfully, we can add the entry to the sparse matrix.
00460     (*(this->adder_)) (rowIndex, colIndex, value);
00461   }
00462   return localSuccess;
00463       }
00464     };
00465 #endif // HAVE_TEUCHOS_COMPLEX
00466 
00467     // Specialization for real Scalar types.
00468     template<class Callback, class Ordinal, class Scalar>
00469     class CoordDataReader<Callback, Ordinal, Scalar, false> : 
00470       public CoordDataReaderBase<Callback, Ordinal> {
00471     public:
00472       CoordDataReader (const RCP<Callback>& adder) :
00473   CoordDataReaderBase<Callback, Ordinal> (adder)
00474       {}
00475 
00476       CoordDataReader() : 
00477   CoordDataReaderBase<Callback, Ordinal> (null)
00478       {}
00479 
00481       virtual ~CoordDataReader() {};
00482 
00483     protected:
00484       bool
00485       readLine (const std::string& theLine, 
00486     const size_t lineNumber,
00487     const bool tolerant)
00488       {
00489   Ordinal rowIndex;
00490   Ordinal colIndex;
00491   Scalar value;
00492   const bool localSuccess = readRealLine (theLine, rowIndex, colIndex, 
00493             value, lineNumber, tolerant);
00494   if (localSuccess) {
00495     // Now that we've read in the (i, j, A_ij) triple
00496     // successfully, we can add the entry to the sparse matrix.
00497     (*(this->adder_)) (rowIndex, colIndex, value);
00498   }
00499   return localSuccess;
00500       }
00501     };
00502 
00503 
00518     template<class Callback, class Ordinal>
00519     class CoordPatternReader : public CoordDataReaderBase<Callback, Ordinal> {
00520     public:
00522       CoordPatternReader (const RCP<Callback>& adder) :
00523   CoordDataReaderBase<Callback, Ordinal> (adder)
00524       {}
00525 
00527       CoordPatternReader() : 
00528   CoordDataReaderBase<Callback, Ordinal> (null)
00529       {}
00530 
00532       virtual ~CoordPatternReader() {};
00533 
00534     protected:
00535       bool
00536       readLine (const std::string& theLine, 
00537     const size_t lineNumber,
00538     const bool tolerant)
00539       {
00540   Ordinal rowIndex;
00541   Ordinal colIndex;
00542   const bool localSuccess = 
00543     readPatternLine (theLine, rowIndex, colIndex, lineNumber, tolerant);
00544   if (localSuccess) {
00545     // Now that we've read in the (i, j) pair successfully, we
00546     // can add the entry to the sparse graph.
00547     (*(this->adder_)) (rowIndex, colIndex);
00548   }
00549   return localSuccess;
00550       }
00551     };
00552 
00553   } // namespace MatrixMarket
00554 } // namespace Tpetra
00555 
00556 #endif // __MatrixMarket_CoordDataReader_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines