|
Teuchos - Trilinos Tools Package
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 __Teuchos_MatrixMarket_Raw_Checker_hpp 00043 #define __Teuchos_MatrixMarket_Raw_Checker_hpp 00044 00045 #include "Teuchos_MatrixMarket_Raw_Adder.hpp" 00046 #include "Teuchos_MatrixMarket_SymmetrizingAdder.hpp" 00047 #include "Teuchos_MatrixMarket_CoordDataReader.hpp" 00048 00049 00050 namespace Teuchos { 00051 namespace MatrixMarket { 00052 namespace Raw { 00067 template<class Scalar, class Ordinal> 00068 class Checker { 00069 public: 00079 Checker (const bool echo, const bool tolerant, const bool debug) : 00080 echo_ (echo), tolerant_ (tolerant), debug_ (debug) 00081 {} 00082 00084 Checker () : 00085 echo_ (false), tolerant_ (false), debug_ (false) 00086 {} 00087 00098 Checker (const RCP<ParameterList>& params) : 00099 echo_ (false), tolerant_ (false), debug_ (false) 00100 { 00101 setParameters (params); 00102 } 00103 00107 void 00108 setParameters (const RCP<ParameterList>& params) 00109 { 00110 // Default parameter values. 00111 bool echo = false; 00112 bool tolerant = false; 00113 bool debug = false; 00114 00115 // Read parameters. 00116 echo = params->get ("Echo to stdout", echo); 00117 tolerant = params->get ("Parse tolerantly", tolerant); 00118 debug = params->get ("Debug mode", debug); 00119 00120 // No side effects on the class until ParameterList 00121 // processing is complete. 00122 echo_ = echo; 00123 tolerant_ = tolerant; 00124 debug_ = debug; 00125 } 00126 00127 RCP<const ParameterList> 00128 getValidParameters () const 00129 { 00130 // Default parameter values. 00131 const bool echo = false; 00132 const bool tolerant = false; 00133 const bool debug = false; 00134 00135 // Set default parameters with documentation. 00136 RCP<ParameterList> params = parameterList ("Matrix Market Checker"); 00137 params->set ("Echo to stdout", echo, "Whether to echo the sparse " 00138 "matrix to stdout after reading it"); 00139 params->set ("Parse tolerantly", tolerant, "Whether to tolerate " 00140 "syntax errors when parsing the Matrix Market file"); 00141 params->set ("Debug mode", debug, "Whether to print debugging output " 00142 "to stderr, on all participating MPI processes"); 00143 00144 return rcp_const_cast<const ParameterList> (params); 00145 } 00146 00157 bool 00158 readFile (const Teuchos::Comm<int>& comm, 00159 const std::string& filename) 00160 { 00161 using std::cerr; 00162 using std::endl; 00163 00164 const int myRank = comm.getRank (); 00165 // Teuchos::broadcast doesn't accept a bool; we use an int 00166 // instead, with the usual 1->true, 0->false Boolean 00167 // interpretation. 00168 int didReadFile = 0; 00169 RCP<std::ifstream> in; // only valid on Rank 0 00170 if (myRank == 0) { 00171 if (debug_) { 00172 cerr << "Attempting to open file \"" << filename 00173 << "\" on Rank 0..."; 00174 } 00175 in = rcp (new std::ifstream (filename.c_str())); 00176 if (! *in) { 00177 didReadFile = 0; 00178 if (debug_) { 00179 cerr << "failed." << endl; 00180 } 00181 } 00182 else { 00183 didReadFile = 1; 00184 if (debug_) { 00185 cerr << "succeeded." << endl; 00186 } 00187 } 00188 } 00189 Teuchos::broadcast (comm, 0, &didReadFile); 00190 // All MPI processes should throw at the same time, or none. 00191 TEUCHOS_TEST_FOR_EXCEPTION(! didReadFile, std::runtime_error, 00192 "Failed to open input file \"" + filename + "\"."); 00193 // Only Rank 0 will try to dereference "in". 00194 return read (comm, in); 00195 } 00196 00207 bool 00208 read (const Teuchos::Comm<int>& comm, 00209 const RCP<std::istream>& in) 00210 { 00211 using std::cerr; 00212 using std::endl; 00213 00214 const int myRank = comm.getRank (); 00215 std::pair<bool, std::string> result; 00216 int msgSize = 0; // Size of error message (if any) 00217 if (myRank == 0) { 00218 if (in.is_null()) { 00219 result.first = false; 00220 result.second = "Input stream is null on Rank 0"; 00221 } 00222 else { 00223 if (debug_) { 00224 cerr << "About to read from input stream on Rank 0" << endl; 00225 } 00226 result = readOnRank0 (*in); 00227 if (debug_) { 00228 if (result.first) { 00229 cerr << "Successfully read sparse matrix from " 00230 "input stream on Rank 0" << endl; 00231 } 00232 else { 00233 cerr << "Failed to read sparse matrix from input " 00234 "stream on Rank 0" << endl; 00235 } 00236 } 00237 } 00238 if (result.first) { 00239 msgSize = 0; 00240 } 00241 else { 00242 msgSize = result.second.size(); 00243 } 00244 } 00245 int success = result.first ? 1 : 0; 00246 Teuchos::broadcast (comm, 0, &success); 00247 if (! success) { 00248 if (! tolerant_) { 00249 // Tell all ranks how long the error message is, so 00250 // they can make space for it in order to receive 00251 // the broadcast of the error message. 00252 Teuchos::broadcast (comm, 0, &msgSize); 00253 00254 if (msgSize > 0) { 00255 std::string errMsg (msgSize, ' '); 00256 if (myRank == 0) { 00257 std::copy (result.second.begin(), result.second.end(), 00258 errMsg.begin()); 00259 } 00260 Teuchos::broadcast (comm, 0, static_cast<int> (msgSize), &errMsg[0]); 00261 TEUCHOS_TEST_FOR_EXCEPTION(! success, std::runtime_error, errMsg); 00262 } 00263 else { 00264 TEUCHOS_TEST_FOR_EXCEPTION(! success, std::runtime_error, 00265 "Unknown error when reading Matrix Market sparse matrix file; " 00266 "the error is \"unknown\" because the error message has length 0."); 00267 } 00268 } 00269 else if (myRank == 0) { 00270 using std::cerr; 00271 using std::endl; 00272 cerr << "The following error occurred when reading the " 00273 "sparse matrix: " << result.second << endl; 00274 } 00275 } 00276 return success; 00277 } 00278 00279 private: 00281 bool echo_; 00283 bool tolerant_; 00285 bool debug_; 00286 00301 RCP<const Teuchos::MatrixMarket::Banner> 00302 readBanner (std::istream& in, size_t& lineNumber) 00303 { 00304 using std::cerr; 00305 using std::endl; 00306 std::string line; // The presumed banner line 00307 00308 // The first line of the Matrix Market file should always be 00309 // the banner line. In tolerant mode, we allow comment 00310 // lines before the banner line. This complicates detection 00311 // of comment lines a bit. 00312 if (tolerant_) { 00313 // Keep reading lines until we get a noncomment line. 00314 const bool maybeBannerLine = true; 00315 size_t numLinesRead = 0; 00316 bool commentLine = false; 00317 do { 00318 // Try to read a line from the input stream. 00319 const bool readFailed = ! getline (in, line); 00320 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument, 00321 "Failed to get Matrix Market banner line from input, after reading " 00322 << numLinesRead << "line" << (numLinesRead != 1 ? "s." : ".")); 00323 // We read a line from the input stream. 00324 ++lineNumber; 00325 ++numLinesRead; 00326 size_t start, size; // Output args of checkCommentLine 00327 commentLine = checkCommentLine (line, start, size, lineNumber, 00328 tolerant_, maybeBannerLine); 00329 } while (commentLine); // Loop until we find a noncomment line. 00330 } 00331 else { 00332 const bool readFailed = ! getline (in, line); 00333 TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument, 00334 "Failed to get Matrix Market banner line from input. This " 00335 "probably means that the file is empty (contains zero lines)."); 00336 } 00337 00338 if (debug_) { 00339 cerr << "Raw::Checker::readBanner: Here is the presumed banner line:" 00340 << endl << line << endl; 00341 } 00342 00343 // Assume that the noncomment line we found is the banner line. 00344 RCP<Banner> banner; 00345 try { 00346 banner = rcp (new Banner (line, tolerant_)); 00347 } catch (std::exception& e) { 00348 TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, 00349 "Matrix Market file's banner line contains syntax error(s): " 00350 << e.what ()); 00351 } 00352 return rcp_const_cast<const Banner> (banner); 00353 } 00354 00364 std::pair<bool, std::string> 00365 readOnRank0 (std::istream& in) 00366 { 00367 using std::cerr; 00368 using std::cout; 00369 using std::endl; 00370 typedef ScalarTraits<Scalar> STS; 00371 00372 // This "Adder" knows how to add sparse matrix entries, 00373 // given a line of data from the file. It also stores the 00374 // entries and can sort them. 00375 typedef Adder<Scalar, Ordinal> raw_adder_type; 00376 // SymmetrizingAdder "advices" (yes, I'm using that as a verb) 00377 // the original Adder, so that additional entries are filled 00378 // in symmetrically, if the Matrix Market banner line 00379 // specified a symmetry type other than "general". 00380 typedef SymmetrizingAdder<raw_adder_type> adder_type; 00381 00382 // Current line number of the input stream. 00383 size_t lineNumber = 1; 00384 00385 // Construct the "Banner" (matrix metadata, including type 00386 // and symmetry information, but not dimensions). 00387 std::ostringstream err; 00388 RCP<const Banner> pBanner; 00389 try { 00390 pBanner = readBanner (in, lineNumber); 00391 } 00392 catch (std::exception& e) { 00393 err << "Failed to read Matrix Market file's Banner: " << e.what(); 00394 return std::make_pair (false, err.str()); 00395 } 00396 // 00397 // Validate the metadata in the Banner. 00398 // 00399 if (pBanner->matrixType () != "coordinate") { 00400 err << "Matrix Market input file must contain a \"coordinate\"-" 00401 "format sparse matrix in order to create a sparse matrix object " 00402 "from it."; 00403 return std::make_pair (false, err.str ()); 00404 } 00405 else if (! STS::isComplex && pBanner->dataType () == "complex") { 00406 err << "The Matrix Market sparse matrix file contains complex-" 00407 "valued data, but you are try to read the data into a sparse " 00408 "matrix containing real values (your matrix's Scalar type is " 00409 "real)."; 00410 return std::make_pair (false, err.str ()); 00411 } 00412 else if (pBanner->dataType () != "real" && 00413 pBanner->dataType () != "complex") { 00414 err << "Only real or complex data types (no pattern or integer " 00415 "matrices) are currently supported."; 00416 return std::make_pair (false, err.str ()); 00417 } 00418 if (debug_) { 00419 cerr << "Banner line:" << endl << *pBanner << endl; 00420 } 00421 00422 // The reader will invoke the adder (see below) once for 00423 // each matrix entry it reads from the input stream. 00424 typedef CoordDataReader<adder_type, Ordinal, Scalar, 00425 STS::isComplex> reader_type; 00426 // We will set the adder below, after calling readDimensions(). 00427 reader_type reader; 00428 00429 // Read in the dimensions of the sparse matrix: (# rows, # 00430 // columns, # matrix entries (counting duplicates as 00431 // separate entries)). The second element of the pair tells 00432 // us whether the values were gotten successfully. 00433 std::pair<Tuple<Ordinal, 3>, bool> dims = 00434 reader.readDimensions (in, lineNumber, tolerant_); 00435 if (! dims.second) { 00436 err << "Error reading Matrix Market sparse matrix " 00437 "file: failed to read coordinate dimensions."; 00438 return std::make_pair (false, err.str ()); 00439 } 00440 // These are "expected" values read from the input stream's 00441 // metadata. The actual matrix entries read from the input 00442 // stream might not conform to their constraints. We allow 00443 // such nonconformity only in "tolerant" mode; otherwise, we 00444 // throw an exception. 00445 const Ordinal numRows = dims.first[0]; 00446 const Ordinal numCols = dims.first[1]; 00447 const Ordinal numEntries = dims.first[2]; 00448 if (debug_) { 00449 cerr << "Reported dimensions: " << numRows << " x " << numCols 00450 << ", with " << numEntries << " entries (counting possible " 00451 << "duplicates)." << endl; 00452 } 00453 00454 // The "raw" adder knows about the expected matrix 00455 // dimensions, but doesn't know about symmetry. 00456 RCP<raw_adder_type> rawAdder = 00457 rcp (new raw_adder_type (numRows, numCols, numEntries, 00458 tolerant_, debug_)); 00459 // The symmetrizing adder knows about symmetry. 00460 RCP<adder_type> adder = 00461 rcp (new adder_type (rawAdder, pBanner->symmType ())); 00462 00463 // Give the adder to the reader. 00464 reader.setAdder (adder); 00465 00466 // Read the sparse matrix entries. "results" just tells us if 00467 // and where there were any bad lines of input. The actual 00468 // sparse matrix entries are stored in the (raw) Adder object. 00469 std::pair<bool, std::vector<size_t> > results = 00470 reader.read (in, lineNumber, tolerant_, debug_); 00471 if (debug_) { 00472 if (results.first) { 00473 cerr << "Matrix Market file successfully read" << endl; 00474 } 00475 else { 00476 cerr << "Failed to read Matrix Market file" << endl; 00477 } 00478 } 00479 00480 // Report any bad line number(s). 00481 if (! results.first) { 00482 if (! tolerant_) { 00483 err << "The Matrix Market input stream had syntax error(s)." 00484 " Here is the error report." << endl; 00485 reportBadness (err, results); 00486 err << endl; 00487 return std::make_pair (false, err.str ()); 00488 } 00489 else { 00490 if (debug_) { 00491 reportBadness (cerr, results); 00492 } 00493 } 00494 } 00495 // We're done reading in the sparse matrix. If we're in 00496 // "echo" mode, print out the matrix entries to stdout. The 00497 // entries will have been symmetrized if applicable. 00498 if (echo_) { 00499 const bool doMerge = false; 00500 const bool replace = false; 00501 rawAdder->print (cout, doMerge, replace); 00502 cout << endl; 00503 } 00504 return std::make_pair (true, err.str()); 00505 } 00506 00508 void 00509 reportBadness (std::ostream& out, 00510 const std::pair<bool, std::vector<size_t> >& results) 00511 { 00512 using std::endl; 00513 const size_t numErrors = results.second.size(); 00514 const size_t maxNumErrorsToReport = 20; 00515 out << numErrors << " errors when reading Matrix Market sparse " 00516 "matrix file." << endl; 00517 if (numErrors > maxNumErrorsToReport) { 00518 out << "-- We do not report individual errors when there " 00519 "are more than " << maxNumErrorsToReport << "."; 00520 } 00521 else if (numErrors == 1) { 00522 out << "Error on line " << results.second[0] << endl; 00523 } 00524 else if (numErrors > 1) { 00525 out << "Errors on lines {"; 00526 for (size_t k = 0; k < numErrors-1; ++k) { 00527 out << results.second[k] << ", "; 00528 } 00529 out << results.second[numErrors-1] << "}" << endl; 00530 } 00531 } 00532 }; // end of class Checker 00533 } // namespace Raw 00534 } // namespace MatrixMarket 00535 } // namespace Teuchos 00536 00537 #endif // __Teuchos_MatrixMarket_Raw_Checker_hpp
1.7.6.1