Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_MatrixMarket_CoordDataReader.hpp
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef __Teuchos_MatrixMarket_CoordDataReader_hpp
11#define __Teuchos_MatrixMarket_CoordDataReader_hpp
12
13#include "Teuchos_MatrixMarket_generic.hpp"
14#include "Teuchos_RCP.hpp"
16#include "Teuchos_Tuple.hpp"
17#include <type_traits>
18
19
20namespace Teuchos {
21 namespace MatrixMarket {
68 template<class Callback, class Ordinal>
70 protected:
73
74 public:
86 adder_ (adder) {}
87
96
99
106 void setAdder (const Teuchos::RCP<Callback>& adder) {
107 adder_ = adder;
108 }
109
110 protected:
137 virtual bool
138 readLine (const std::string& theLine,
139 const size_t lineNumber,
140 const bool tolerant) = 0;
141
142 public:
143
171 virtual std::pair<bool, std::vector<size_t> >
172 read (std::istream& in,
173 const size_t startingLineNumber,
174 const bool tolerant,
175 const bool debug = false)
176 {
177 (void) debug; // silence unused input argument warning
178 TEUCHOS_TEST_FOR_EXCEPTION(! in, std::invalid_argument,
179 "Input stream is invalid.");
180
181 std::string line;
182 size_t lineNumber = startingLineNumber;
183 bool allSucceeded = true;
184 std::vector<size_t> badLineNumbers;
185 while (getline (in, line)) {
186 size_t start, size;
187 if (checkCommentLine (line, start, size, lineNumber, tolerant)) {
188 ++lineNumber;
189 continue; // it's a comment line
190 }
191 const std::string theLine = line.substr (start, size);
192
193 const bool localSuccess = readLine (theLine, lineNumber, tolerant);
194 ++lineNumber;
195 allSucceeded = allSucceeded && localSuccess;
196 if (! localSuccess) {
197 badLineNumbers.push_back (lineNumber);
198 }
199 }
200 return std::make_pair (allSucceeded, badLineNumbers);
201 }
202
226 std::pair<Teuchos::Tuple<Ordinal, 3>, bool>
227 readDimensions (std::istream& in,
228 size_t& lineNumber,
229 const bool tolerant = false)
230 {
232 // Fill in (numRows, numCols, numNonzeros) with reasonable
233 // defaults. If we don't succeed in reading all the data
234 // from the current line of the input stream, the remaining
235 // values not read will be these default values.
236 dims[0] = 0;
237 dims[1] = 0;
238 dims[2] = 0;
239
240 // Keep reading lines from the input stream until we find a
241 // non-comment line, or until we run out of lines. The latter
242 // is an error, since every "coordinate" format Matrix Market
243 // file must have a dimensions line after the banner (even if
244 // the matrix has zero rows or columns, or zero entries).
245 std::string line;
246 bool commentLine = true;
247 while (commentLine) {
248 // Is it even valid to read from the input stream?
249 if (in.eof() || in.fail()) {
250 if (tolerant) {
251 return std::make_pair (dims, false);
252 }
253 else {
254 std::ostringstream os;
255 os << "Unable to get coordinate dimensions line (at all) "
256 "from (line " << lineNumber << ") of input stream; the "
257 "input stream claims that it is at \"end-of-file\" or has "
258 "an otherwise \"fail\"ed state.";
259 throw std::invalid_argument(os.str());
260 }
261 }
262 // Try to get the next line from the input stream.
263 if (getline(in, line)) {
264 lineNumber++; // We did actually read a line
265 }
266 else {
267 if (tolerant) {
268 return std::make_pair (dims, false);
269 }
270 else {
271 std::ostringstream os;
272 os << "Failed to read coordinate dimensions line (at all) "
273 "from (line " << lineNumber << " from input stream. The "
274 "line should contain the coordinate matrix dimensions in "
275 << " the form \"<numRows> <numCols> <numNonzeros>\".";
276 throw std::invalid_argument (os.str());
277 }
278 }
279 // Is the current line a comment line? Ignore start and
280 // size; they are only useful for reading the actual matrix
281 // entries. (We could use them here as an optimization, but
282 // we've chosen not to.)
283 size_t start = 0, size = 0;
284 commentLine = checkCommentLine (line, start, size,
285 lineNumber, tolerant);
286 }
287 //
288 // Read in <numRows> <numCols> <numNonzeros> from input line
289 //
290 std::istringstream istr (line);
291 // Does line contain anything at all? Can we safely read from
292 // the input stream wrapping the line?
293 if (istr.eof() || istr.fail()) {
294 if (tolerant) {
295 return std::make_pair (dims, false);
296 }
297 std::ostringstream os;
298 os << "Unable to read any data from line " << lineNumber
299 << " of input; the line should contain the coordinate matrix "
300 << "dimensions \"<numRows> <numCols> <numNonzeros>\".";
301 throw std::invalid_argument(os.str());
302 }
303 // Read in <numRows>
304 {
305 Ordinal theNumRows = 0;
306 istr >> theNumRows;
307 if (istr.fail()) {
308 if (tolerant) {
309 return std::make_pair (dims, false);
310 }
311 std::ostringstream os;
312 os << "Failed to get number of rows from line " << lineNumber
313 << " of input; the line should contain the coordinate matrix "
314 << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
315 throw std::invalid_argument(os.str());
316 }
317 else { // Capture the validly read result before checking for eof.
318 dims[0] = theNumRows;
319 }
320 }
321 // There should be two more things to read.
322 if (istr.eof()) {
323 if (tolerant) {
324 return std::make_pair (dims, false);
325 }
326 std::ostringstream os;
327 os << "No more data after number of rows on line " << lineNumber
328 << " of input; the line should contain the coordinate matrix "
329 << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
330 throw std::invalid_argument(os.str());
331 }
332 // Read in <numCols>
333 {
334 Ordinal theNumCols = 0;
335 istr >> theNumCols;
336 if (istr.fail()) {
337 if (tolerant) {
338 return std::make_pair (dims, false);
339 }
340 std::ostringstream os;
341 os << "Failed to get number of columns from line " << lineNumber
342 << " of input; the line should contain the coordinate matrix "
343 << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
344 throw std::invalid_argument(os.str());
345 }
346 else { // Capture the validly read result before checking for eof.
347 dims[1] = theNumCols;
348 }
349 }
350 // There should be one more thing to read.
351 if (istr.eof()) {
352 if (tolerant) {
353 return std::make_pair (dims, false);
354 }
355 std::ostringstream os;
356 os << "No more data after number of columns on line " << lineNumber
357 << " of input; the line should contain the coordinate matrix "
358 << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
359 throw std::invalid_argument(os.str());
360 }
361 // Read in <numNonzeros>
362 {
363 Ordinal theNumNonzeros = 0;
364 istr >> theNumNonzeros;
365 if (istr.fail()) {
366 if (tolerant) {
367 return std::make_pair (dims, false);
368 }
369 std::ostringstream os;
370 os << "Failed to get number of (structural) nonzeros from line "
371 << lineNumber
372 << " of input; the line should contain the coordinate matrix "
373 << " dimensions \"<numRows> <numCols> <numNonzeros>\".";
374 throw std::invalid_argument(os.str());
375 }
376 else { // Capture the validly read result
377 dims[2] = theNumNonzeros;
378 }
379 }
380 // Validate that dimensions are non-negative. Only signed
381 // Ordinal types can be negative; skipping the test for
382 // unsigned types avoids tautological-comparison warnings.
383 if constexpr (std::is_signed_v<Ordinal>) {
384 if (dims[0] < 0 || dims[1] < 0 || dims[2] < 0) {
385 if (tolerant) {
386 return std::make_pair (dims, false);
387 }
388 std::ostringstream os;
389 os << "Invalid Matrix Market dimensions on line " << lineNumber
390 << ": dimensions must be non-negative, got "
391 << dims[0] << " " << dims[1] << " " << dims[2];
392 throw std::invalid_argument(os.str());
393 }
394 }
395 return std::make_pair (dims, true);
396 }
397 };
398
433 template<class Callback,
434 class Ordinal,
435 class Scalar,
437 class CoordDataReader : public CoordDataReaderBase<Callback, Ordinal> {
438 public:
452
461
464
465 protected:
466 bool
467 readLine (const std::string& theLine,
468 const size_t lineNumber,
469 const bool tolerant);
470 };
471
472#ifdef HAVE_TEUCHOS_COMPLEX
473 // Partial specialization for complex Scalar types.
474 template<class Callback, class Ordinal, class Scalar>
475 class CoordDataReader<Callback, Ordinal, Scalar, true> :
476 public CoordDataReaderBase<Callback, Ordinal> {
477 public:
479 CoordDataReaderBase<Callback, Ordinal> (adder)
480 {}
481
483 CoordDataReaderBase<Callback, Ordinal> (null)
484 {}
485
486 virtual ~CoordDataReader() {};
487
488 protected:
489 bool
490 readLine (const std::string& theLine,
491 const size_t lineNumber,
492 const bool tolerant)
493 {
494 typedef Teuchos::ScalarTraits<Scalar> STS;
495 typedef typename STS::magnitudeType Real;
496
497 Ordinal rowIndex;
498 Ordinal colIndex;
499 Scalar value;
500
501 Real realPart, imagPart;
502 const bool localSuccess =
503 readComplexLine (theLine, rowIndex, colIndex, realPart, imagPart,
504 lineNumber, tolerant);
505 if (localSuccess) {
506 // Assume that assignment from std::complex<Real> to Scalar
507 // (which itself is complex-valued) is valid. We have to do
508 // this, since the C++ compiler may not be smart enough to
509 // assume here (when it instantiates the templates) that
510 // Scalar is an std::complex<Real> -- even though it has to
511 // be, if STS::isComplex is true (which as of 31 Jan 2011,
512 // only holds for std::complex<T>).
513 value = std::complex<Real> (realPart, imagPart);
514
515 // Now that we've read in the (i, j, A_ij) triple
516 // successfully, we can add the entry to the sparse matrix.
517 (*(this->adder_)) (rowIndex, colIndex, value);
518 }
519 return localSuccess;
520 }
521 };
522#endif // HAVE_TEUCHOS_COMPLEX
523
524 // Partial specialization for real Scalar types.
525 template<class Callback, class Ordinal, class Scalar>
526 class CoordDataReader<Callback, Ordinal, Scalar, false> :
527 public CoordDataReaderBase<Callback, Ordinal> {
528 public:
529 CoordDataReader (const Teuchos::RCP<Callback>& adder) :
530 CoordDataReaderBase<Callback, Ordinal> (adder)
531 {}
532
534 CoordDataReaderBase<Callback, Ordinal> (null)
535 {}
536
537 virtual ~CoordDataReader() {};
538
539 protected:
540 bool
541 readLine (const std::string& theLine,
542 const size_t lineNumber,
543 const bool tolerant)
544 {
545 Ordinal rowIndex;
546 Ordinal colIndex;
547 Scalar value;
548 const bool localSuccess = readRealLine (theLine, rowIndex, colIndex,
549 value, lineNumber, tolerant);
550 if (localSuccess) {
551 // Now that we've read in the (i, j, A_ij) triple
552 // successfully, we can add the entry to the sparse matrix.
553 (*(this->adder_)) (rowIndex, colIndex, value);
554 }
555 return localSuccess;
556 }
557 };
558
559
582 template<class Callback, class Ordinal>
583 class CoordPatternReader : public CoordDataReaderBase<Callback, Ordinal> {
584 public:
598 CoordDataReaderBase<Callback, Ordinal> (adder)
599 {}
600
609 CoordDataReaderBase<Callback, Ordinal> (null)
610 {}
611
614
615 protected:
616 bool
617 readLine (const std::string& theLine,
618 const size_t lineNumber,
619 const bool tolerant)
620 {
621 Ordinal rowIndex;
622 Ordinal colIndex;
623 const bool localSuccess =
624 readPatternLine (theLine, rowIndex, colIndex, lineNumber, tolerant);
625 if (localSuccess) {
626 // Now that we've read in the (i, j) pair successfully, we
627 // can add the entry to the sparse graph.
628 (*(this->adder_)) (rowIndex, colIndex);
629 }
630 return localSuccess;
631 }
632 };
633
634 } // namespace MatrixMarket
635} // namespace Teuchos
636
637#endif // __Teuchos_MatrixMarket_CoordDataReader_hpp
Reference-counted pointer class and non-member templated function implementations.
Defines basic traits for the scalar field type.
Common functionality of a coordinate-format sparse matrix or graph data reader.
virtual ~CoordDataReaderBase()
Virtual destructor for safety and happy compilers.
virtual std::pair< bool, std::vector< size_t > > read(std::istream &in, const size_t startingLineNumber, const bool tolerant, const bool debug=false)
Read in all the data from the given input stream.
std::pair< Teuchos::Tuple< Ordinal, 3 >, bool > readDimensions(std::istream &in, size_t &lineNumber, const bool tolerant=false)
Read (numRows, numCols, numNonzeros).
Teuchos::RCP< Callback > adder_
Closure that knows how to add entries to the sparse graph or matrix.
CoordDataReaderBase(const Teuchos::RCP< Callback > &adder)
Constructor with "adder" argument.
virtual bool readLine(const std::string &theLine, const size_t lineNumber, const bool tolerant)=0
Read in the data from a single line of the input stream.
void setAdder(const Teuchos::RCP< Callback > &adder)
Set the Adder object.
Coordinate-format sparse matrix data reader.
CoordDataReader()
No-argument constructor.
virtual ~CoordDataReader()
Virtual destructor for safety and happy compilers.
CoordDataReader(const Teuchos::RCP< Callback > &adder)
Constructor with "adder" argument.
bool readLine(const std::string &theLine, const size_t lineNumber, const bool tolerant)
Read in the data from a single line of the input stream.
CoordPatternReader(const Teuchos::RCP< Callback > &adder)
Constructor with "adder" argument.
virtual ~CoordPatternReader()
Virtual destructor for safety and happy compilers.
bool readLine(const std::string &theLine, const size_t lineNumber, const bool tolerant)
Read in the data from a single line of the input stream.
Smart reference counting pointer class for automatic garbage collection.
Statically sized simple array (tuple) class.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
static const bool isComplex
Determines if scalar type is std::complex.