Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Tpetra_Details_CrsPadding.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 TPETRA_DETAILS_CRSPADDING_HPP
11 #define TPETRA_DETAILS_CRSPADDING_HPP
12 
14 #include "Tpetra_Util.hpp"
15 #include <algorithm>
16 #include <iostream>
17 #include <memory>
18 #include <sstream>
19 #include <vector>
20 
21 namespace Tpetra {
22  namespace Details {
23 
27  template<class LocalOrdinal, class GlobalOrdinal>
28  class CrsPadding {
29  private:
30  using LO = LocalOrdinal;
31  using GO = GlobalOrdinal;
32 
33  enum class Phase {
34  SAME,
35  PERMUTE,
36  IMPORT
37  };
38 
39  public:
40  CrsPadding(const int myRank,
41  const size_t /* numSameIDs */,
42  const size_t /* numPermutes */)
43  : myRank_(myRank)
44  {}
45 
46  CrsPadding(const int myRank,
47  const size_t /* numImports */)
48  : myRank_(myRank)
49  {}
50 
51  void
52  update_same(
53  const LO targetLocalIndex,
54  GO tgtGblColInds[],
55  const size_t origNumTgtEnt,
56  const bool tgtIsUnique,
57  GO srcGblColInds[],
58  const size_t origNumSrcEnt,
59  const bool srcIsUnique)
60  {
61  const LO whichSame = targetLocalIndex;
62  update_impl(Phase::SAME, whichSame, targetLocalIndex,
63  tgtGblColInds, origNumTgtEnt, tgtIsUnique,
64  srcGblColInds, origNumSrcEnt, srcIsUnique);
65  }
66 
67  void
68  update_permute(
69  const LO whichPermute, // index in permuteFrom/To
70  const LO targetLocalIndex,
71  GO tgtGblColInds[],
72  const size_t origNumTgtEnt,
73  const bool tgtIsUnique,
74  GO srcGblColInds[],
75  const size_t origNumSrcEnt,
76  const bool srcIsUnique)
77  {
78  update_impl(Phase::PERMUTE, whichPermute, targetLocalIndex,
79  tgtGblColInds, origNumTgtEnt, tgtIsUnique,
80  srcGblColInds, origNumSrcEnt, srcIsUnique);
81  }
82 
83  void
84  update_import(
85  const LO whichImport,
86  const LO targetLocalIndex,
87  GO tgtGblColInds[],
88  const size_t origNumTgtEnt,
89  const bool tgtIsUnique,
90  GO srcGblColInds[],
91  const size_t origNumSrcEnt,
92  const bool srcIsUnique)
93  {
94  update_impl(Phase::IMPORT, whichImport, targetLocalIndex,
95  tgtGblColInds, origNumTgtEnt, tgtIsUnique,
96  srcGblColInds, origNumSrcEnt, srcIsUnique);
97  }
98 
99  void print(std::ostream& out) const {
100  const size_t maxNumToPrint =
102  const size_t size = entries_.size();
103  out << "entries: [";
104  size_t k = 0;
105  for (const auto& keyval : entries_) {
106  if (k > maxNumToPrint) {
107  out << "...";
108  break;
109  }
110  out << "(" << keyval.first << ", ";
111  Details::verbosePrintArray(out, keyval.second,
112  "Global column indices", maxNumToPrint);
113  out << ")";
114  if (k + size_t(1) < size) {
115  out << ", ";
116  }
117  ++k;
118  }
119  out << "]";
120  }
121 
122  struct Result {
123  size_t numInSrcNotInTgt;
124  bool found;
125  };
126 
134  Result
135  get_result(const LO targetLocalIndex) const
136  {
137  auto it = entries_.find(targetLocalIndex);
138  if (it == entries_.end()) {
139  return {0, false};
140  }
141  else {
142  return {it->second.size(), true};
143  }
144  }
145 
146  private:
147  void
148  update_impl(
149  const Phase phase,
150  const LO whichImport,
151  const LO targetLocalIndex,
152  GO tgtGblColInds[],
153  const size_t origNumTgtEnt,
154  const bool tgtIsUnique,
155  GO srcGblColInds[],
156  const size_t origNumSrcEnt,
157  const bool srcIsUnique)
158  {
159  using std::endl;
160  std::unique_ptr<std::string> prefix;
161  if (verbose_) {
162  prefix = createPrefix("update_impl");
163  std::ostringstream os;
164  os << *prefix << "Start: "
165  << "targetLocalIndex=" << targetLocalIndex
166  << ", origNumTgtEnt=" << origNumTgtEnt
167  << ", origNumSrcEnt=" << origNumSrcEnt << endl;
168  std::cerr << os.str();
169  }
170 
171  // FIXME (08 Feb 2020) We only need to sort and unique
172  // tgtGblColInds if we haven't already seen it before.
173  size_t newNumTgtEnt = origNumTgtEnt;
174  auto tgtEnd = tgtGblColInds + origNumTgtEnt;
175  std::sort(tgtGblColInds, tgtEnd);
176  if (! tgtIsUnique) {
177  tgtEnd = std::unique(tgtGblColInds, tgtEnd);
178  newNumTgtEnt = size_t(tgtEnd - tgtGblColInds);
179  TEUCHOS_ASSERT( newNumTgtEnt <= origNumTgtEnt );
180  }
181 
182  if (verbose_) {
183  std::ostringstream os;
184  os << *prefix << "finished src; process tgt" << endl;
185  std::cerr << os.str();
186  }
187 
188  size_t newNumSrcEnt = origNumSrcEnt;
189  auto srcEnd = srcGblColInds + origNumSrcEnt;
190  std::sort(srcGblColInds, srcEnd);
191  if (! srcIsUnique) {
192  srcEnd = std::unique(srcGblColInds, srcEnd);
193  newNumSrcEnt = size_t(srcEnd - srcGblColInds);
194  TEUCHOS_ASSERT( newNumSrcEnt <= origNumSrcEnt );
195  }
196 
197  merge_with_current_state(phase, whichImport, targetLocalIndex,
198  tgtGblColInds, newNumTgtEnt,
199  srcGblColInds, newNumSrcEnt);
200  if (verbose_) {
201  std::ostringstream os;
202  os << *prefix << "Done" << endl;
203  std::cerr << os.str();
204  }
205  }
206 
207  std::vector<GO>&
208  get_difference_col_inds(const Phase /* phase */,
209  const LO /* whichIndex */,
210  const LO tgtLclRowInd)
211  {
212  return entries_[tgtLclRowInd];
213  }
214 
215  void
216  merge_with_current_state(
217  const Phase phase,
218  const LO whichIndex,
219  const LO tgtLclRowInd,
220  const GO tgtColInds[], // sorted & merged
221  const size_t numTgtEnt,
222  const GO srcColInds[], // sorted & merged
223  const size_t numSrcEnt)
224  {
225  using std::endl;
226  std::unique_ptr<std::string> prefix;
227  if (verbose_) {
228  prefix = createPrefix("merge_with_current_state");
229  std::ostringstream os;
230  os << *prefix << "Start: "
231  << "tgtLclRowInd=" << tgtLclRowInd
232  << ", numTgtEnt=" << numTgtEnt
233  << ", numSrcEnt=" << numSrcEnt << endl;
234  std::cerr << os.str();
235  }
236  // We only need to accumulate those source indices that are
237  // not already target indices. This is because we always have
238  // the target indices on input to this function, so there's no
239  // need to store them here again. That still could be a lot
240  // to store, but it's better than duplicating target matrix
241  // storage.
242  //
243  // This means that consumers of this data structure need to
244  // treat entries_[tgtLclRowInd].size() as an increment, not as
245  // the required new allocation size itself.
246  //
247  // We store
248  //
249  // difference(union(incoming source indices,
250  // already stored source indices),
251  // target indices)
252 
253  auto tgtEnd = tgtColInds + numTgtEnt;
254  auto srcEnd = srcColInds + numSrcEnt;
255 
256  // At least one input source index isn't in the target.
257  std::vector<GO>& diffColInds =
258  get_difference_col_inds(phase, whichIndex, tgtLclRowInd);
259  const size_t oldDiffNumEnt = diffColInds.size();
260 
261  if (oldDiffNumEnt == 0) {
262  if (verbose_) {
263  std::ostringstream os;
264  os << *prefix << "oldDiffNumEnt=0; call "
265  "set_difference(src,tgt,diff)" << endl;
266  std::cerr << os.str();
267  }
268  diffColInds.resize(numSrcEnt);
269  auto diffEnd = std::set_difference(srcColInds, srcEnd,
270  tgtColInds, tgtEnd,
271  diffColInds.begin());
272  const size_t newLen(diffEnd - diffColInds.begin());
273  TEUCHOS_ASSERT( newLen <= numSrcEnt );
274  diffColInds.resize(newLen);
275  }
276  else {
277  // scratch = union(srcColInds, diffColInds);
278  // diffColInds = difference(scratch, tgtColInds);
279 
280  const size_t maxUnionSize = numSrcEnt + oldDiffNumEnt;
281  if (verbose_) {
282  std::ostringstream os;
283  os << *prefix << "oldDiffNumEnt=" << oldDiffNumEnt
284  << ", maxUnionSize=" << maxUnionSize
285  << "; call set_union(src,diff,union)" << endl;
286  std::cerr << os.str();
287  }
288  if (scratchColInds_.size() < maxUnionSize) {
289  scratchColInds_.resize(maxUnionSize);
290  }
291  auto unionBeg = scratchColInds_.begin();
292  auto unionEnd = std::set_union(srcColInds, srcEnd,
293  diffColInds.begin(), diffColInds.end(),
294  unionBeg);
295  const size_t unionSize(unionEnd - unionBeg);
296  TEUCHOS_ASSERT( unionSize <= maxUnionSize );
297 
298  if (verbose_) {
299  std::ostringstream os;
300  os << *prefix << "oldDiffNumEnt=" << oldDiffNumEnt
301  << ", unionSize=" << unionSize << "; call "
302  "set_difference(union,tgt,diff)" << endl;
303  std::cerr << os.str();
304  }
305  diffColInds.resize(unionSize);
306  auto diffEnd = std::set_difference(unionBeg, unionEnd,
307  tgtColInds, tgtEnd,
308  diffColInds.begin());
309  const size_t diffLen(diffEnd - diffColInds.begin());
310  TEUCHOS_ASSERT( diffLen <= unionSize );
311  diffColInds.resize(diffLen);
312  }
313 
314  if (verbose_) {
315  std::ostringstream os;
316  os << *prefix << "Done" << endl;
317  std::cerr << os.str();
318  }
319  }
320 
321  std::unique_ptr<std::string>
322  createPrefix(const char funcName[])
323  {
324  std::ostringstream os;
325  os << "Proc " << myRank_ << ": CrsPadding::" << funcName
326  << ": ";
327  return std::unique_ptr<std::string>(new std::string(os.str()));
328  }
329 
330  // imports may overlap with sames and/or permutes, so it makes
331  // sense to store them all in one map.
332  std::map<LO, std::vector<GO> > entries_;
333  std::vector<GO> scratchColInds_;
334  int myRank_ = -1;
335  bool verbose_ = Behavior::verbose("CrsPadding");
336  };
337  } // namespace Details
338 } // namespace Tpetra
339 
340 #endif // TPETRA_DETAILS_CRSPADDING_HPP
Result get_result(const LO targetLocalIndex) const
For a given target matrix local row index, return the number of unique source column indices to merge...
void verbosePrintArray(std::ostream &out, const ArrayType &x, const char name[], const size_t maxNumToPrint)
Print min(x.size(), maxNumToPrint) entries of x.
void sort(View &view, const size_t &size)
Convenience wrapper for std::sort for host-accessible views.
Keep track of how much more space a CrsGraph or CrsMatrix needs, when the graph or matrix is the targ...
static bool verbose()
Whether Tpetra is in verbose mode.
Stand-alone utility functions and macros.
static size_t verbosePrintCountThreshold()
Number of entries below which arrays, lists, etc. will be printed in debug mode.
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra&#39;s behavior.