Teuchos Package Browser (Single Doxygen Collection) Version of the Day
Teuchos_MatrixMarket_CoordDataReader.hpp
Go to the documentation of this file.
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_CoordDataReader_hpp
00043 #define __Teuchos_MatrixMarket_CoordDataReader_hpp
00044 
00045 #include "Teuchos_MatrixMarket_generic.hpp"
00046 #include "Teuchos_RCP.hpp"
00047 #include "Teuchos_ScalarTraits.hpp"
00048 #include "Teuchos_Tuple.hpp"
00049 
00050 
00051 namespace Teuchos {
00052   namespace MatrixMarket {
00099     template<class Callback, class Ordinal>
00100     class CoordDataReaderBase {
00101     protected:
00103       Teuchos::RCP<Callback> adder_;
00104 
00105     public:
00116       CoordDataReaderBase (const Teuchos::RCP<Callback>& adder) :
00117         adder_ (adder) {}
00118 
00126       CoordDataReaderBase () : adder_ (null) {}
00127 
00129       virtual ~CoordDataReaderBase () {}
00130 
00137       void setAdder (const Teuchos::RCP<Callback>& adder) {
00138         adder_ = adder;
00139       }
00140 
00141     protected:
00168       virtual bool
00169       readLine (const std::string& theLine,
00170                 const size_t lineNumber,
00171                 const bool tolerant) = 0;
00172 
00173     public:
00174 
00202       virtual std::pair<bool, std::vector<size_t> >
00203       read (std::istream& in,
00204             const size_t startingLineNumber,
00205             const bool tolerant,
00206             const bool debug = false)
00207       {
00208         (void) debug; // silence unused input argument warning
00209         TEUCHOS_TEST_FOR_EXCEPTION(! in, std::invalid_argument,
00210           "Input stream is invalid.");
00211 
00212         std::string line;
00213         size_t lineNumber = startingLineNumber;
00214         bool allSucceeded = true;
00215         std::vector<size_t> badLineNumbers;
00216         size_t validDataLines = 0;
00217         while (getline (in, line)) {
00218           size_t start, size;
00219           if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
00220             ++lineNumber;
00221             continue; // it's a comment line
00222           }
00223           const std::string theLine = line.substr (start, size);
00224 
00225           const bool localSuccess = readLine (theLine, lineNumber, tolerant);
00226           ++lineNumber;
00227           allSucceeded = allSucceeded && localSuccess;
00228           if (! localSuccess) {
00229             badLineNumbers.push_back (lineNumber);
00230           }
00231           else {
00232             ++validDataLines;
00233           }
00234         }
00235         return std::make_pair (allSucceeded, badLineNumbers);
00236       }
00237 
00261       std::pair<Teuchos::Tuple<Ordinal, 3>, bool>
00262       readDimensions (std::istream& in,
00263                       size_t& lineNumber,
00264                       const bool tolerant = false)
00265       {
00266         Teuchos::Tuple<Ordinal, 3> dims;
00267         // Fill in (numRows, numCols, numNonzeros) with reasonable
00268         // defaults.  If we don't succeed in reading all the data
00269         // from the current line of the input stream, the remaining
00270         // values not read will be these default values.
00271         dims[0] = 0;
00272         dims[1] = 0;
00273         dims[2] = 0;
00274 
00275         // Keep reading lines from the input stream until we find a
00276         // non-comment line, or until we run out of lines.  The latter
00277         // is an error, since every "coordinate" format Matrix Market
00278         // file must have a dimensions line after the banner (even if
00279         // the matrix has zero rows or columns, or zero entries).
00280         std::string line;
00281         bool commentLine = true;
00282         while (commentLine) {
00283           // Is it even valid to read from the input stream?
00284           if (in.eof() || in.fail()) {
00285             if (tolerant) {
00286               return std::make_pair (dims, false);
00287             }
00288             else {
00289               std::ostringstream os;
00290               os << "Unable to get coordinate dimensions line (at all) "
00291                 "from (line " << lineNumber << ") of input stream; the "
00292                 "input stream claims that it is at \"end-of-file\" or has "
00293                 "an otherwise \"fail\"ed state.";
00294               throw std::invalid_argument(os.str());
00295             }
00296           }
00297           // Try to get the next line from the input stream.
00298           if (getline(in, line)) {
00299             lineNumber++; // We did actually read a line
00300           }
00301           else {
00302             if (tolerant) {
00303               return std::make_pair (dims, false);
00304             }
00305             else {
00306               std::ostringstream os;
00307               os << "Failed to read coordinate dimensions line (at all) "
00308                 "from (line " << lineNumber << " from input stream.  The "
00309                 "line should contain the coordinate matrix dimensions in "
00310                  << " the form \"<numRows> <numCols> <numNonzeros>\".";
00311               throw std::invalid_argument (os.str());
00312             }
00313           }
00314           // Is the current line a comment line?  Ignore start and
00315           // size; they are only useful for reading the actual matrix
00316           // entries.  (We could use them here as an optimization, but
00317           // we've chosen not to.)
00318           size_t start = 0, size = 0;
00319           commentLine = checkCommentLine (line, start, size,
00320                                           lineNumber, tolerant);
00321         }
00322         //
00323         // Read in <numRows> <numCols> <numNonzeros> from input line
00324         //
00325         std::istringstream istr (line);
00326         // Does line contain anything at all?  Can we safely read from
00327         // the input stream wrapping the line?
00328         if (istr.eof() || istr.fail()) {
00329           if (tolerant) {
00330             return std::make_pair (dims, false);
00331           }
00332           std::ostringstream os;
00333           os << "Unable to read any data from line " << lineNumber
00334              << " of input; the line should contain the coordinate matrix "
00335              << "dimensions \"<numRows> <numCols> <numNonzeros>\".";
00336           throw std::invalid_argument(os.str());
00337         }
00338         // Read in <numRows>
00339         {
00340           Ordinal theNumRows = 0;
00341           istr >> theNumRows;
00342           if (istr.fail()) {
00343             if (tolerant) {
00344               return std::make_pair (dims, false);
00345             }
00346             std::ostringstream os;
00347             os << "Failed to get number of rows from line " << lineNumber
00348                << " of input; the line should contain the coordinate matrix "
00349                << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00350             throw std::invalid_argument(os.str());
00351           }
00352           else { // Capture the validly read result before checking for eof.
00353             dims[0] = theNumRows;
00354           }
00355         }
00356         // There should be two more things to read.
00357         if (istr.eof()) {
00358           if (tolerant) {
00359             return std::make_pair (dims, false);
00360           }
00361           std::ostringstream os;
00362           os << "No more data after number of rows on line " << lineNumber
00363              << " of input; the line should contain the coordinate matrix "
00364              << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00365           throw std::invalid_argument(os.str());
00366         }
00367         // Read in <numCols>
00368         {
00369           Ordinal theNumCols = 0;
00370           istr >> theNumCols;
00371           if (istr.fail()) {
00372             if (tolerant) {
00373               return std::make_pair (dims, false);
00374             }
00375             std::ostringstream os;
00376             os << "Failed to get number of columns from line " << lineNumber
00377                << " of input; the line should contain the coordinate matrix "
00378                << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00379             throw std::invalid_argument(os.str());
00380           }
00381           else { // Capture the validly read result before checking for eof.
00382             dims[1] = theNumCols;
00383           }
00384         }
00385         // There should be one more thing to read.
00386         if (istr.eof()) {
00387           if (tolerant) {
00388             return std::make_pair (dims, false);
00389           }
00390           std::ostringstream os;
00391           os << "No more data after number of columns on line " << lineNumber
00392              << " of input; the line should contain the coordinate matrix "
00393              << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00394           throw std::invalid_argument(os.str());
00395         }
00396         // Read in <numNonzeros>
00397         {
00398           Ordinal theNumNonzeros = 0;
00399           istr >> theNumNonzeros;
00400           if (istr.fail()) {
00401             if (tolerant) {
00402               return std::make_pair (dims, false);
00403             }
00404             std::ostringstream os;
00405             os << "Failed to get number of (structural) nonzeros from line "
00406                << lineNumber
00407                << " of input; the line should contain the coordinate matrix "
00408                << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
00409             throw std::invalid_argument(os.str());
00410           }
00411           else { // Capture the validly read result
00412             dims[2] = theNumNonzeros;
00413           }
00414         }
00415         // It would be nice to validate the read-in data further.  The
00416         // only thing we can do now is test if it's negative.  However,
00417         // we don't know syntactically whether Ordinal is a signed or
00418         // unsigned type, so we shouldn't even test for negativity.
00419         return std::make_pair (dims, true);
00420       }
00421     };
00422 
00457     template<class Callback,
00458              class Ordinal,
00459              class Scalar,
00460              bool isComplex = Teuchos::ScalarTraits<Scalar>::isComplex>
00461     class CoordDataReader : public CoordDataReaderBase<Callback, Ordinal> {
00462     public:
00475       CoordDataReader (const Teuchos::RCP<Callback>& adder);
00476 
00484       CoordDataReader ();
00485 
00487       virtual ~CoordDataReader();
00488 
00489     protected:
00490       bool
00491       readLine (const std::string& theLine,
00492                 const size_t lineNumber,
00493                 const bool tolerant);
00494     };
00495 
00496 #ifdef HAVE_TEUCHOS_COMPLEX
00497     // Partial specialization for complex Scalar types.
00498     template<class Callback, class Ordinal, class Scalar>
00499     class CoordDataReader<Callback, Ordinal, Scalar, true> :
00500       public CoordDataReaderBase<Callback, Ordinal> {
00501     public:
00502       CoordDataReader (const Teuchos::RCP<Callback>& adder) :
00503         CoordDataReaderBase<Callback, Ordinal> (adder)
00504       {}
00505 
00506       CoordDataReader() :
00507         CoordDataReaderBase<Callback, Ordinal> (null)
00508       {}
00509 
00510       virtual ~CoordDataReader() {};
00511 
00512     protected:
00513       bool
00514       readLine (const std::string& theLine,
00515                 const size_t lineNumber,
00516                 const bool tolerant)
00517       {
00518         typedef Teuchos::ScalarTraits<Scalar> STS;
00519         typedef typename STS::magnitudeType Real;
00520 
00521         Ordinal rowIndex;
00522         Ordinal colIndex;
00523         Scalar value;
00524 
00525         Real realPart, imagPart;
00526         const bool localSuccess =
00527           readComplexLine (theLine, rowIndex, colIndex, realPart, imagPart,
00528                            lineNumber, tolerant);
00529         if (localSuccess) {
00530           // Assume that assignment from std::complex<Real> to Scalar
00531           // (which itself is complex-valued) is valid.  We have to do
00532           // this, since the C++ compiler may not be smart enough to
00533           // assume here (when it instantiates the templates) that
00534           // Scalar is an std::complex<Real> -- even though it has to
00535           // be, if STS::isComplex is true (which as of 31 Jan 2011,
00536           // only holds for std::complex<T>).
00537           value = std::complex<Real> (realPart, imagPart);
00538 
00539           // Now that we've read in the (i, j, A_ij) triple
00540           // successfully, we can add the entry to the sparse matrix.
00541           (*(this->adder_)) (rowIndex, colIndex, value);
00542         }
00543         return localSuccess;
00544       }
00545     };
00546 #endif // HAVE_TEUCHOS_COMPLEX
00547 
00548     // Partial specialization for real Scalar types.
00549     template<class Callback, class Ordinal, class Scalar>
00550     class CoordDataReader<Callback, Ordinal, Scalar, false> :
00551       public CoordDataReaderBase<Callback, Ordinal> {
00552     public:
00553       CoordDataReader (const Teuchos::RCP<Callback>& adder) :
00554         CoordDataReaderBase<Callback, Ordinal> (adder)
00555       {}
00556 
00557       CoordDataReader() :
00558         CoordDataReaderBase<Callback, Ordinal> (null)
00559       {}
00560 
00561       virtual ~CoordDataReader() {};
00562 
00563     protected:
00564       bool
00565       readLine (const std::string& theLine,
00566                 const size_t lineNumber,
00567                 const bool tolerant)
00568       {
00569         Ordinal rowIndex;
00570         Ordinal colIndex;
00571         Scalar value;
00572         const bool localSuccess = readRealLine (theLine, rowIndex, colIndex,
00573                                                 value, lineNumber, tolerant);
00574         if (localSuccess) {
00575           // Now that we've read in the (i, j, A_ij) triple
00576           // successfully, we can add the entry to the sparse matrix.
00577           (*(this->adder_)) (rowIndex, colIndex, value);
00578         }
00579         return localSuccess;
00580       }
00581     };
00582 
00583 
00606     template<class Callback, class Ordinal>
00607     class CoordPatternReader : public CoordDataReaderBase<Callback, Ordinal> {
00608     public:
00621       CoordPatternReader (const Teuchos::RCP<Callback>& adder) :
00622         CoordDataReaderBase<Callback, Ordinal> (adder)
00623       {}
00624 
00632       CoordPatternReader() :
00633         CoordDataReaderBase<Callback, Ordinal> (null)
00634       {}
00635 
00637       virtual ~CoordPatternReader() {};
00638 
00639     protected:
00640       bool
00641       readLine (const std::string& theLine,
00642                 const size_t lineNumber,
00643                 const bool tolerant)
00644       {
00645         Ordinal rowIndex;
00646         Ordinal colIndex;
00647         const bool localSuccess =
00648           readPatternLine (theLine, rowIndex, colIndex, lineNumber, tolerant);
00649         if (localSuccess) {
00650           // Now that we've read in the (i, j) pair successfully, we
00651           // can add the entry to the sparse graph.
00652           (*(this->adder_)) (rowIndex, colIndex);
00653         }
00654         return localSuccess;
00655       }
00656     };
00657 
00658   } // namespace MatrixMarket
00659 } // namespace Teuchos
00660 
00661 #endif // __Teuchos_MatrixMarket_CoordDataReader_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines