Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MatrixMarket_Raw_InOutTest.cpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
50 #include <algorithm>
51 
52 using std::endl;
53 
54 namespace {
55  // Sample Matrix Market sparse matrix file. We include this so we
56  // can test without needing to read in a file. Notice that all the
57  // decimal floating-point values in this example can be represented
58  // exactly in binary floating point. This example has correct
59  // syntax, so you won't need to use tolerant mode to parse it.
60  const char sampleMatrixMarketFile[] =
61  "%%MatrixMarket matrix coordinate real general\n"
62  "5 5 10\n"
63  "5 5 55.0\n"
64  "4 4 44.0\n"
65  "3 3 33.0\n"
66  "2 2 22.0\n"
67  "1 1 11.0\n"
68  "4 5 45.0\n"
69  "3 4 34.0\n"
70  "2 3 23.0\n"
71  "1 2 12.0\n"
72  "1 5 15.0\n";
73 
74  // Sample Matrix Market sparse matrix file for testing symmetric
75  // storage. Matrix Market format for symmetric, skew-symemtric,
76  // etc. specifies that only the lower triangle should be stored.
77  const char symmetricMatrixMarketFile[] =
78  "%%MatrixMarket matrix coordinate real symmetric\n"
79  "5 5 10\n"
80  "5 5 55.0\n"
81  "4 4 44.0\n"
82  "3 3 33.0\n"
83  "2 2 22.0\n"
84  "1 1 11.0\n"
85  "5 4 54.0\n"
86  "4 3 43.0\n"
87  "3 2 32.0\n"
88  "2 1 21.0\n"
89  "5 1 51.0\n";
90 
91 } // namespace (anonymous)
92 
93 // Benchmark driver
94  int
95 main (int argc, char *argv[])
96 {
99  using Teuchos::ArrayRCP;
100  using Teuchos::ArrayView;
101  using Teuchos::Comm;
104  using Teuchos::RCP;
105  using Teuchos::rcp;
106  using Teuchos::rcpFromRef;
107  using Teuchos::SerialComm;
108  using std::cout;
109  using std::cerr;
110  typedef double scalar_type;
111  typedef int ordinal_type;
112 
113  bool success = false;
114  // Verbosity of output
115  bool verbose = true;
116  try {
117  // Name of the Matrix Market sparse matrix file to read. If empty,
118  // use the Matrix Market example embedded as a string in this file.
119  std::string filename;
120  // If true, just check the sparse matrix file. Otherwise,
121  // do a full conversion to CSR (compressed sparse row) format.
122  bool checkOnly = false;
123  // Whether to echo the sparse matrix to stdout after reading it
124  // successfully.
125  bool echo = false;
126  // Whether to parse the Matrix Market file tolerantly.
127  bool tolerant = false;
128  // Whether to print debugging-level output
129  bool debug = false;
130 
131  CommandLineProcessor cmdp (false, true);
132  cmdp.setOption ("filename", &filename,
133  "Name of the Matrix Market sparse matrix file to read.");
134  cmdp.setOption ("checkOnly", "fullTest", &checkOnly,
135  "If true, just check the syntax of the input file. "
136  "Otherwise, do a full test.");
137  cmdp.setOption ("echo", "noecho", &echo,
138  "Whether to echo the sparse matrix contents to stdout "
139  "after reading it successfully.");
140  cmdp.setOption ("tolerant", "strict", &tolerant,
141  "Whether to tolerate syntax errors in the Matrix Market file.");
142  cmdp.setOption ("verbose", "quiet", &verbose,
143  "Print status output to stdout.");
144  cmdp.setOption ("debug", "nodebug", &debug,
145  "Print possibly copious debugging output to stderr.");
146  // Parse the command-line arguments.
147  {
148  const CommandLineProcessor::EParseCommandLineReturn parseResult =
149  cmdp.parse (argc,argv);
150  // If the caller asks us to print the documentation, or does not
151  // explicitly say to run the benchmark, we let this "test" pass
152  // trivially.
153  if (parseResult == CommandLineProcessor::PARSE_HELP_PRINTED) {
154  std::cout << "End Result: TEST PASSED" << endl;
155  return EXIT_SUCCESS;
156  }
158  parseResult != CommandLineProcessor::PARSE_SUCCESSFUL,
159  std::invalid_argument, "Failed to parse command-line arguments.");
160  }
161 
162  // Test reading in the sparse matrix. If no filename or an empty
163  // filename is specified, the test passes trivially.
164  success = true;
165  {
166  // The following tests check reading in different banners. A bug was found
167  // in the banner reader wherein banners with multiple consecutive spaces
168  // were not read correctly. These tests assure that banners with or
169  // without multiple consecutive spaces/tabs are read correctly.
170  bool xs;
171  if (verbose) {
172  cout << "Checking MatrixMarket banner parsing\n";
173  }
174  {
175  // Well formatted banner, passes trivially
176  if (verbose) cout << "Reading first banner\n";
177  typedef Checker<scalar_type, ordinal_type> checker_type;
178  checker_type checker (echo, false, false);
179  RCP<const Comm<int> > comm = rcp (new SerialComm<int>);
180  std::stringstream in;
181  in.str("%%MatrixMarket matrix coordinate real symmetric\n0 0 0\n");
182  RCP<std::istream> inStream = rcpFromRef(in);
183  xs = checker.read (*comm, inStream);
184  if (verbose) {
185  cout << "Banner read " << (!xs ? "un" : "") << "successfully\n";
186  }
187  success = success && xs;
188  }
189 
190  {
191  // Banner with multiple adjacent/consecutive spaces/tabs
192  if (verbose) cout << "Reading second banner\n";
193  typedef Checker<scalar_type, ordinal_type> checker_type;
194  checker_type checker (echo, false, false);
195  RCP<const Comm<int> > comm = rcp (new SerialComm<int>);
196  std::stringstream in;
197  in.str("%%MatrixMarket\tmatrix\t\tcoordinate real symmetric\n0 0 0\n");
198  RCP<std::istream> inStream = rcpFromRef(in);
199  xs = checker.read (*comm, inStream);
200  if (verbose) {
201  cout << "Banner read " << (!xs ? "un" : "") << "successfully\n";
202  }
203  success = success && xs;
204  }
205 
206  {
207  // Bad value in banner. Should throw std::runtime_error
208  if (verbose) cout << "Reading third banner\n";
209  typedef Checker<scalar_type, ordinal_type> checker_type;
210  checker_type checker (echo, false, false);
211  RCP<const Comm<int> > comm = rcp (new SerialComm<int>);
212  std::stringstream in;
213  try {
214  in.str("%%MatrixMarket matrix coordinate real xyz\n0 0 0\n");
215  RCP<std::istream> inStream = rcpFromRef(in);
216  checker.read (*comm, inStream);
217  // The call to read *should* raise an error and the following line
218  // should not be encountered
219  xs = false;
220  }
221  catch (const std::runtime_error& e) {
222  // The error message will include that "xyz" is a bad value. Check
223  // that the string "xyz" is in the error mesage.
224  std::string es(e.what());
225  xs = es.find("xyz") != std::string::npos;
226  }
227  if (verbose) {
228  cout << "Banner read " << (!xs ? "un" : "") << "successfully\n";
229  }
230  success = success && xs;
231  }
232 
233  if (verbose) {
234  if (success) {
235  cout << "Banners parsed successfully\n";
236  } else {
237  cout << "Banners not parsed successfully\n";
238  }
239  }
240  }
241 
242  if (checkOnly) {
243  typedef Checker<scalar_type, ordinal_type> checker_type;
244  checker_type checker (echo, tolerant, debug);
245 
246  RCP<const Comm<int> > comm = rcp (new SerialComm<int>);
247  if (filename != "") {
248  if (verbose) {
249  cout << "Checking syntax of the Matrix Market file \"" << filename
250  << "\"" << endl;
251  }
252  success = success && checker.readFile (*comm, filename);
253  if (verbose) {
254  if (success) {
255  cout << "The given file is a valid Matrix Market file." << endl;
256  }
257  else {
258  cout << "The given file has syntax errors." << endl;
259  }
260  }
261  }
262  else {
263  if (verbose) {
264  cout << "Checking syntax of the first built-in Matrix Market example" << endl
265  << std::flush;// for debug output next
266  }
267  if (debug) {
268  cerr << "First built-in Matrix Market example: " << endl
269  << sampleMatrixMarketFile << endl;
270  }
271  std::istringstream in (sampleMatrixMarketFile);
272  RCP<std::istream> inStream = rcpFromRef (in);
273  success = success && checker.read (*comm, inStream);
274  if (verbose) {
275  if (success) {
276  cout << "The example has valid Matrix Market syntax." << endl;
277  }
278  else {
279  cout << "The example has syntax errors." << endl;
280  }
281  }
282  }
283  }
284  else {
285  typedef Reader<scalar_type, ordinal_type> reader_type;
286  reader_type reader (tolerant, debug);
287  ArrayRCP<ordinal_type> ptr, ind;
288  ArrayRCP<scalar_type> val;
289  ordinal_type numRows, numCols;
290  //
291  // Read the Matrix Market data, either from a file or from a
292  // built-in string.
293  //
294  if (filename != "") {
295  if (verbose) {
296  cout << "Reading the Matrix Market file \"" << filename << "\"" << endl;
297  }
298  success = success && reader.readFile (ptr, ind, val,
299  numRows, numCols, filename);
300  }
301  else {
302  if (verbose) {
303  cout << "Reading the first built-in Matrix Market example" << endl;
304  }
305  if (debug) {
306  cerr << "First built-in Matrix Market example:" << endl
307  << sampleMatrixMarketFile << endl;
308  }
309  std::istringstream inStr (sampleMatrixMarketFile);
310  success = success && reader.read (ptr, ind, val, numRows, numCols, inStr);
311  }
312  TEUCHOS_TEST_FOR_EXCEPTION(! success, std::runtime_error, "Matrix Market "
313  "reader failed to read the given file or input stream.");
314  if (success && verbose) {
315  cout << "Returned from reading the Matrix Market data" << endl
316  << std::flush; // for following debug output
317  }
318  if (debug) {
319  cerr << "CSR output info:" << endl
320  << " ptr.size() = " << ptr.size()
321  << ", ind.size() = " << ind.size()
322  << ", val.size() = " << val.size()
323  << ", numRows = " << numRows
324  << ", numCols = " << numCols
325  << endl;
326  }
327 
328  // Here's the fun part. Output the CSR data to an output stream.
329  // Then read in the output stream. The resulting matrix should be
330  // exactly the same (unless the original file had elements at the
331  // same location that were added together with rounding error).
332  // This is a test for both Writer and Reader.
333  std::ostringstream outStr;
334  if (success && verbose) {
335  cout << "Printing the CSR arrays to a Matrix Market output stream"
336  << endl << std::flush;
337  }
339  writer.write (outStr, ptr (), ind (), val (), numRows, numCols);
340 
341  if (debug && echo) {
342  cerr << "CSR data:" << endl
343  << "- ptr = [";
344  for (ordinal_type i = 0; i < ptr.size(); ++i) {
345  cerr << ptr[i];
346  if (i+1 != ptr.size()) { // don't subtract from zero if unsigned
347  cerr << ", ";
348  }
349  }
350  cerr << "]" << endl
351  << "- ind = [";
352  for (ordinal_type i = 0; i < ind.size(); ++i) {
353  cerr << ind[i];
354  if (i+1 != ind.size()) { // don't subtract from zero if unsigned
355  cerr << ", ";
356  }
357  }
358  cerr << "]" << endl
359  << "- val = [";
360  for (ordinal_type i = 0; i < val.size(); ++i) {
361  cerr << val[i];
362  if (i+1 != val.size()) { // don't subtract from zero if unsigned
363  cerr << ", ";
364  }
365  }
366  cerr << "]" << endl;
367 
368  cerr << "CSR data, converted back to Matrix Market format" << endl;
369  writer.write (cerr, ptr (), ind (), val (), numRows, numCols);
370  cerr << endl;
371  }
372 
373  ArrayRCP<ordinal_type> newptr, newind;
374  ArrayRCP<scalar_type> newval;
375  ordinal_type newNumRows, newNumCols;
376  if (success && verbose) {
377  cout << "Reading the Matrix Market output back into CSR arrays" << endl;
378  }
379  {
380  std::istringstream inStr (outStr.str ());
381  success = success && reader.read (newptr, newind, newval,
382  newNumRows, newNumCols, inStr);
383  }
384  TEUCHOS_TEST_FOR_EXCEPTION(! success, std::logic_error, "Matrix Market "
385  "reader failed to read the output back into CSR arrays.");
386  if (success && verbose) {
387  cout << "Successfully read the Matrix Market output back into CSR arrays"
388  << endl << std::flush;
389  }
390  if (debug) {
391  cerr << "CSR output info:" << endl
392  << " newptr.size() = " << newptr.size()
393  << ", newind.size() = " << newind.size()
394  << ", newval.size() = " << newval.size()
395  << ", newNumRows = " << newNumRows
396  << ", newNumCols = " << newNumCols
397  << endl;
398  }
399 
400  // The old arrays should equal the new arrays.
401  TEUCHOS_TEST_FOR_EXCEPTION(ptr.size () != newptr.size (), std::logic_error,
402  "New ptr array has a different length than old ptr array");
403  TEUCHOS_TEST_FOR_EXCEPTION(ind.size () != newind.size (), std::logic_error,
404  "New ind array has a different length than old ind array");
405  TEUCHOS_TEST_FOR_EXCEPTION(val.size () != newval.size (), std::logic_error,
406  "New val array has a different length than old val array");
407  TEUCHOS_TEST_FOR_EXCEPTION(newNumRows != numRows || newNumCols != numCols,
408  std::logic_error, "New dimensions differ from old dimensions");
409  TEUCHOS_TEST_FOR_EXCEPTION(ptr.size () != numRows+1, std::logic_error,
410  "ptr.size() != numRows+1");
411  TEUCHOS_TEST_FOR_EXCEPTION(newptr.size () != newNumRows+1, std::logic_error,
412  "newptr.size() != newNumRows+1");
413 
414  for (ordinal_type rowIndex = 0; rowIndex < numRows; ++rowIndex) {
415  TEUCHOS_TEST_FOR_EXCEPTION(ptr[rowIndex] != newptr[rowIndex],
416  std::logic_error, "At row index " << rowIndex << ", ptr[rowIndex] = "
417  << ptr[rowIndex] << " != newptr[rowIndex] = " << newptr[rowIndex]
418  << ".");
419  TEUCHOS_TEST_FOR_EXCEPTION(ptr[rowIndex+1] != newptr[rowIndex+1],
420  std::logic_error, "At row index " << rowIndex << ", ptr[rowIndex+1] = "
421  << ptr[rowIndex+1] << " != newptr[rowIndex+1] = " << newptr[rowIndex+1]
422  << ".");
423  for (ordinal_type k = ptr[rowIndex]; k < ptr[rowIndex+1]; ++k) {
424  TEUCHOS_TEST_FOR_EXCEPTION(ind[k] != newind[k], std::logic_error,
425  "At row index " << rowIndex << ", ind[k=" << k << "] = "
426  << ind[k] << " != newind[k] = " << newind[k] << ".");
427  // You may want to relax this inequality if the original
428  // Matrix Market file had multiple entries at the same
429  // location and if adding them together resulted in rounding
430  // error.
431  TEUCHOS_TEST_FOR_EXCEPTION(val[k] != newval[k], std::logic_error,
432  "At row index " << rowIndex << ", val[k=" << k << "] = "
433  << val[k] << " != newval[k] = " << newval[k] << ".");
434  }
435  }
436 
437  // Now test reading symmetric data, if no filename was specified.
438  if (filename == "") {
439  std::istringstream inStr (symmetricMatrixMarketFile);
440  success = success && reader.read (ptr, ind, val, numRows, numCols, inStr);
441  TEUCHOS_TEST_FOR_EXCEPTION(! success, std::logic_error,
442  "Matrix Market reader failed to read the given example string.");
443  if (success && verbose) {
444  cout << "Returned from reading the Matrix Market data" << endl
445  << std::flush; // for following debug output
446  }
447  if (debug) {
448  cerr << "CSR output info:" << endl
449  << " ptr.size() = " << ptr.size()
450  << ", ind.size() = " << ind.size()
451  << ", val.size() = " << val.size()
452  << ", numRows = " << numRows
453  << ", numCols = " << numCols
454  << endl;
455  }
456 
457  // This is a bit of a hack, since we know the contents of the
458  // example. Since we "symmetrize" when reading in symmetric
459  // data, there should be 15 entries in the resulting matrix.
460  const ordinal_type correctNumEntries = 15;
462  val.size() != correctNumEntries,
463  std::logic_error,
464  "Incorrect number of entries after symmetrization: There should be "
465  << correctNumEntries << ", but there are " << val.size() << " entries "
466  "instead.");
467  }
468  } // end of the file / string Reader tests
469 
470  if (success)
471  std::cout << "End Result: TEST PASSED" << endl;
472  else
473  std::cout << "End Result: TEST FAILED" << endl;
474  }
475  TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose, std::cerr, success);
476 
477  return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
478 }
Read a sparse matrix from a Matrix Market file into raw CSR (compressed sparse row) storage...
RCP< T > rcp(const boost::shared_ptr< T > &sptr)
Conversion function that takes in a boost::shared_ptr object and spits out a Teuchos::RCP object...
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Concrete serial communicator subclass.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
void write(std::ostream &out, const ArrayView< const OrdinalType > &rowptr, const ArrayView< const OrdinalType > &colind, const ArrayView< const ScalarType > &values, const OrdinalType numRows, const OrdinalType numCols)
Write the sparse matrix to the given output stream.
#define TEUCHOS_STANDARD_CATCH_STATEMENTS(VERBOSE, ERR_STREAM, SUCCESS_FLAG)
Simple macro that catches and reports standard exceptions and other exceptions.
A list of parameters of arbitrary type.
Ptr< T > ptr(T *p)
Create a pointer to an object from a raw pointer.
int main(int argc, char *argv[])
Abstract interface for distributed-memory communication.
Nonowning array view.
A MPI utilities class, providing methods for initializing, finalizing, and querying the global MPI se...
Basic command line parser for input from (argc,argv[])
RCP< T > rcpFromRef(T &r)
Return a non-owning weak RCP object from a raw object reference for a defined type.
Smart reference counting pointer class for automatic garbage collection.
Tool for debugging the syntax of a Matrix Market file containing a sparse matrix. ...
Write a sparse matrix from raw CSR (compressed sparse row) storage to a Matrix Market file...
Class that helps parse command line input arguments from (argc,argv[]) and set options.
Reference-counted smart pointer for managing arrays.