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