Zoltan2
Loading...
Searching...
No Matches
findUniqueGids.cpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Zoltan2: A package of combinatorial algorithms for scientific computing
4//
5// Copyright 2012 NTESS and the Zoltan2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10// Program to testing Zoltan2::findUniqueGids capability
11// Input: Vector of keys: each key is an array with N entries
12// Result vector to be filled by findUniqueGids
13// Output: Filled result vector
14
15
16#include <iostream>
17#include <vector>
18#include <array>
19#include <unordered_set>
20#include <string>
21#include <typeinfo>
22
23#include <Teuchos_Comm.hpp>
24#include <Teuchos_DefaultComm.hpp>
26
27template<typename T>
29{
30 static const char* name() {
31 std::cout << "You are missing a DECL_TYPE_NAME" << std::endl;
32 return(NULL);
33 }
34};
35
36#define DECL_TYPE_NAME(x) \
37 template<> struct type_name<x> { static const char* name() {return #x;} }
38
41DECL_TYPE_NAME(long long);
42
44// Tests for correctness
45static const std::string fail = "FAIL ";
46static const std::string pass = " ";
47
48// Test for correct number of unique Gids
49void checkNUnique(std::string &name, size_t nUniqueGids, size_t nExpected)
50{
51 if (nUniqueGids != nExpected)
52 std::cout << fail << name
53 << "nUniqueGids " << nUniqueGids << " != " << nExpected
54 << std::endl;
55}
56
57// Test for correct maximum Gid
58template <typename gno_t>
60 std::string &name,
61 std::vector<gno_t> &gids,
62 gno_t maxExpected,
63 const Teuchos::Comm<int> &comm
64)
65{
66 gno_t maxGid = 0, gmaxGid = 0;
67 size_t len = gids.size();
68 for (size_t i = 0; i < len; i++)
69 if (gids[i] > maxGid) maxGid = gids[i];
70
71 Teuchos::reduceAll<int, gno_t>(comm, Teuchos::REDUCE_MAX, 1,
72 &maxGid, &gmaxGid);
73 if (gmaxGid != maxExpected)
74 std::cout << fail << name
75 << "max Gid " << gmaxGid << " != " << maxExpected
76 << std::endl;
77}
78
79// Test for correct minimum Gid
80template <typename gno_t>
82 std::string &name,
83 std::vector<gno_t> &gids,
84 gno_t minExpected,
85 const Teuchos::Comm<int> &comm
86)
87{
88 gno_t minGid = std::numeric_limits<gno_t>::max(), gminGid;
89 size_t len = gids.size();
90 for (size_t i = 0; i < len; i++)
91 if (gids[i] < minGid) minGid = gids[i];
92
93 Teuchos::reduceAll<int, gno_t>(comm, Teuchos::REDUCE_MIN, 1,
94 &minGid, &gminGid);
95 if (gminGid != minExpected)
96 std::cout << fail << name
97 << "min Gid " << gminGid << " != " << minExpected
98 << std::endl;
99}
100
101// Test for number of locally unique Gids
102template <typename gno_t>
104 std::string &name,
105 std::vector<gno_t> &gids,
106 size_t nExpected)
107{
108 size_t gidsLen = gids.size();
109 std::unordered_set<gno_t> gidsSet(gidsLen);
110
111 size_t nDups = 0;
112 for (size_t i = 0; i < gidsLen; i++) {
113 if (gidsSet.find(gids[i]) != gidsSet.end()) {
114 // Gid is already found locally
115 nDups++;
116 }
117 else
118 gidsSet.insert(gids[i]);
119 }
120 size_t nUnique = gidsLen - nDups;
121 if (nUnique != nExpected)
122 std::cout << fail << name
123 << "num locally unique Gids " << nUnique << " != " << nExpected
124 << std::endl;
125}
126
128
129template <typename gno_t>
130void test1(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
131{
132 // Test 1:
133 // Key has only one entry
134 // Each proc has me+1 keys
135 // Keys are in range [1,np]
136 int me = comm->getRank();
137 int np = comm->getSize();
138
139 std::string name = std::string(" test1: ")
140 + std::string(type_name<gno_t>::name());
141 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
142
143 typedef std::array<gno_t, 1> zkey_t;
144 typedef std::vector<zkey_t> keyvec_t;
145 typedef std::vector<gno_t> gidvec_t;
146
147 const size_t nKeys = me+1;
148 keyvec_t keys(nKeys);
149 gidvec_t gids(nKeys);
150
151 for (size_t i = 0; i < nKeys; i++) {
152 zkey_t k;
153 k[0] = i+1;
154 keys[i] = k;
155 }
156
157 size_t nUniqueGids = Zoltan2::findUniqueGids<zkey_t, gno_t>(keys,gids,*comm);
158
159 // Test for correctness
160 if (me == 0)
161 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
162
163 checkNUnique(name, nUniqueGids, size_t(np));
164
165 checkMaxGid(name, gids, gno_t(np-1), *comm);
166
167 checkMinGid(name, gids, gno_t(0), *comm);
168
169 checkNLocallyUnique(name, gids, nKeys);
170}
171
173
174template <typename gno_t>
175void test2(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
176{
177 // Test 2:
178 // Key has two entries
179 // Each proc has six keys
180 // Three Keys are {rank, x} for x in {1, 2, 3}
181 // Three Keys are {(rank+x)%np, x} for x in {1, 2, 3}
182 // Each rank has three unique and three non-unique keys
183 int me = comm->getRank();
184 int np = comm->getSize();
185
186 std::string name = std::string(" test2: ")
187 + std::string(type_name<gno_t>::name());
188 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
189
190 typedef std::array<gno_t, 2> zkey_t;
191 typedef std::vector<zkey_t> keyvec_t;
192 typedef std::vector<gno_t> gidvec_t;
193
194 const size_t nKeys = 6;
195 const size_t nKeysHalf = 3;
196 keyvec_t keys(nKeys);
197 gidvec_t gids(nKeys);
198
199 for (size_t i = 0; i < nKeysHalf; i++) {
200 zkey_t k;
201 k[0] = gno_t(me);
202 k[1] = gno_t(i+1);
203 keys[i] = k;
204 }
205 for (size_t i = 0; i < nKeysHalf; i++) {
206 zkey_t k;
207 k[0] = gno_t((me+i+1)%np);
208 k[1] = gno_t(i+1);
209 keys[i+nKeysHalf] = k;
210 }
211
212 size_t nUniqueGids = Zoltan2::findUniqueGids<zkey_t,gno_t>(keys,gids,*comm);
213
214 // Test for correctness
215 if (me == 0)
216 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
217
218 checkNUnique(name, nUniqueGids, size_t(nKeysHalf*np));
219
220 checkMaxGid(name, gids, gno_t(nKeysHalf*np-1), *comm);
221
222 checkMinGid(name, gids, gno_t(0), *comm);
223
224}
225
227template <typename gno_t>
228void test3(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
229{
230 // Test 3:
231 // Key has three entries
232 // Each proc has 2*np keys
233 // np Keys are {x, x, x} for x in {0, 1, ..., np-1}
234 // np Keys are {rank, rank, x} for x in {0, 1, ..., np-1}
235 // Each proc has one locally duplicated key
236 // Each proc contributes np unique keys
237 int me = comm->getRank();
238 int np = comm->getSize();
239
240 std::string name = std::string(" test3: ")
241 + std::string(type_name<gno_t>::name());
242 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
243
244 typedef std::array<gno_t, 3> zkey_t;
245 typedef std::vector<zkey_t> keyvec_t;
246 typedef std::vector<gno_t> gidvec_t;
247
248 const size_t nKeys = 2*np;
249 const size_t nKeysHalf = np;
250 keyvec_t keys(nKeys);
251 gidvec_t gids(nKeys);
252
253 for (size_t i = 0; i < nKeysHalf; i++) {
254 zkey_t k;
255 k[0] = gno_t(me);
256 k[1] = gno_t(me);
257 k[2] = gno_t(i);
258 keys[i+nKeysHalf] = k;
259 }
260 for (size_t i = 0; i < nKeysHalf; i++) {
261 zkey_t k;
262 k[0] = gno_t(i);
263 k[1] = gno_t(i);
264 k[2] = gno_t(i);
265 keys[i] = k;
266 }
267
268 size_t nUniqueGids = Zoltan2::findUniqueGids<zkey_t,gno_t>(keys,gids,*comm);
269
270 // for (size_t i = 0; i < nKeys; i++)
271 // std::cout << me << " Key " << i << ": "
272 // << keys[i][0] << " " << keys[i][1] << " " << keys[i][2]
273 // << " GID " << gids[i]
274 // << std::endl;
275
276 // Test for correctness
277 if (me == 0)
278 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
279
280 checkNUnique(name, nUniqueGids, size_t(np*np));
281
282 checkMaxGid(name, gids, gno_t(np*np-1), *comm);
283
284 checkMinGid(name, gids, gno_t(0), *comm);
285
286 checkNLocallyUnique(name, gids, size_t(nKeys-1));
287}
288
290
291template <typename gno_t>
292void test4(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
293{
294 // Test 4:
295 // Key has four entries
296 // Each proc has (rank+1)%2 keys; odd-numbered ranks are empty
297 // Keys are all identical {0, 1, 2, 3}
298 int me = comm->getRank();
299
300 std::string name = std::string(" test4: ")
301 + std::string(type_name<gno_t>::name());
302 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
303
304 typedef std::array<gno_t, 4> zkey_t;
305 typedef std::vector<zkey_t> keyvec_t;
306 typedef std::vector<gno_t> gidvec_t;
307
308 const size_t nKeys = (me+1)%2;
309 keyvec_t keys(nKeys);
310 gidvec_t gids(nKeys);
311
312 for (size_t i = 0; i < nKeys; i++) {
313 zkey_t k;
314 k[0] = gno_t(0);
315 k[1] = gno_t(1);
316 k[2] = gno_t(2);
317 k[3] = gno_t(3);
318 keys[i] = k;
319 }
320
321 size_t nUniqueGids = Zoltan2::findUniqueGids<zkey_t,gno_t>(keys,gids,*comm);
322
323 // Test for correctness
324 if (me == 0)
325 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
326
327 checkNUnique(name, nUniqueGids, size_t(1));
328
329 checkMaxGid(name, gids, gno_t(0), *comm);
330
331 checkMinGid(name, gids, gno_t(0), *comm);
332
333 checkNLocallyUnique(name, gids, (nKeys ? size_t(1): size_t(0)));
334}
335
337
338template <typename gno_t>
339void test5(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
340{
341 // Test 5: Same as Test 3 but using the Tpetra Multivector interface.
342 // Key has three entries
343 // Each proc has 2*np keys
344 // np Keys are {x, x, x} for x in {0, 1, ..., np-1}
345 // np Keys are {rank, rank, x} for x in {0, 1, ..., np-1}
346 // Each proc has one locally duplicated key
347 // Each proc contributes np unique keys
348 int me = comm->getRank();
349 int np = comm->getSize();
350
351 std::string name = std::string(" test5: ")
352 + std::string(type_name<gno_t>::name());
353 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
354
355 typedef int lno_t;
356
357 const size_t nVecs = 3;
358 const size_t nKeys = 2*np;
359 const size_t nKeysHalf = np;
360
361 Tpetra::global_size_t gNEntries =
362 Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid();
363
364 typedef Tpetra::Map<lno_t, gno_t> map_t;
365 Teuchos::RCP<const map_t> map = rcp(new map_t(gNEntries, nKeys, 0, comm),
366 true);
367
368 Tpetra::MultiVector<gno_t, lno_t, gno_t> keys(map, nVecs);
369 Tpetra::Vector<gno_t, lno_t, gno_t> gids(map);
370
371 for (size_t i = 0; i < nKeysHalf; i++) {
372 keys.replaceLocalValue(i+nKeysHalf, 0, gno_t(me));
373 keys.replaceLocalValue(i+nKeysHalf, 1, gno_t(me));
374 keys.replaceLocalValue(i+nKeysHalf, 2, gno_t(i));
375 }
376 for (size_t i = 0; i < nKeysHalf; i++) {
377 keys.replaceLocalValue(i, 0, gno_t(i));
378 keys.replaceLocalValue(i, 1, gno_t(i));
379 keys.replaceLocalValue(i, 2, gno_t(i));
380 }
381
382 size_t nUniqueGids = Zoltan2::findUniqueGids<lno_t,gno_t>(keys,gids);
383
384 // Test for correctness
385 if (me == 0)
386 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
387
388 checkNUnique(name, nUniqueGids, size_t(np*np));
389
390 Teuchos::ArrayRCP<const gno_t> gidsData = gids.getData();
391 std::vector<gno_t> gidsVec(nKeys);
392 for (size_t i = 0; i < nKeys; i++) gidsVec[i] = gidsData[i];
393
394 checkMaxGid(name, gidsVec, gno_t(np*np-1), *comm);
395
396 checkMinGid(name, gidsVec, gno_t(0), *comm);
397
398 checkNLocallyUnique(name, gidsVec, size_t(nKeys-1));
399}
400
402
403template <typename gno_t>
404void test6(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
405{
406 // Test 6: Same as Test 4 but using the Tpetra Multivector interface.
407 // Key has four entries
408 // Each proc has (rank+1)%2 keys; odd-numbered ranks are empty
409 // Keys are all identical {0, 1, 2, 3}
410 int me = comm->getRank();
411
412 std::string name = std::string(" test6: ")
413 + std::string(type_name<gno_t>::name());
414 if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
415
416 typedef int lno_t;
417
418 const size_t nVecs = 4;
419 const size_t nKeys = (me+1)%2;
420
421 Tpetra::global_size_t gNEntries =
422 Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid();
423
424 typedef Tpetra::Map<lno_t, gno_t> map_t;
425 Teuchos::RCP<const map_t> map = rcp(new map_t(gNEntries, nKeys, 0, comm),
426 true);
427
428 Tpetra::MultiVector<gno_t, lno_t, gno_t> keys(map, nVecs);
429 Tpetra::Vector<gno_t, lno_t, gno_t> gids(map);
430
431 for (size_t i = 0; i < nKeys; i++) {
432 keys.replaceLocalValue(i, 0, gno_t(0));
433 keys.replaceLocalValue(i, 1, gno_t(1));
434 keys.replaceLocalValue(i, 2, gno_t(2));
435 keys.replaceLocalValue(i, 3, gno_t(3));
436 }
437
438 size_t nUniqueGids = Zoltan2::findUniqueGids<lno_t,gno_t>(keys,gids);
439
440 // Test for correctness
441 if (me == 0)
442 std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
443
444 checkNUnique(name, nUniqueGids, size_t(1));
445
446 Teuchos::ArrayRCP<const gno_t> gidsData = gids.getData();
447 std::vector<gno_t> gidsVec(nKeys);
448 for (size_t i = 0; i < nKeys; i++) gidsVec[i] = gidsData[i];
449
450 checkMaxGid(name, gidsVec, gno_t(0), *comm);
451
452 checkMinGid(name, gidsVec, gno_t(0), *comm);
453
454 checkNLocallyUnique(name, gidsVec, (nKeys ? size_t(1): size_t(0)));
455}
456
458
459int main(int narg, char *arg[])
460{
461 Tpetra::ScopeGuard tscope(&narg, &arg);
462 Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
463
464#ifdef HAVE_TPETRA_INT_INT
465 test1<int>(comm);
466 test2<int>(comm);
467 test3<int>(comm);
468 test4<int>(comm);
469 test5<int>(comm);
470 test6<int>(comm);
471#else
472 if (comm->getRank() == 0)
473 std::cout << "Skipping int tests because Tpetra is not build with "
474 << "GO == int" << std::endl;
475#endif
476
477#ifdef HAVE_TPETRA_INT_LONG
478 test1<long>(comm);
479 test2<long>(comm);
480 test3<long>(comm);
481 test4<long>(comm);
482 test5<long>(comm);
483 test6<long>(comm);
484#else
485 if (comm->getRank() == 0)
486 std::cout << "Skipping long tests because Tpetra is not build with "
487 << "GO == long " << std::endl;
488#endif
489
490#ifdef HAVE_TPETRA_INT_LONG_LONG
491 test1<long long>(comm);
492 test2<long long>(comm);
493 test3<long long>(comm);
494 test4<long long>(comm);
495 test5<long long>(comm);
496 test6<long long>(comm);
497#else
498 if (comm->getRank() == 0)
499 std::cout << "Skipping long long tests because Tpetra is not build with "
500 << "GO == long long" << std::endl;
501#endif
502
503 return 0;
504}
Convert keys stored in std::vector to unique Gids stored in std::vector.
int main()
void checkNUnique(std::string &name, size_t nUniqueGids, size_t nExpected)
void test3(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void checkMinGid(std::string &name, std::vector< gno_t > &gids, gno_t minExpected, const Teuchos::Comm< int > &comm)
void test6(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void test2(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void checkMaxGid(std::string &name, std::vector< gno_t > &gids, gno_t maxExpected, const Teuchos::Comm< int > &comm)
void checkNLocallyUnique(std::string &name, std::vector< gno_t > &gids, size_t nExpected)
void test5(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void test4(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void test1(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
#define DECL_TYPE_NAME(x)
static const std::string fail
static const std::string pass
map_t::local_ordinal_type lno_t
map_t::global_ordinal_type gno_t
Tpetra::Map map_t
static const char * name()