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