Teuchos - Trilinos Tools Package  Version of the Day
Teuchos_MatrixMarket_Raw_Reader.hpp
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 
45 #include "Teuchos_MatrixMarket_Raw_Adder.hpp"
46 #include "Teuchos_MatrixMarket_SymmetrizingAdder.hpp"
47 #include "Teuchos_MatrixMarket_CoordDataReader.hpp"
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
Teuchos::MatrixMarket::Raw::Reader::read
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.
Definition: Teuchos_MatrixMarket_Raw_Reader.hpp:240
MatrixMarket
Matrix Market file utilities.
Teuchos::MatrixMarket::Raw::Adder
To be used with Checker for "raw" sparse matrix input.
Definition: Teuchos_MatrixMarket_Raw_Adder.hpp:283
Teuchos::MatrixMarket::Raw::Reader
Read a sparse matrix from a Matrix Market file into raw CSR (compressed sparse row) storage.
Definition: Teuchos_MatrixMarket_Raw_Reader.hpp:101
Teuchos::rcp
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
Definition: Teuchos_RCPDecl.hpp:1224
Teuchos::RCP
Smart reference counting pointer class for automatic garbage collection.
Definition: Teuchos_RCPDecl.hpp:429
Teuchos::MatrixMarket::Raw::Reader::Reader
Reader()
Constructor that sets default Boolean parameters.
Definition: Teuchos_MatrixMarket_Raw_Reader.hpp:116
Teuchos::MatrixMarket::Raw::Reader::Reader
Reader(const bool tolerant, const bool debug)
Constructor that takes Boolean parameters.
Definition: Teuchos_MatrixMarket_Raw_Reader.hpp:109
Teuchos::MatrixMarket::Raw::Reader::setParameters
void setParameters(const RCP< ParameterList > &params)
Set parameters from the given ParameterList.
Definition: Teuchos_MatrixMarket_Raw_Reader.hpp:140
Teuchos::MatrixMarket::SymmetrizingAdder
Adds entries with optional symmetry to a sparse matrix.
Definition: Teuchos_MatrixMarket_SymmetrizingAdder.hpp:112
Teuchos::ArrayRCP
Reference-counted smart pointer for managing arrays.
Definition: Teuchos_ArrayRCPDecl.hpp:127
Teuchos::MatrixMarket::CoordDataReader
Coordinate-format sparse matrix data reader.
Definition: Teuchos_MatrixMarket_CoordDataReader.hpp:461
Teuchos::ScalarTraits
This structure defines some basic traits for a scalar field type.
Definition: Teuchos_ScalarTraitsDecl.hpp:90
Raw
"Raw" input of sparse matrices from Matrix Market files.
Teuchos::MatrixMarket::Raw::Reader::Reader
Reader(const RCP< ParameterList > &params)
Constructor that takes a ParameterList of parameters.
Definition: Teuchos_MatrixMarket_Raw_Reader.hpp:129
Teuchos::RCP::get
T * get() const
Get the raw C++ pointer to the underlying object.
Definition: Teuchos_RCP.hpp:363
Teuchos::MatrixMarket::Raw::Reader::getValidParameters
RCP< const ParameterList > getValidParameters() const
Get a list of valid default parameters, with documentation.
Definition: Teuchos_MatrixMarket_Raw_Reader.hpp:158
Teuchos::MatrixMarket::CoordDataReaderBase::readDimensions
std::pair< Teuchos::Tuple< Ordinal, 3 >, bool > readDimensions(std::istream &in, size_t &lineNumber, const bool tolerant=false)
Read (numRows, numCols, numNonzeros).
Definition: Teuchos_MatrixMarket_CoordDataReader.hpp:262
Teuchos
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
TEUCHOS_TEST_FOR_EXCEPTION
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Definition: Teuchos_TestForException.hpp:170
Teuchos::MatrixMarket::Raw::Reader::readFile
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.
Definition: Teuchos_MatrixMarket_Raw_Reader.hpp:200