|
Tpetra Matrix/Vector Services Version of the Day
|
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
1.7.4