Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
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 
51 #include <algorithm>
52 
53 using std::endl;
54 
55 namespace {
56  // Sample Matrix Market sparse matrix file. We include this so we
57  // can test without needing to read in a file. Notice that all the
58  // decimal floating-point values in this example can be represented
59  // exactly in binary floating point. This example has correct
60  // syntax, so you won't need to use tolerant mode to parse it.
61  const char sampleMatrixMarketFile[] =
62  "%%MatrixMarket matrix coordinate real general\n"
63  "5 5 10\n"
64  "5 5 55.0\n"
65  "4 4 44.0\n"
66  "3 3 33.0\n"
67  "2 2 22.0\n"
68  "1 1 11.0\n"
69  "4 5 45.0\n"
70  "3 4 34.0\n"
71  "2 3 23.0\n"
72  "1 2 12.0\n"
73  "1 5 15.0\n";
74 
75  // Sample Matrix Market sparse matrix file for testing symmetric
76  // storage. Matrix Market format for symmetric, skew-symemtric,
77  // etc. specifies that only the lower triangle should be stored.
78  const char symmetricMatrixMarketFile[] =
79  "%%MatrixMarket matrix coordinate real symmetric\n"
80  "5 5 10\n"
81  "5 5 55.0\n"
82  "4 4 44.0\n"
83  "3 3 33.0\n"
84  "2 2 22.0\n"
85  "1 1 11.0\n"
86  "5 4 54.0\n"
87  "4 3 43.0\n"
88  "3 2 32.0\n"
89  "2 1 21.0\n"
90  "5 1 51.0\n";
91 
92 } // namespace (anonymous)
93 
94 // Benchmark driver
95  int
96 main (int argc, char *argv[])
97 {
100  using Teuchos::ArrayRCP;
101  using Teuchos::ArrayView;
102  using Teuchos::Comm;
105  using Teuchos::RCP;
106  using Teuchos::rcp;
107  using Teuchos::rcpFromRef;
108  using Teuchos::SerialComm;
109  using std::cout;
110  using std::cerr;
111  typedef double scalar_type;
112  typedef int ordinal_type;
113 
114  bool success = false;
115  // Verbosity of output
116  bool verbose = true;
117  try {
118  // Name of the Matrix Market sparse matrix file to read. If empty,
119  // use the Matrix Market example embedded as a string in this file.
120  std::string filename;
121  // If true, just check the sparse matrix file. Otherwise,
122  // do a full conversion to CSR (compressed sparse row) format.
123  bool checkOnly = false;
124  // Whether to echo the sparse matrix to stdout after reading it
125  // successfully.
126  bool echo = false;
127  // Whether to parse the Matrix Market file tolerantly.
128  bool tolerant = false;
129  // Whether to print debugging-level output
130  bool debug = false;
131 
132  CommandLineProcessor cmdp (false, true);
133  cmdp.setOption ("filename", &filename,
134  "Name of the Matrix Market sparse matrix file to read.");
135  cmdp.setOption ("checkOnly", "fullTest", &checkOnly,
136  "If true, just check the syntax of the input file. "
137  "Otherwise, do a full test.");
138  cmdp.setOption ("echo", "noecho", &echo,
139  "Whether to echo the sparse matrix contents to stdout "
140  "after reading it successfully.");
141  cmdp.setOption ("tolerant", "strict", &tolerant,
142  "Whether to tolerate syntax errors in the Matrix Market file.");
143  cmdp.setOption ("verbose", "quiet", &verbose,
144  "Print status output to stdout.");
145  cmdp.setOption ("debug", "nodebug", &debug,
146  "Print possibly copious debugging output to stderr.");
147  // Parse the command-line arguments.
148  {
149  const CommandLineProcessor::EParseCommandLineReturn parseResult =
150  cmdp.parse (argc,argv);
151  // If the caller asks us to print the documentation, or does not
152  // explicitly say to run the benchmark, we let this "test" pass
153  // trivially.
154  if (parseResult == CommandLineProcessor::PARSE_HELP_PRINTED) {
155  std::cout << "End Result: TEST PASSED" << endl;
156  return EXIT_SUCCESS;
157  }
159  parseResult != CommandLineProcessor::PARSE_SUCCESSFUL,
160  std::invalid_argument, "Failed to parse command-line arguments.");
161  }
162 
163  // Test reading in the sparse matrix. If no filename or an empty
164  // filename is specified, the test passes trivially.
165  success = true;
166  if (checkOnly) {
167  typedef Checker<scalar_type, ordinal_type> checker_type;
168  checker_type checker (echo, tolerant, debug);
169 
170  RCP<const Comm<int> > comm = rcp (new SerialComm<int>);
171  if (filename != "") {
172  if (verbose) {
173  cout << "Checking syntax of the Matrix Market file \"" << filename
174  << "\"" << endl;
175  }
176  success = success && checker.readFile (*comm, filename);
177  if (verbose) {
178  if (success) {
179  cout << "The given file is a valid Matrix Market file." << endl;
180  }
181  else {
182  cout << "The given file has syntax errors." << endl;
183  }
184  }
185  }
186  else {
187  if (verbose) {
188  cout << "Checking syntax of the first built-in Matrix Market example" << endl
189  << std::flush;// for debug output next
190  }
191  if (debug) {
192  cerr << "First built-in Matrix Market example: " << endl
193  << sampleMatrixMarketFile << endl;
194  }
195  std::istringstream in (sampleMatrixMarketFile);
196  RCP<std::istream> inStream = rcpFromRef (in);
197  success = success && checker.read (*comm, inStream);
198  if (verbose) {
199  if (success) {
200  cout << "The example has valid Matrix Market syntax." << endl;
201  }
202  else {
203  cout << "The example has syntax errors." << endl;
204  }
205  }
206  }
207  }
208  else {
209  typedef Reader<scalar_type, ordinal_type> reader_type;
210  reader_type reader (tolerant, debug);
211  ArrayRCP<ordinal_type> ptr, ind;
212  ArrayRCP<scalar_type> val;
213  ordinal_type numRows, numCols;
214  //
215  // Read the Matrix Market data, either from a file or from a
216  // built-in string.
217  //
218  if (filename != "") {
219  if (verbose) {
220  cout << "Reading the Matrix Market file \"" << filename << "\"" << endl;
221  }
222  success = success && reader.readFile (ptr, ind, val,
223  numRows, numCols, filename);
224  }
225  else {
226  if (verbose) {
227  cout << "Reading the first built-in Matrix Market example" << endl;
228  }
229  if (debug) {
230  cerr << "First built-in Matrix Market example:" << endl
231  << sampleMatrixMarketFile << endl;
232  }
233  std::istringstream inStr (sampleMatrixMarketFile);
234  success = success && reader.read (ptr, ind, val, numRows, numCols, inStr);
235  }
236  TEUCHOS_TEST_FOR_EXCEPTION(! success, std::runtime_error, "Matrix Market "
237  "reader failed to read the given file or input stream.");
238  if (success && verbose) {
239  cout << "Returned from reading the Matrix Market data" << endl
240  << std::flush; // for following debug output
241  }
242  if (debug) {
243  cerr << "CSR output info:" << endl
244  << " ptr.size() = " << ptr.size()
245  << ", ind.size() = " << ind.size()
246  << ", val.size() = " << val.size()
247  << ", numRows = " << numRows
248  << ", numCols = " << numCols
249  << endl;
250  }
251 
252  // Here's the fun part. Output the CSR data to an output stream.
253  // Then read in the output stream. The resulting matrix should be
254  // exactly the same (unless the original file had elements at the
255  // same location that were added together with rounding error).
256  // This is a test for both Writer and Reader.
257  std::ostringstream outStr;
258  if (success && verbose) {
259  cout << "Printing the CSR arrays to a Matrix Market output stream"
260  << endl << std::flush;
261  }
263  writer.write (outStr, ptr (), ind (), val (), numRows, numCols);
264 
265  if (debug && echo) {
266  cerr << "CSR data:" << endl
267  << "- ptr = [";
268  for (ordinal_type i = 0; i < ptr.size(); ++i) {
269  cerr << ptr[i];
270  if (i+1 != ptr.size()) { // don't subtract from zero if unsigned
271  cerr << ", ";
272  }
273  }
274  cerr << "]" << endl
275  << "- ind = [";
276  for (ordinal_type i = 0; i < ind.size(); ++i) {
277  cerr << ind[i];
278  if (i+1 != ind.size()) { // don't subtract from zero if unsigned
279  cerr << ", ";
280  }
281  }
282  cerr << "]" << endl
283  << "- val = [";
284  for (ordinal_type i = 0; i < val.size(); ++i) {
285  cerr << val[i];
286  if (i+1 != val.size()) { // don't subtract from zero if unsigned
287  cerr << ", ";
288  }
289  }
290  cerr << "]" << endl;
291 
292  cerr << "CSR data, converted back to Matrix Market format" << endl;
293  writer.write (cerr, ptr (), ind (), val (), numRows, numCols);
294  cerr << endl;
295  }
296 
297  ArrayRCP<ordinal_type> newptr, newind;
298  ArrayRCP<scalar_type> newval;
299  ordinal_type newNumRows, newNumCols;
300  if (success && verbose) {
301  cout << "Reading the Matrix Market output back into CSR arrays" << endl;
302  }
303  {
304  std::istringstream inStr (outStr.str ());
305  success = success && reader.read (newptr, newind, newval,
306  newNumRows, newNumCols, inStr);
307  }
308  TEUCHOS_TEST_FOR_EXCEPTION(! success, std::logic_error, "Matrix Market "
309  "reader failed to read the output back into CSR arrays.");
310  if (success && verbose) {
311  cout << "Successfully read the Matrix Market output back into CSR arrays"
312  << endl << std::flush;
313  }
314  if (debug) {
315  cerr << "CSR output info:" << endl
316  << " newptr.size() = " << newptr.size()
317  << ", newind.size() = " << newind.size()
318  << ", newval.size() = " << newval.size()
319  << ", newNumRows = " << newNumRows
320  << ", newNumCols = " << newNumCols
321  << endl;
322  }
323 
324  // The old arrays should equal the new arrays.
325  TEUCHOS_TEST_FOR_EXCEPTION(ptr.size () != newptr.size (), std::logic_error,
326  "New ptr array has a different length than old ptr array");
327  TEUCHOS_TEST_FOR_EXCEPTION(ind.size () != newind.size (), std::logic_error,
328  "New ind array has a different length than old ind array");
329  TEUCHOS_TEST_FOR_EXCEPTION(val.size () != newval.size (), std::logic_error,
330  "New val array has a different length than old val array");
331  TEUCHOS_TEST_FOR_EXCEPTION(newNumRows != numRows || newNumCols != numCols,
332  std::logic_error, "New dimensions differ from old dimensions");
333  TEUCHOS_TEST_FOR_EXCEPTION(ptr.size () != numRows+1, std::logic_error,
334  "ptr.size() != numRows+1");
335  TEUCHOS_TEST_FOR_EXCEPTION(newptr.size () != newNumRows+1, std::logic_error,
336  "newptr.size() != newNumRows+1");
337 
338  for (ordinal_type rowIndex = 0; rowIndex < numRows; ++rowIndex) {
339  TEUCHOS_TEST_FOR_EXCEPTION(ptr[rowIndex] != newptr[rowIndex],
340  std::logic_error, "At row index " << rowIndex << ", ptr[rowIndex] = "
341  << ptr[rowIndex] << " != newptr[rowIndex] = " << newptr[rowIndex]
342  << ".");
343  TEUCHOS_TEST_FOR_EXCEPTION(ptr[rowIndex+1] != newptr[rowIndex+1],
344  std::logic_error, "At row index " << rowIndex << ", ptr[rowIndex+1] = "
345  << ptr[rowIndex+1] << " != newptr[rowIndex+1] = " << newptr[rowIndex+1]
346  << ".");
347  for (ordinal_type k = ptr[rowIndex]; k < ptr[rowIndex+1]; ++k) {
348  TEUCHOS_TEST_FOR_EXCEPTION(ind[k] != newind[k], std::logic_error,
349  "At row index " << rowIndex << ", ind[k=" << k << "] = "
350  << ind[k] << " != newind[k] = " << newind[k] << ".");
351  // You may want to relax this inequality if the original
352  // Matrix Market file had multiple entries at the same
353  // location and if adding them together resulted in rounding
354  // error.
355  TEUCHOS_TEST_FOR_EXCEPTION(val[k] != newval[k], std::logic_error,
356  "At row index " << rowIndex << ", val[k=" << k << "] = "
357  << val[k] << " != newval[k] = " << newval[k] << ".");
358  }
359  }
360 
361  // Now test reading symmetric data, if no filename was specified.
362  if (filename == "") {
363  std::istringstream inStr (symmetricMatrixMarketFile);
364  success = success && reader.read (ptr, ind, val, numRows, numCols, inStr);
365  TEUCHOS_TEST_FOR_EXCEPTION(! success, std::logic_error,
366  "Matrix Market reader failed to read the given example string.");
367  if (success && verbose) {
368  cout << "Returned from reading the Matrix Market data" << endl
369  << std::flush; // for following debug output
370  }
371  if (debug) {
372  cerr << "CSR output info:" << endl
373  << " ptr.size() = " << ptr.size()
374  << ", ind.size() = " << ind.size()
375  << ", val.size() = " << val.size()
376  << ", numRows = " << numRows
377  << ", numCols = " << numCols
378  << endl;
379  }
380 
381  // This is a bit of a hack, since we know the contents of the
382  // example. Since we "symmetrize" when reading in symmetric
383  // data, there should be 15 entries in the resulting matrix.
384  const ordinal_type correctNumEntries = 15;
386  val.size() != correctNumEntries,
387  std::logic_error,
388  "Incorrect number of entries after symmetrization: There should be "
389  << correctNumEntries << ", but there are " << val.size() << " entries "
390  "instead.");
391  }
392  } // end of the file / string Reader tests
393 
394  if (success)
395  std::cout << "End Result: TEST PASSED" << endl;
396  else
397  std::cout << "End Result: TEST FAILED" << endl;
398  }
399  TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose, std::cerr, success);
400 
401  return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
402 }
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.
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.
int main(int argc, char *argv[])
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.