Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
directoryTest_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 <Zoltan2_Standards.hpp>
25 
26 namespace Zoltan2
27 {
28 
29 template <typename key_t, typename gno_t>
31  const std::vector<key_t> &keys,
32  std::vector<gno_t> &gids,
33  Teuchos::RCP<const Teuchos::Comm<int> > &comm
34 )
35 {
36  // Compute the new GIDs
37  const bool bUseLocalIDs = false; // Local IDs not needed
38  int debug_level = 0;
39 
40  typedef int lno_t; // unused
41 
43 
44  directory_t directory(comm, bUseLocalIDs, debug_level);
45 
46  directory.update(keys.size(), &keys[0], NULL, &gids[0], NULL,
48 
49  directory.remap_user_data_as_unique_gids();
50 
51  // Retrieve the global numbers and put in the result gids vector
52  directory.find(keys.size(), &keys[0], NULL, &gids[0], NULL, NULL, false);
53 
54  // using ssize_t can be long* on clang and I get warnings here or in the original
55  // findUniqueGids - using long long specifically is ok. Can we do an MPI type
56  // as size_t safely or is a conversion necessary? TODO but this gives a clean
57  // build result.
58  typedef long long mpi_t;
59  mpi_t nDDEntries = static_cast<mpi_t>(directory.node_map_size());
60  mpi_t nUnique = 0;
61 
62  // TODO use Teuchos
63 #ifdef HAVE_MPI
64  MPI_Allreduce(&nDDEntries, &nUnique, 1, MPI_LONG_LONG, MPI_SUM,
65  Teuchos::getRawMpiComm(*comm));
66 #else
67  MPI_Allreduce(&nDDEntries, &nUnique, 1, MPI_LONG_LONG, MPI_SUM, MPI_COMM_WORLD);
68 #endif
69 
70  return size_t(nUnique);
71 }
72 
73 template<typename T>
74 struct type_name
75 {
76  static const char* name() {
77  std::cout << "You are missing a DECL_TYPE_NAME" << std::endl;
78  return(NULL);
79  }
80 };
81 
82 #define DECL_TYPE_NAME(x) \
83  template<> struct type_name<x> { static const char* name() {return #x;} }
84 
85 DECL_TYPE_NAME(int);
86 DECL_TYPE_NAME(long long);
87 
89 // Tests for correctness
90 static const std::string fail = "FAIL ";
91 static const std::string pass = " ";
92 
93 // Test for correct number of unique Gids
94 void checkNUnique(std::string &name, size_t nUniqueGids, size_t nExpected)
95 {
96  if (nUniqueGids != nExpected)
97  std::cout << fail << name
98  << "nUniqueGids " << nUniqueGids << " != " << nExpected
99  << std::endl;
100 }
101 
102 // Test for correct maximum Gid
103 template <typename gno_t>
105  std::string &name,
106  std::vector<gno_t> &gids,
107  gno_t maxExpected,
108  Teuchos::RCP<const Teuchos::Comm<int> > &comm
109 )
110 {
111  gno_t maxGid = 0, gmaxGid = 0;
112  size_t len = gids.size();
113  for (size_t i = 0; i < len; i++)
114  if (gids[i] > maxGid) maxGid = gids[i];
115 
116  Teuchos::reduceAll<int, gno_t>(*comm, Teuchos::REDUCE_MAX, 1,
117  &maxGid, &gmaxGid);
118  if (gmaxGid != maxExpected)
119  std::cout << fail << name
120  << "max Gid " << gmaxGid << " != " << maxExpected
121  << std::endl;
122 }
123 
124 // Test for correct minimum Gid
125 template <typename gno_t>
127  std::string &name,
128  std::vector<gno_t> &gids,
129  gno_t minExpected,
130  Teuchos::RCP<const Teuchos::Comm<int> > &comm
131 )
132 {
133  gno_t minGid = std::numeric_limits<gno_t>::max(), gminGid;
134  size_t len = gids.size();
135  for (size_t i = 0; i < len; i++)
136  if (gids[i] < minGid) minGid = gids[i];
137 
138  Teuchos::reduceAll<int, gno_t>(*comm, Teuchos::REDUCE_MIN, 1,
139  &minGid, &gminGid);
140  if (gminGid != minExpected)
141  std::cout << fail << name
142  << "min Gid " << gminGid << " != " << minExpected
143  << std::endl;
144 }
145 
146 // Test for number of locally unique Gids
147 template <typename gno_t>
149  std::string &name,
150  std::vector<gno_t> &gids,
151  size_t nExpected)
152 {
153  size_t gidsLen = gids.size();
154  std::unordered_set<gno_t> gidsSet(gidsLen);
155 
156  size_t nDups = 0;
157  for (size_t i = 0; i < gidsLen; i++) {
158  if (gidsSet.find(gids[i]) != gidsSet.end()) {
159  // Gid is already found locally
160  nDups++;
161  }
162  else
163  gidsSet.insert(gids[i]);
164  }
165  size_t nUnique = gidsLen - nDups;
166  if (nUnique != nExpected)
167  std::cout << fail << name
168  << "num locally unique Gids " << nUnique << " != " << nExpected
169  << std::endl;
170 }
171 
173 
174 template <typename gno_t>
175 void test1(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
176 {
177  // Test 1:
178  // Key has only one entry
179  // Each proc has me+1 keys
180  // Keys are in range [1,np]
181  int me = comm->getRank();
182  int np = comm->getSize();
183 
184  std::string name = std::string(" test1: ")
185  + std::string(type_name<gno_t>::name());
186  if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
187 
188  typedef std::array<gno_t, 1> zkey_t;
189  typedef std::vector<zkey_t> keyvec_t;
190  typedef std::vector<gno_t> gidvec_t;
191 
192  const size_t nKeys = me+1;
193  keyvec_t keys(nKeys);
194  gidvec_t gids(nKeys);
195 
196  for (size_t i = 0; i < nKeys; i++) {
197  zkey_t k;
198  k[0] = i+1;
199  keys[i] = k;
200  }
201 
202  size_t nUniqueGids = findUniqueGids<zkey_t, gno_t>(keys,gids,comm);
203 
204  // Test for correctness
205  if (me == 0)
206  std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
207 
208  checkNUnique(name, nUniqueGids, size_t(np));
209 
210  checkMaxGid(name, gids, gno_t(np-1), comm);
211 
212  checkMinGid(name, gids, gno_t(0), comm);
213 
214  checkNLocallyUnique(name, gids, nKeys);
215 }
216 
218 
219 template <typename gno_t>
220 void test2(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
221 {
222  // Test 2:
223  // Key has two entries
224  // Each proc has six keys
225  // Three Keys are {rank, x} for x in {1, 2, 3}
226  // Three Keys are {(rank+x)%np, x} for x in {1, 2, 3}
227  // Each rank has three unique and three non-unique keys
228  int me = comm->getRank();
229  int np = comm->getSize();
230 
231  std::string name = std::string(" test2: ")
232  + std::string(type_name<gno_t>::name());
233  if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
234 
235  typedef std::array<gno_t, 2> zkey_t;
236  typedef std::vector<zkey_t> keyvec_t;
237  typedef std::vector<gno_t> gidvec_t;
238 
239  const size_t nKeys = 6;
240  const size_t nKeysHalf = 3;
241  keyvec_t keys(nKeys);
242  gidvec_t gids(nKeys);
243 
244  for (size_t i = 0; i < nKeysHalf; i++) {
245  zkey_t k;
246  k[0] = gno_t(me);
247  k[1] = gno_t(i+1);
248  keys[i] = k;
249  }
250  for (size_t i = 0; i < nKeysHalf; i++) {
251  zkey_t k;
252  k[0] = gno_t((me+i+1)%np);
253  k[1] = gno_t(i+1);
254  keys[i+nKeysHalf] = k;
255  }
256 
257  size_t nUniqueGids = findUniqueGids<zkey_t,gno_t>(keys,gids,comm);
258 
259  // Test for correctness
260  if (me == 0)
261  std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
262 
263  checkNUnique(name, nUniqueGids, size_t(nKeysHalf*np));
264 
265  checkMaxGid(name, gids, gno_t(nKeysHalf*np-1), comm);
266 
267  checkMinGid(name, gids, gno_t(0), comm);
268 }
269 
271 template <typename gno_t>
272 void test3(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
273 {
274  // Test 3:
275  // Key has three entries
276  // Each proc has 2*np keys
277  // np Keys are {x, x, x} for x in {0, 1, ..., np-1}
278  // np Keys are {rank, rank, x} for x in {0, 1, ..., np-1}
279  // Each proc has one locally duplicated key
280  // Each proc contributes np unique keys
281  int me = comm->getRank();
282  int np = comm->getSize();
283 
284  std::string name = std::string(" test3: ")
285  + std::string(type_name<gno_t>::name());
286  if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
287 
288  typedef std::array<gno_t, 3> zkey_t;
289  typedef std::vector<zkey_t> keyvec_t;
290  typedef std::vector<gno_t> gidvec_t;
291 
292  const size_t nKeys = 2*np;
293  const size_t nKeysHalf = np;
294  keyvec_t keys(nKeys);
295  gidvec_t gids(nKeys);
296 
297  for (size_t i = 0; i < nKeysHalf; i++) {
298  zkey_t k;
299  k[0] = gno_t(me);
300  k[1] = gno_t(me);
301  k[2] = gno_t(i);
302  keys[i+nKeysHalf] = k;
303  }
304  for (size_t i = 0; i < nKeysHalf; i++) {
305  zkey_t k;
306  k[0] = gno_t(i);
307  k[1] = gno_t(i);
308  k[2] = gno_t(i);
309  keys[i] = k;
310  }
311 
312  size_t nUniqueGids = findUniqueGids<zkey_t,gno_t>(keys,gids,comm);
313 
314  // for (size_t i = 0; i < nKeys; i++)
315  // std::cout << me << " Key " << i << ": "
316  // << keys[i][0] << " " << keys[i][1] << " " << keys[i][2]
317  // << " GID " << gids[i]
318  // << std::endl;
319 
320  // Test for correctness
321  if (me == 0)
322  std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
323 
324  checkNUnique(name, nUniqueGids, size_t(np*np));
325 
326  checkMaxGid(name, gids, gno_t(np*np-1), comm);
327 
328  checkMinGid(name, gids, gno_t(0), comm);
329 
330  checkNLocallyUnique(name, gids, size_t(nKeys-1));
331 }
332 
334 
335 template <typename gno_t>
336 void test4(Teuchos::RCP<const Teuchos::Comm<int> > &comm)
337 {
338  // Test 4:
339  // Key has four entries
340  // Each proc has (rank+1)%2 keys; odd-numbered ranks are empty
341  // Keys are all identical {0, 1, 2, 3}
342  int me = comm->getRank();
343 
344  std::string name = std::string(" test4: ")
345  + std::string(type_name<gno_t>::name());
346  if (me == 0) std::cout << "--------\n Starting " << name << std::endl;
347 
348  typedef std::array<gno_t, 4> zkey_t;
349  typedef std::vector<zkey_t> keyvec_t;
350  typedef std::vector<gno_t> gidvec_t;
351 
352  const size_t nKeys = (me+1)%2;
353  keyvec_t keys(nKeys);
354  gidvec_t gids(nKeys);
355 
356  for (size_t i = 0; i < nKeys; i++) {
357  zkey_t k;
358  k[0] = gno_t(0);
359  k[1] = gno_t(1);
360  k[2] = gno_t(2);
361  k[3] = gno_t(3);
362  keys[i] = k;
363  }
364 
365  size_t nUniqueGids = findUniqueGids<zkey_t,gno_t>(keys,gids,comm);
366 
367  // Test for correctness
368  if (me == 0)
369  std::cout << " " << name << " nUniqueGids " << nUniqueGids << std::endl;
370 
371  checkNUnique(name, nUniqueGids, size_t(1));
372 
373  checkMaxGid(name, gids, gno_t(0), comm);
374 
375  checkMinGid(name, gids, gno_t(0), comm);
376 
377  checkNLocallyUnique(name, gids, (nKeys ? size_t(1): size_t(0)));
378 }
379 
380 } // namespace Zoltan2
381 
382 int main(int argc, char *argv[])
383 {
384  Tpetra::ScopeGuard tscope(&argc, &argv);
385  Teuchos::RCP<const Teuchos::Comm<int> > comm =
386  Teuchos::DefaultComm<int>::getComm();
387 
388  Zoltan2::test1<int>(comm);
389  Zoltan2::test2<int>(comm);
390  Zoltan2::test3<int>(comm);
391  Zoltan2::test4<int>(comm);
392 
393  Zoltan2::test1<long long>(comm);
394  Zoltan2::test2<long long>(comm);
395  Zoltan2::test3<long long>(comm);
396  Zoltan2::test4<long long>(comm);
397 
398  return 0;
399 }
void test1(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
int main(int narg, char **arg)
Definition: coloring1.cpp:164
void test4(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
static const std::string pass
void checkNUnique(std::string &name, size_t nUniqueGids, size_t nExpected)
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
size_t findUniqueGids(Tpetra::MultiVector< gno_t, lno_t, gno_t > &keys, Tpetra::Vector< gno_t, lno_t, gno_t > &gids)
void test2(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
static const std::string fail
DECL_TYPE_NAME(int)
void checkNLocallyUnique(std::string &name, std::vector< gno_t > &gids, size_t nExpected)
Gathering definitions used in software development.
void test3(Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void checkMinGid(std::string &name, std::vector< gno_t > &gids, gno_t minExpected, Teuchos::RCP< const Teuchos::Comm< int > > &comm)
void checkMaxGid(std::string &name, std::vector< gno_t > &gids, gno_t maxExpected, Teuchos::RCP< const Teuchos::Comm< int > > &comm)