Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_MatrixMarket_Raw_Graph_Adder.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_Raw_Graph_Adder_hpp
11#define __Teuchos_MatrixMarket_Raw_Graph_Adder_hpp
12
14#include "Teuchos_ArrayRCP.hpp"
15#include "Teuchos_CommHelpers.hpp"
17#include "Teuchos_MatrixMarket_Banner.hpp"
18#include "Teuchos_MatrixMarket_CoordDataReader.hpp"
19
20#include <algorithm>
21#include <fstream>
22#include <iostream>
23#include <iterator>
24#include <vector>
25#include <stdexcept>
26
27
28namespace Teuchos {
29 namespace MatrixMarket {
30 namespace Raw {
53 template<class Ordinal>
55 public:
58 rowIndex_ (Teuchos::OrdinalTraits<Ordinal>::invalid ()),
59 colIndex_ (Teuchos::OrdinalTraits<Ordinal>::invalid ())
60 {}
61
63 GraphElement (const Ordinal i, const Ordinal j) :
64 rowIndex_ (i), colIndex_ (j) {}
65
67 bool operator== (const GraphElement& rhs) const {
68 return rowIndex_ == rhs.rowIndex_ && colIndex_ == rhs.colIndex_;
69 }
70
72 bool operator!= (const GraphElement& rhs) const {
73 return ! (*this == rhs);
74 }
75
77 bool operator< (const GraphElement& rhs) const {
78 if (rowIndex_ < rhs.rowIndex_)
79 return true;
80 else if (rowIndex_ > rhs.rowIndex_)
81 return false;
82 else { // equal
83 return colIndex_ < rhs.colIndex_;
84 }
85 }
86
88 Ordinal rowIndex() const { return rowIndex_; }
89
91 Ordinal colIndex() const { return colIndex_; }
92
93 private:
94 Ordinal rowIndex_, colIndex_;
95 };
96
101 template<class Ordinal>
102 std::ostream&
103 operator<< (std::ostream& out, const GraphElement<Ordinal>& elt)
104 {
105 out << elt.rowIndex () << " " << elt.colIndex ();
106 return out;
107 }
108
128 template<class Ordinal>
130 public:
131 typedef Ordinal index_type;
133 typedef typename std::vector<element_type>::size_type size_type;
134
146 expectedNumRows_(0),
147 expectedNumCols_(0),
148 expectedNumEntries_(0),
149 seenNumRows_(0),
150 seenNumCols_(0),
151 seenNumEntries_(0),
152 tolerant_ (true),
153 debug_ (false)
154 {}
155
174 const Ordinal expectedNumCols,
175 const Ordinal expectedNumEntries,
176 const bool tolerant=false,
177 const bool debug=false) :
178 expectedNumRows_(expectedNumRows),
179 expectedNumCols_(expectedNumCols),
180 expectedNumEntries_(expectedNumEntries),
181 seenNumRows_(0),
182 seenNumCols_(0),
183 seenNumEntries_(0),
184 tolerant_ (tolerant),
185 debug_ (debug)
186 {}
187
208 void
209 operator() (const Ordinal i,
210 const Ordinal j,
211 const bool countAgainstTotal=true)
212 {
213 if (! tolerant_) {
214 const bool indexPairOutOfRange = i < 1 || j < 1 ||
215 i > expectedNumRows_ || j > expectedNumCols_;
216
218 std::invalid_argument, "Graph is " << expectedNumRows_ << " x "
219 << expectedNumCols_ << ", so entry A(" << i << "," << j
220 << ") is out of range.");
221 if (countAgainstTotal) {
222 TEUCHOS_TEST_FOR_EXCEPTION(seenNumEntries_ >= expectedNumEntries_,
223 std::invalid_argument, "Cannot add entry A(" << i << "," << j
224 << ") to graph; already have expected number "
225 "of entries " << expectedNumEntries_ << ".");
226 }
227 }
228 // i and j are 1-based indices, but we store them as 0-based.
229 elts_.push_back (element_type (i-1, j-1));
230
231 // Keep track of the rightmost column containing a matrix
232 // entry, and the bottommost row containing a matrix entry.
233 // This gives us a lower bound for the dimensions of the
234 // graph, and a check for the reported dimensions of the
235 // graph in the Matrix Market file.
236 seenNumRows_ = std::max (seenNumRows_, i);
237 seenNumCols_ = std::max (seenNumCols_, j);
238 if (countAgainstTotal) {
239 ++seenNumEntries_;
240 }
241 }
242
259 void
260 print (std::ostream& out, const bool doMerge, const bool replace=false)
261 {
262 if (doMerge) {
264 (replace, std::logic_error, "replace = true not implemented!");
265 //merge (replace);
266 merge ();
267 } else {
268 std::sort (elts_.begin(), elts_.end());
269 }
270 // Print out the results, delimited by newlines.
271 typedef std::ostream_iterator<element_type> iter_type;
272 std::copy (elts_.begin(), elts_.end(), iter_type (out, "\n"));
273 }
274
288 std::pair<size_type, size_type>
290 {
291 typedef typename std::vector<element_type>::iterator iter_type;
292
293 // Start with a sorted container. GraphElement objects sort in
294 // lexicographic order of their (row, column) indices, for
295 // easy conversion to CSR format. If you expect that the
296 // elements will usually be sorted in the desired order, you
297 // can check first whether they are already sorted. We have
298 // no such expectation, so we don't even bother to spend the
299 // extra O(# entries) operations to check.
300 std::sort (elts_.begin(), elts_.end());
301
302 // Remove duplicate elements from the sequence
304 it = std::unique(elts_.begin(), elts_.end());
305 size_type numUnique = std::distance(elts_.begin(),it);
306 const size_type numRemoved = elts_.size() - numUnique;
307 elts_.resize( std::distance(elts_.begin(),it) );
308 elts_.resize (numUnique);
309 return std::make_pair (numUnique, numRemoved);
310 }
311
343 void
345 size_type& numRemovedElts,
348 {
349 using Teuchos::arcp;
350 using Teuchos::ArrayRCP;
351
352 std::pair<size_type, size_type> mergeResult = merge();
353
354 // At this point, elts_ is already in CSR order.
355 // Now we can allocate and fill the ind array.
356 ArrayRCP<Ordinal> ind = arcp<Ordinal> (elts_.size ());
357
358 // Number of rows in the graph.
359 const Ordinal nrows = tolerant_ ? seenNumRows_ : expectedNumRows_;
361
362 // Copy over the elements, and fill in the ptr array with
363 // offsets. Note that merge() sorted the entries by row
364 // index, so we can assume the row indices are increasing in
365 // the list of entries.
366 Ordinal curRow = 0;
367 Ordinal curInd = 0;
368 typedef typename std::vector<element_type>::const_iterator iter_type;
369 ptr[0] = 0; // ptr always has at least one entry.
370 for (iter_type it = elts_.begin(); it != elts_.end(); ++it) {
371 const Ordinal i = it->rowIndex ();
372 const Ordinal j = it->colIndex ();
373
374 TEUCHOS_TEST_FOR_EXCEPTION(i < curRow, std::logic_error, "The "
375 "current graph entry's row index " << i << " is less then what "
376 "should be the current row index lower bound " << curRow << ".");
377 for (Ordinal k = curRow+1; k <= i; ++k) {
378 ptr[k] = curInd;
379 }
380 curRow = i;
381
383 static_cast<size_t> (curInd) >= elts_.size (),
384 std::logic_error, "The current index " << curInd << " into ind "
385 "is >= the number of matrix entries " << elts_.size ()
386 << ".");
387 ind[curInd] = j;
388 ++curInd;
389 }
390 for (Ordinal k = curRow+1; k <= nrows; ++k) {
391 ptr[k] = curInd;
392 }
393
394 // Assign to outputs here, to ensure the strong exception
395 // guarantee (assuming that ArrayRCP's operator= doesn't
396 // throw).
397 rowptr = ptr;
398 colind = ind;
401 }
402
404 const std::vector<element_type>& getEntries() const {
405 return elts_;
406 }
407
409 void clear() {
410 seenNumRows_ = 0;
411 seenNumCols_ = 0;
412 seenNumEntries_ = 0;
413 elts_.resize (0);
414 }
415
419 const Ordinal numRows() const { return seenNumRows_; }
420
424 const Ordinal numCols() const { return seenNumCols_; }
425
426 private:
427 Ordinal expectedNumRows_, expectedNumCols_, expectedNumEntries_;
428 Ordinal seenNumRows_, seenNumCols_, seenNumEntries_;
429 bool tolerant_;
430 bool debug_;
431
433 std::vector<element_type> elts_;
434 };
435 } // namespace Raw
436 } // namespace MatrixMarket
437} // namespace Teuchos
438
439#endif // #ifndef __Teuchos_MatrixMarket_Raw_Graph_Adder_hpp
Teuchos header file which uses auto-configuration information to include necessary C++ headers.
Templated Parameter List class.
Reference-counted smart pointer for managing arrays.
To be used with Checker for "raw" sparse matrix input.
GraphAdder(const Ordinal expectedNumRows, const Ordinal expectedNumCols, const Ordinal expectedNumEntries, const bool tolerant=false, const bool debug=false)
Standard constructor.
void clear()
Clear all the added graph entries and reset metadata.
const Ordinal numCols() const
Computed number of columns.
const std::vector< element_type > & getEntries() const
A temporary const view of the entries of the graph.
std::pair< size_type, size_type > merge()
Merge duplicate elements.
void mergeAndConvertToCSR(size_type &numUniqueElts, size_type &numRemovedElts, Teuchos::ArrayRCP< Ordinal > &rowptr, Teuchos::ArrayRCP< Ordinal > &colind)
Merge duplicate elements and convert to zero-based CSR.
void operator()(const Ordinal i, const Ordinal j, const bool countAgainstTotal=true)
Add an entry to the sparse graph.
const Ordinal numRows() const
Computed number of rows.
void print(std::ostream &out, const bool doMerge, const bool replace=false)
Print the sparse graph data.
Ordinal rowIndex() const
Row index (zero-based) of this GraphElement.
GraphElement()
Default constructor: an invalid entry of the graph.
Ordinal colIndex() const
Column index (zero-based) of this GraphElement.
GraphElement(const Ordinal i, const Ordinal j)
Create a sparse graph entry at (i,j).
bool operator==(const GraphElement &rhs) const
Compare row and column indices.
bool operator<(const GraphElement &rhs) const
Lexicographic order first by row index, then by column index.
bool operator!=(const GraphElement &rhs) const
Compare row and column indices.
Smart reference counting pointer class for automatic garbage collection.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Matrix Market file utilities.
"Raw" input of sparse matrices from Matrix Market files.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
This structure defines some basic traits for the ordinal field type.