Teuchos Package Browser (Single Doxygen Collection) Version of the Day
MatrixMarket_Raw_InOutTest.cpp
Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
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 #include <Teuchos_MatrixMarket_Raw_Checker.hpp>
00043 #include <Teuchos_MatrixMarket_Raw_Reader.hpp>
00044 #include <Teuchos_MatrixMarket_Raw_Writer.hpp>
00045 #include <Teuchos_MatrixMarket_SetScientific.hpp>
00046 #include <Teuchos_CommandLineProcessor.hpp>
00047 #include <Teuchos_GlobalMPISession.hpp>
00048 #include <Teuchos_oblackholestream.hpp>
00049 #include <Teuchos_DefaultSerialComm.hpp>
00050 #include <algorithm>
00051 
00052 using std::endl;
00053 
00054 namespace {
00055   // Sample Matrix Market sparse matrix file.  We include this so we
00056   // can test without needing to read in a file.  Notice that all the
00057   // decimal floating-point values in this example can be represented
00058   // exactly in binary floating point.  This example has correct
00059   // syntax, so you won't need to use tolerant mode to parse it.
00060   const char sampleMatrixMarketFile[] =
00061     "%%MatrixMarket matrix coordinate real general\n"
00062     "5 5 10\n"
00063     "5 5 55.0\n"
00064     "4 4 44.0\n"
00065     "3 3 33.0\n"
00066     "2 2 22.0\n"
00067     "1 1 11.0\n"
00068     "4 5 45.0\n"
00069     "3 4 34.0\n"
00070     "2 3 23.0\n"
00071     "1 2 12.0\n"
00072     "1 5 15.0\n";
00073 
00074   // Sample Matrix Market sparse matrix file for testing symmetric
00075   // storage.  Matrix Market format for symmetric, skew-symemtric,
00076   // etc. specifies that only the lower triangle should be stored.
00077   const char symmetricMatrixMarketFile[] =
00078     "%%MatrixMarket matrix coordinate real symmetric\n"
00079     "5 5 10\n"
00080     "5 5 55.0\n"
00081     "4 4 44.0\n"
00082     "3 3 33.0\n"
00083     "2 2 22.0\n"
00084     "1 1 11.0\n"
00085     "5 4 54.0\n"
00086     "4 3 43.0\n"
00087     "3 2 32.0\n"
00088     "2 1 21.0\n"
00089     "5 1 51.0\n";
00090 
00091 } // namespace (anonymous)
00092 
00093 // Benchmark driver
00094 int
00095 main (int argc, char *argv[])
00096 {
00097   using Teuchos::MatrixMarket::Raw::Checker;
00098   using Teuchos::MatrixMarket::Raw::Reader;
00099   using Teuchos::ArrayRCP;
00100   using Teuchos::ArrayView;
00101   using Teuchos::Comm;
00102   using Teuchos::CommandLineProcessor;
00103   using Teuchos::ParameterList;
00104   using Teuchos::RCP;
00105   using Teuchos::rcp;
00106   using Teuchos::rcpFromRef;
00107   using Teuchos::SerialComm;
00108   using std::cout;
00109   using std::cerr;
00110   typedef double scalar_type;
00111   typedef int ordinal_type;
00112 
00113   // Name of the Matrix Market sparse matrix file to read.  If empty,
00114   // use the Matrix Market example embedded as a string in this file.
00115   std::string filename;
00116   // If true, just check the sparse matrix file.  Otherwise,
00117   // do a full conversion to CSR (compressed sparse row) format.
00118   bool checkOnly = false;
00119   // Whether to echo the sparse matrix to stdout after reading it
00120   // successfully.
00121   bool echo = false;
00122   // Whether to parse the Matrix Market file tolerantly.
00123   bool tolerant = false;
00124   // Verbosity of output
00125   bool verbose = false;
00126   // Whether to print debugging-level output
00127   bool debug = false;
00128 
00129   CommandLineProcessor cmdp (false, true);
00130   cmdp.setOption ("filename", &filename,
00131                   "Name of the Matrix Market sparse matrix file to read.");
00132   cmdp.setOption ("checkOnly", "fullTest", &checkOnly,
00133                   "If true, just check the syntax of the input file.  "
00134                   "Otherwise, do a full test.");
00135   cmdp.setOption ("echo", "noecho", &echo,
00136                   "Whether to echo the sparse matrix contents to stdout "
00137                   "after reading it successfully.");
00138   cmdp.setOption ("tolerant", "strict", &tolerant,
00139                   "Whether to tolerate syntax errors in the Matrix Market file.");
00140   cmdp.setOption ("verbose", "quiet", &verbose,
00141                   "Print status output to stdout.");
00142   cmdp.setOption ("debug", "nodebug", &debug,
00143                   "Print possibly copious debugging output to stderr.");
00144   // Parse the command-line arguments.
00145   {
00146     const CommandLineProcessor::EParseCommandLineReturn parseResult =
00147       cmdp.parse (argc,argv);
00148     // If the caller asks us to print the documentation, or does not
00149     // explicitly say to run the benchmark, we let this "test" pass
00150     // trivially.
00151     if (parseResult == CommandLineProcessor::PARSE_HELP_PRINTED) {
00152       std::cout << "End Result: TEST PASSED" << endl;
00153       return EXIT_SUCCESS;
00154     }
00155     TEUCHOS_TEST_FOR_EXCEPTION(
00156        parseResult != CommandLineProcessor::PARSE_SUCCESSFUL,
00157        std::invalid_argument, "Failed to parse command-line arguments.");
00158   }
00159 
00160   // Test reading in the sparse matrix.  If no filename or an empty
00161   // filename is specified, the test passes trivially.
00162   bool success = true;
00163   if (checkOnly) {
00164     typedef Checker<scalar_type, ordinal_type> checker_type;
00165     checker_type checker (echo, tolerant, debug);
00166 
00167     RCP<const Comm<int> > comm = rcp (new SerialComm<int>);
00168     if (filename != "") {
00169       if (verbose) {
00170         cout << "Checking syntax of the Matrix Market file \"" << filename
00171              << "\"" << endl;
00172       }
00173       success = success && checker.readFile (*comm, filename);
00174       if (verbose) {
00175         if (success) {
00176           cout << "The given file is a valid Matrix Market file." << endl;
00177         }
00178         else {
00179           cout << "The given file has syntax errors." << endl;
00180         }
00181       }
00182     }
00183     else {
00184       if (verbose) {
00185         cout << "Checking syntax of the first built-in Matrix Market example" << endl
00186              << std::flush;// for debug output next
00187       }
00188       if (debug) {
00189         cerr << "First built-in Matrix Market example: " << endl
00190              << sampleMatrixMarketFile << endl;
00191       }
00192       std::istringstream in (sampleMatrixMarketFile);
00193       RCP<std::istream> inStream = rcpFromRef (in);
00194       success = success && checker.read (*comm, inStream);
00195       if (verbose) {
00196         if (success) {
00197           cout << "The example has valid Matrix Market syntax." << endl;
00198         }
00199         else {
00200           cout << "The example has syntax errors." << endl;
00201         }
00202       }
00203     }
00204   }
00205   else {
00206     typedef Reader<scalar_type, ordinal_type> reader_type;
00207     reader_type reader (tolerant, debug);
00208     ArrayRCP<ordinal_type> ptr, ind;
00209     ArrayRCP<scalar_type> val;
00210     ordinal_type numRows, numCols;
00211     //
00212     // Read the Matrix Market data, either from a file or from a
00213     // built-in string.
00214     //
00215     if (filename != "") {
00216       if (verbose) {
00217         cout << "Reading the Matrix Market file \"" << filename << "\"" << endl;
00218       }
00219       success = success && reader.readFile (ptr, ind, val,
00220                                             numRows, numCols, filename);
00221     }
00222     else {
00223       if (verbose) {
00224         cout << "Reading the first built-in Matrix Market example" << endl;
00225       }
00226       if (debug) {
00227         cerr << "First built-in Matrix Market example:" << endl
00228              << sampleMatrixMarketFile << endl;
00229       }
00230       std::istringstream inStr (sampleMatrixMarketFile);
00231       success = success && reader.read (ptr, ind, val, numRows, numCols, inStr);
00232     }
00233     TEUCHOS_TEST_FOR_EXCEPTION(! success, std::runtime_error, "Matrix Market "
00234       "reader failed to read the given file or input stream.");
00235     if (success && verbose) {
00236       cout << "Returned from reading the Matrix Market data" << endl
00237            << std::flush; // for following debug output
00238     }
00239     if (debug) {
00240       cerr << "CSR output info:" << endl
00241            << "  ptr.size() = " << ptr.size()
00242            << ", ind.size() = " << ind.size()
00243            << ", val.size() = " << val.size()
00244            << ", numRows = " << numRows
00245            << ", numCols = " << numCols
00246            << endl;
00247     }
00248 
00249     // Here's the fun part.  Output the CSR data to an output stream.
00250     // Then read in the output stream.  The resulting matrix should be
00251     // exactly the same (unless the original file had elements at the
00252     // same location that were added together with rounding error).
00253     // This is a test for both Writer and Reader.
00254     std::ostringstream outStr;
00255     if (success && verbose) {
00256       cout << "Printing the CSR arrays to a Matrix Market output stream"
00257            << endl << std::flush;
00258     }
00259     Teuchos::MatrixMarket::Raw::Writer<scalar_type, ordinal_type> writer;
00260     writer.write (outStr, ptr (), ind (), val (), numRows, numCols);
00261 
00262     if (debug && echo) {
00263       cerr << "CSR data:" << endl
00264            << "- ptr = [";
00265       for (ordinal_type i = 0; i < ptr.size(); ++i) {
00266         cerr << ptr[i];
00267         if (i+1 != ptr.size()) { // don't subtract from zero if unsigned
00268           cerr << ", ";
00269         }
00270       }
00271       cerr << "]" << endl
00272            << "- ind = [";
00273       for (ordinal_type i = 0; i < ind.size(); ++i) {
00274         cerr << ind[i];
00275         if (i+1 != ind.size()) { // don't subtract from zero if unsigned
00276           cerr << ", ";
00277         }
00278       }
00279       cerr << "]" << endl
00280            << "- val = [";
00281       for (ordinal_type i = 0; i < val.size(); ++i) {
00282         cerr << val[i];
00283         if (i+1 != val.size()) { // don't subtract from zero if unsigned
00284           cerr << ", ";
00285         }
00286       }
00287       cerr << "]" << endl;
00288 
00289       cerr << "CSR data, converted back to Matrix Market format" << endl;
00290       writer.write (cerr, ptr (), ind (), val (), numRows, numCols);
00291       cerr << endl;
00292     }
00293 
00294     ArrayRCP<ordinal_type> newptr, newind;
00295     ArrayRCP<scalar_type> newval;
00296     ordinal_type newNumRows, newNumCols;
00297     if (success && verbose) {
00298       cout << "Reading the Matrix Market output back into CSR arrays" << endl;
00299     }
00300     {
00301       std::istringstream inStr (outStr.str ());
00302       success = success && reader.read (newptr, newind, newval,
00303                                         newNumRows, newNumCols, inStr);
00304     }
00305     TEUCHOS_TEST_FOR_EXCEPTION(! success, std::logic_error, "Matrix Market "
00306       "reader failed to read the output back into CSR arrays.");
00307     if (success && verbose) {
00308       cout << "Successfully read the Matrix Market output back into CSR arrays"
00309            << endl << std::flush;
00310     }
00311     if (debug) {
00312       cerr << "CSR output info:" << endl
00313            << "  newptr.size() = " << newptr.size()
00314            << ", newind.size() = " << newind.size()
00315            << ", newval.size() = " << newval.size()
00316            << ", newNumRows = " << newNumRows
00317            << ", newNumCols = " << newNumCols
00318            << endl;
00319     }
00320 
00321     // The old arrays should equal the new arrays.
00322     TEUCHOS_TEST_FOR_EXCEPTION(ptr.size () != newptr.size (), std::logic_error,
00323       "New ptr array has a different length than old ptr array");
00324     TEUCHOS_TEST_FOR_EXCEPTION(ind.size () != newind.size (), std::logic_error,
00325       "New ind array has a different length than old ind array");
00326     TEUCHOS_TEST_FOR_EXCEPTION(val.size () != newval.size (), std::logic_error,
00327       "New val array has a different length than old val array");
00328     TEUCHOS_TEST_FOR_EXCEPTION(newNumRows != numRows || newNumCols != numCols,
00329       std::logic_error, "New dimensions differ from old dimensions");
00330     TEUCHOS_TEST_FOR_EXCEPTION(ptr.size () != numRows+1, std::logic_error,
00331       "ptr.size() != numRows+1");
00332     TEUCHOS_TEST_FOR_EXCEPTION(newptr.size () != newNumRows+1, std::logic_error,
00333       "newptr.size() != newNumRows+1");
00334 
00335     for (ordinal_type rowIndex = 0; rowIndex < numRows; ++rowIndex) {
00336       TEUCHOS_TEST_FOR_EXCEPTION(ptr[rowIndex] != newptr[rowIndex],
00337         std::logic_error, "At row index " << rowIndex << ", ptr[rowIndex] = "
00338         << ptr[rowIndex] << " != newptr[rowIndex] = " << newptr[rowIndex]
00339         << ".");
00340       TEUCHOS_TEST_FOR_EXCEPTION(ptr[rowIndex+1] != newptr[rowIndex+1],
00341         std::logic_error, "At row index " << rowIndex << ", ptr[rowIndex+1] = "
00342         << ptr[rowIndex+1] << " != newptr[rowIndex+1] = " << newptr[rowIndex+1]
00343         << ".");
00344       for (ordinal_type k = ptr[rowIndex]; k < ptr[rowIndex+1]; ++k) {
00345         TEUCHOS_TEST_FOR_EXCEPTION(ind[k] != newind[k], std::logic_error,
00346           "At row index " << rowIndex << ", ind[k=" << k << "] = "
00347           << ind[k] << " != newind[k] = " << newind[k] << ".");
00348         // You may want to relax this inequality if the original
00349         // Matrix Market file had multiple entries at the same
00350         // location and if adding them together resulted in rounding
00351         // error.
00352         TEUCHOS_TEST_FOR_EXCEPTION(val[k] != newval[k], std::logic_error,
00353           "At row index " << rowIndex << ", val[k=" << k << "] = "
00354           << val[k] << " != newval[k] = " << newval[k] << ".");
00355       }
00356     }
00357 
00358     // Now test reading symmetric data, if no filename was specified.
00359     if (filename == "") {
00360       std::istringstream inStr (symmetricMatrixMarketFile);
00361       success = success && reader.read (ptr, ind, val, numRows, numCols, inStr);
00362       TEUCHOS_TEST_FOR_EXCEPTION(! success, std::logic_error,
00363         "Matrix Market reader failed to read the given example string.");
00364       if (success && verbose) {
00365         cout << "Returned from reading the Matrix Market data" << endl
00366              << std::flush; // for following debug output
00367       }
00368       if (debug) {
00369         cerr << "CSR output info:" << endl
00370              << "  ptr.size() = " << ptr.size()
00371              << ", ind.size() = " << ind.size()
00372              << ", val.size() = " << val.size()
00373              << ", numRows = " << numRows
00374              << ", numCols = " << numCols
00375              << endl;
00376       }
00377 
00378       // This is a bit of a hack, since we know the contents of the
00379       // example.  Since we "symmetrize" when reading in symmetric
00380       // data, there should be 15 entries in the resulting matrix.
00381       const ordinal_type correctNumEntries = 15;
00382       TEUCHOS_TEST_FOR_EXCEPTION(
00383         val.size() != correctNumEntries,
00384         std::logic_error,
00385         "Incorrect number of entries after symmetrization: There should be "
00386         << correctNumEntries << ", but there are " << val.size() << " entries "
00387         "instead.");
00388     }
00389   } // end of the file / string Reader tests
00390 
00391   if (success) {
00392     std::cout << "End Result: TEST PASSED" << endl;
00393     return EXIT_SUCCESS;
00394   }
00395   else {
00396     std::cout << "End Result: TEST FAILED" << endl;
00397     return EXIT_FAILURE;
00398   }
00399 }
00400 
00401 
00402 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines