Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 
27 template<typename T>
28 struct type_name
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 
39 DECL_TYPE_NAME(int);
40 DECL_TYPE_NAME(long);
41 DECL_TYPE_NAME(long long);
42 
44 // Tests for correctness
45 static const std::string fail = "FAIL ";
46 static const std::string pass = " ";
47 
48 // Test for correct number of unique Gids
49 void 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
58 template <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
80 template <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
102 template <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 
129 template <typename gno_t>
130 void 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 
174 template <typename gno_t>
175 void 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 
227 template <typename gno_t>
228 void 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 
291 template <typename gno_t>
292 void 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 
338 template <typename gno_t>
339 void 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 
403 template <typename gno_t>
404 void 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 
459 int 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 }
void checkNUnique(std::string &name, size_t nUniqueGids, size_t nExpected)
void test3(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void test6(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
void test2(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void test5(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
int main(int narg, char **arg)
Definition: coloring1.cpp:164
Tpetra::Map map_t
Definition: mapRemotes.cpp:25
static const char * name()
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
static const std::string fail
void test1(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void checkNLocallyUnique(std::string &name, std::vector< gno_t > &gids, size_t nExpected)
static const std::string pass
Tpetra::global_size_t global_size_t
void checkMaxGid(std::string &name, std::vector< gno_t > &gids, gno_t maxExpected, const Teuchos::Comm< int > &comm)
Convert keys stored in std::vector to unique Gids stored in std::vector.
void checkMinGid(std::string &name, std::vector< gno_t > &gids, gno_t minExpected, const Teuchos::Comm< int > &comm)
void test4(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
#define DECL_TYPE_NAME(x)