Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_MatrixMarket_Raw_Reader.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
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 
42 #ifndef __Teuchos_MatrixMarket_Raw_Reader_hpp
43 #define __Teuchos_MatrixMarket_Raw_Reader_hpp
44 
48 
49 
50 namespace Teuchos {
71  namespace MatrixMarket {
87  namespace Raw {
100  template<class Scalar, class Ordinal>
101  class Reader {
102  public:
109  Reader (const bool tolerant, const bool debug) :
110  tolerant_ (tolerant), debug_ (debug)
111  {
112  init ();
113  }
114 
116  Reader () :
117  tolerant_ (false), debug_ (false)
118  {
119  init ();
120  }
121 
129  Reader (const RCP<ParameterList>& params) :
130  tolerant_ (false), debug_ (false)
131  {
132  setParameters (params);
133  init ();
134  }
135 
139  void
141  {
142  // Default parameter values.
143  bool tolerant = false;
144  bool debug = false;
145 
146  // Read parameters.
147  tolerant = params->get ("Parse tolerantly", tolerant);
148  debug = params->get ("Debug mode", debug);
149 
150  // No side effects on the class until ParameterList
151  // processing is complete.
152  tolerant_ = tolerant;
153  debug_ = debug;
154  }
155 
159  {
160  // Default parameter values.
161  const bool tolerant = false;
162  const bool debug = false;
163 
164  // Set default parameters with documentation.
165  RCP<ParameterList> params = parameterList ("Matrix Market Reader");
166  params->set ("Parse tolerantly", tolerant, "Whether to tolerate "
167  "syntax errors when parsing the Matrix Market file");
168  params->set ("Debug mode", debug, "Whether to print debugging output "
169  "to stderr, on all participating MPI processes");
170 
171  return rcp_const_cast<const ParameterList> (params);
172  }
173 
199  bool
201  ArrayRCP<Ordinal>& colind,
202  ArrayRCP<Scalar>& values,
203  Ordinal& numRows,
204  Ordinal& numCols,
205  const std::string& filename)
206  {
207  std::ifstream in (filename.c_str ());
208  TEUCHOS_TEST_FOR_EXCEPTION(! in, std::runtime_error,
209  "Failed to open file \"" << filename << "\" for reading.");
210  return read (rowptr, colind, values, numRows, numCols, in);
211  }
212 
239  bool
241  ArrayRCP<Ordinal>& colind,
242  ArrayRCP<Scalar>& values,
243  Ordinal& numRows,
244  Ordinal& numCols,
245  std::istream& in)
246  {
247  using std::cerr;
248  using std::cout;
249  using std::endl;
250  typedef ScalarTraits<Scalar> STS;
251 
252  // This "Adder" knows how to add sparse matrix entries,
253  // given a line of data from the file. It also stores the
254  // entries and can sort them.
255  typedef Adder<Scalar, Ordinal> raw_adder_type;
256  // SymmetrizingAdder "advices" (yes, I'm using that as a verb)
257  // the original Adder, so that additional entries are filled
258  // in symmetrically, if the Matrix Market banner line
259  // specified a symmetry type other than "general".
260  typedef SymmetrizingAdder<raw_adder_type> adder_type;
261 
262  // Current line number of the input stream.
263  size_t lineNumber = 1;
264 
265  // Construct the "Banner" (matrix metadata, including type
266  // and symmetry information, but not dimensions).
267  RCP<const Banner> banner;
268  std::ostringstream err;
269  try {
270  banner = readBanner (in, lineNumber);
271  }
272  catch (std::exception& e) {
273  err << "Failed to read Matrix Market input's Banner: " << e.what();
274  if (tolerant_) {
275  if (debug_) {
276  cerr << err.str() << endl;
277  }
278  return false;
279  }
280  else {
281  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, err.str());
282  }
283  }
284 
285  //
286  // Validate the metadata in the Banner.
287  //
288  bool ok = true;
289  if (banner->matrixType () != "coordinate") {
290  err << "Matrix Market input file must contain a \"coordinate\"-"
291  "format sparse matrix in order to create a sparse matrix object "
292  "from it.";
293  ok = false;
294  }
295  else if (! STS::isComplex && banner->dataType () == "complex") {
296  err << "The Matrix Market sparse matrix file contains complex-"
297  "valued data, but you are try to read the data into a sparse "
298  "matrix containing real values (your matrix's Scalar type is "
299  "real).";
300  ok = false;
301  }
302  else if (banner->dataType () != "real" &&
303  banner->dataType () != "complex") {
304  err << "Only real or complex data types (no pattern or integer "
305  "matrices) are currently supported.";
306  ok = false;
307  }
308  if (! ok) {
309  if (tolerant_) {
310  if (debug_) {
311  cerr << "Matrix Market banner is invalid: " << err.str () << endl;
312  return false;
313  }
314  }
315  else {
316  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
317  "Matrix Market banner is invalid: " << err.str ());
318  }
319  }
320  if (debug_) {
321  cerr << "Matrix Market Banner line:" << endl << *banner << endl;
322  }
323 
324  // The reader will invoke the adder (see below) once for
325  // each matrix entry it reads from the input stream.
327  // We will set the adder below, after calling readDimensions().
328  reader_type reader;
329 
330  // Read in the dimensions of the sparse matrix: (# rows, #
331  // columns, # matrix entries (counting duplicates as
332  // separate entries)). The second element of the pair tells
333  // us whether the values were gotten successfully.
334  std::pair<Tuple<Ordinal, 3>, bool> dims =
335  reader.readDimensions (in, lineNumber, tolerant_);
336  if (! dims.second) {
337  err << "Error reading Matrix Market sparse matrix file: failed to "
338  "read coordinate dimensions.";
339  if (tolerant_) {
340  if (debug_) {
341  cerr << err.str () << endl;
342  }
343  return false;
344  }
345  else {
346  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, err.str ());
347  }
348  }
349 
350  // These are "expected" values read from the input stream's
351  // metadata. The actual matrix entries read from the input
352  // stream might not conform to their constraints. We allow
353  // such nonconformity only in "tolerant" mode; otherwise, we
354  // throw an exception.
355  numRows = dims.first[0];
356  numCols = dims.first[1];
357  const Ordinal numEntries = dims.first[2];
358  if (debug_) {
359  cerr << "Reported dimensions: " << numRows << " x " << numCols
360  << ", with " << numEntries << " entries (counting possible "
361  << "duplicates)." << endl;
362  }
363 
364  // The "raw" adder knows about the expected matrix
365  // dimensions, but doesn't know about symmetry.
366  RCP<raw_adder_type> rawAdder =
367  rcp (new raw_adder_type (numRows, numCols, numEntries,
368  tolerant_, debug_));
369  // The symmetrizing adder knows about symmetry. It mediates
370  // adding entries to the "raw" adder. We'll use the raw
371  // adder to compute the CSR arrays.
372  RCP<adder_type> adder =
373  rcp (new adder_type (rawAdder, banner->symmType ()));
374 
375  // Give the adder to the reader.
376  reader.setAdder (adder);
377 
378  // Read the sparse matrix entries. "results" just tells us if
379  // and where there were any bad lines of input. The actual
380  // sparse matrix entries are stored in the (raw) Adder object.
381  std::pair<bool, std::vector<size_t> > results =
382  reader.read (in, lineNumber, tolerant_, debug_);
383 
384  // Report any bad line number(s).
385  if (! results.first) {
386  err << "The Matrix Market input stream had syntax error(s)."
387  " Here is the error report." << endl;
388  reportBadness (err, results);
389  if (tolerant_) {
390  if (debug_) {
391  cerr << err.str() << endl;
392  }
393  return false;
394  }
395  else {
396  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, err.str ());
397  }
398  }
399  // Done reading the sparse matrix; now extract CSR arrays.
400  size_t numUnique, numRemoved;
401  ArrayRCP<Ordinal> ptr;
402  ArrayRCP<Ordinal> ind;
403  ArrayRCP<Scalar> val;
404  try {
405  rawAdder->mergeAndConvertToCSR (numUnique, numRemoved, ptr, ind, val);
406  }
407  catch (std::exception& e) {
408  err << "Failed to convert sparse matrix data to CSR (compressed "
409  "sparse row) format. Reported error: " << e.what ();
410  if (tolerant_) {
411  if (debug_) {
412  cerr << err.str () << endl;
413  }
414  return false;
415  }
416  else {
417  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, err.str ());
418  }
419  }
420  rowptr = ptr;
421  colind = ind;
422  values = val;
423  return true;
424  }
425 
426  private:
428  bool tolerant_;
430  bool debug_;
431 
438  void init () {
439  using std::cerr;
440  using std::endl;
441 
442  if (debug_) {
443  cerr << "MatrixMarket::Raw::Reader:" << endl
444  << "- Tolerant mode: " << tolerant_ << endl
445  << "- Debug mode: " << debug_ << endl;
446  }
447  }
448 
462  readBanner (std::istream& in, size_t& lineNumber)
463  {
464  using std::cerr;
465  using std::endl;
466  std::string line; // The presumed banner line
467 
468  // The first line of the Matrix Market file should always be
469  // the banner line. In tolerant mode, we allow comment
470  // lines before the banner line. This complicates detection
471  // of comment lines a bit.
472  if (tolerant_) {
473  // Keep reading lines until we get a noncomment line.
474  const bool maybeBannerLine = true;
475  size_t numLinesRead = 0;
476  bool commentLine = false;
477  do {
478  // Try to read a line from the input stream.
479  const bool readFailed = ! getline (in, line);
480  TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
481  "Failed to get Matrix Market banner line from input, after reading "
482  << numLinesRead << "line" << (numLinesRead != 1 ? "s." : "."));
483  // We read a line from the input stream.
484  ++lineNumber;
485  ++numLinesRead;
486  size_t start, size; // Output args of checkCommentLine
487  commentLine = checkCommentLine (line, start, size, lineNumber,
488  tolerant_, maybeBannerLine);
489  } while (commentLine); // Loop until we find a noncomment line.
490  }
491  else {
492  const bool readFailed = ! getline (in, line);
493  TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
494  "Failed to get Matrix Market banner line from input. This "
495  "probably means that the file is empty (contains zero lines).");
496  }
497 
498  if (debug_) {
499  cerr << "Raw::Reader::readBanner: Here is the presumed banner line:"
500  << endl << line << endl;
501  }
502 
503  // Assume that the noncomment line we found is the banner line.
504  RCP<Banner> banner;
505  try {
506  banner = rcp (new Banner (line, tolerant_));
507  } catch (std::exception& e) {
508  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
509  "Matrix Market file's banner line contains syntax error(s): "
510  << e.what ());
511  }
512  return rcp_const_cast<const Banner> (banner);
513  }
514 
519  void
520  reportBadness (std::ostream& out,
521  const std::pair<bool, std::vector<size_t> >& results)
522  {
523  using std::endl;
524  const size_t numErrors = results.second.size();
525  const size_t maxNumErrorsToReport = 20;
526  out << numErrors << " errors when reading Matrix Market sparse "
527  "matrix file." << endl;
528  if (numErrors > maxNumErrorsToReport) {
529  out << "-- We do not report individual errors when there "
530  "are more than " << maxNumErrorsToReport << ".";
531  }
532  else if (numErrors == 1) {
533  out << "Error on line " << results.second[0] << endl;
534  }
535  else if (numErrors > 1) {
536  out << "Errors on lines {";
537  for (size_t k = 0; k < numErrors-1; ++k) {
538  out << results.second[k] << ", ";
539  }
540  out << results.second[numErrors-1] << "}" << endl;
541  }
542  }
543  }; // end of class Reader
544  } // namespace Raw
545  } // namespace MatrixMarket
546 } // namespace Teuchos
547 
548 #endif // __Teuchos_MatrixMarket_Raw_Reader_hpp
Read a sparse matrix from a Matrix Market file into raw CSR (compressed sparse row) storage...
bool checkCommentLine(const std::string &line, size_t &start, size_t &size, const size_t lineNumber, const bool tolerant, const bool maybeBannerLine)
True if the line is a comment line, false otherwise.
void setParameters(const RCP< ParameterList > &params)
Set parameters from the given ParameterList.
RCP< const ParameterList > getValidParameters() const
Get a list of valid default parameters, with documentation.
void init()
&quot;Initialize&quot; the Reader.
Adds entries with optional symmetry to a sparse matrix.
bool debug_
Whether to print debugging output to stderr.
std::pair< Teuchos::Tuple< Ordinal, 3 >, bool > readDimensions(std::istream &in, size_t &lineNumber, const bool tolerant=false)
Read (numRows, numCols, numNonzeros).
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
T * get() const
Get the raw C++ pointer to the underlying object.
Reader(const RCP< ParameterList > &params)
Constructor that takes a ParameterList of parameters.
Coordinate-format sparse matrix data reader.
This structure defines some basic traits for a scalar field type.
bool read(ArrayRCP< Ordinal > &rowptr, ArrayRCP< Ordinal > &colind, ArrayRCP< Scalar > &values, Ordinal &numRows, Ordinal &numCols, std::istream &in)
Read the sparse matrix from the given input stream into CSR storage.
bool tolerant_
Whether to parse the Matrix Market file tolerantly.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
bool readFile(ArrayRCP< Ordinal > &rowptr, ArrayRCP< Ordinal > &colind, ArrayRCP< Scalar > &values, Ordinal &numRows, Ordinal &numCols, const std::string &filename)
Read the sparse matrix from the given file into CSR storage.
RCP< const Banner > readBanner(std::istream &in, size_t &lineNumber)
Read in the Banner line from the given input stream.
A list of parameters of arbitrary type.
Reader()
Constructor that sets default Boolean parameters.
Smart reference counting pointer class for automatic garbage collection.
Reader(const bool tolerant, const bool debug)
Constructor that takes Boolean parameters.
void reportBadness(std::ostream &out, const std::pair< bool, std::vector< size_t > > &results)
Parse a Matrix Market banner line.
Reference-counted smart pointer for managing arrays.
To be used with Checker for &quot;raw&quot; sparse matrix input.