Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
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
21namespace 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
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Stand-alone utility functions and macros.
static bool verbose()
Whether Tpetra is in verbose mode.
static size_t verbosePrintCountThreshold()
Number of entries below which arrays, lists, etc. will be printed in debug mode.
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...
Nonmember function that computes a residual Computes R = B - A * X.
void verbosePrintArray(std::ostream &out, const ArrayType &x, const char name[], const size_t maxNumToPrint)
Print min(x.size(), maxNumToPrint) entries of x.
std::unique_ptr< std::string > createPrefix(const int myRank, const char prefix[])
Create string prefix for each line of verbose output.
Namespace Tpetra contains the class and methods constituting the Tpetra library.