TIMPI
set_unit.C
Go to the documentation of this file.
1 #include <timpi/timpi.h>
2 
3 #include <bitset>
4 #include <map>
5 #include <set>
6 #include <unordered_set>
7 #include <unordered_map>
8 
9 #define TIMPI_UNIT_ASSERT(expr) \
10  if (!(expr)) \
11  timpi_error();
12 
13 using namespace TIMPI;
14 
16 
17 void my_inserter(std::set<int> & s, int i)
18 { s.insert(i); }
19 
20 void my_inserter(std::multiset<int> & s, int i)
21 {
22  s.insert(-1);
23  s.insert(3*i+1);
24  s.insert(3*i+2);
25 }
26 
27 void my_inserter(std::unordered_multiset<int> & s, int i)
28 {
29  s.insert(-1);
30  s.insert(3*i+1);
31  s.insert(3*i+2);
32 }
33 
34 void my_inserter(std::set<std::vector<int>> & s, int i)
35 { s.insert(std::vector<int>(i,i)); }
36 
37 void my_inserter(std::unordered_set<int> & s, int i)
38 { s.insert(i); }
39 
40 void my_inserter(std::map<int, int> & m, int i)
41 { m.insert(std::make_pair(i,2*i+3)); }
42 
43 void my_inserter(std::multimap<int, int> & m, int i)
44 {
45  m.insert(std::make_pair(-1,-1));
46  m.insert(std::make_pair(i,3*i+1));
47  m.insert(std::make_pair(i,3*i+2));
48 }
49 
50 void my_inserter(std::unordered_multimap<int, int> & m, int i)
51 {
52  m.insert(std::make_pair(-1,-1));
53  m.insert(std::make_pair(i,3*i+1));
54  m.insert(std::make_pair(i,3*i+2));
55 }
56 
57 void my_inserter(std::map<int, std::vector<int>> & m, int i)
58 { m.insert(std::make_pair(i,std::vector<int>(i,2*i+3))); }
59 
60 void my_inserter(std::unordered_map<int, int> & m, int i)
61 { m.insert(std::make_pair(i,2*i+3)); }
62 
63 void my_inserter(std::unordered_map<int, std::vector<int>> & m, int i)
64 { m.insert(std::make_pair(i,std::vector<int>(i,2*i+3))); }
65 
66 
67 void tester(const std::set<int> & s, int i)
68 { TIMPI_UNIT_ASSERT( s.count(i) == std::size_t(1) ); }
69 
70 void tester(const std::multiset<int> & s, int i)
71 {
72  TIMPI_UNIT_ASSERT( s.count(-1) * 3 == s.size() );
73  TIMPI_UNIT_ASSERT( s.count(3*i+1) == std::size_t(1) );
74  TIMPI_UNIT_ASSERT( s.count(3*i+2) == std::size_t(1) );
75 }
76 
77 void tester(const std::unordered_multiset<int> & s, int i)
78 {
79  TIMPI_UNIT_ASSERT( s.count(-1) * 3 == s.size() );
80  TIMPI_UNIT_ASSERT( s.count(3*i+1) == std::size_t(1) );
81  TIMPI_UNIT_ASSERT( s.count(3*i+2) == std::size_t(1) );
82 }
83 
84 void tester(const std::set<std::vector<int>> & s, int i)
85 { TIMPI_UNIT_ASSERT( s.count(std::vector<int>(i,i)) == std::size_t(1) ); }
86 
87 void tester(const std::unordered_set<int> & s, int i)
88 { TIMPI_UNIT_ASSERT( s.count(i) == std::size_t(1) ); }
89 
90 void tester(const std::map<int, int> & m, int i)
91 {
92  TIMPI_UNIT_ASSERT( m.count(i) == std::size_t(1) );
93  TIMPI_UNIT_ASSERT( m.at(i) == 2*i+3 );
94 }
95 
96 void tester(const std::multimap<int, int> & m, int i)
97 {
98  TIMPI_UNIT_ASSERT( m.count(-1) * 3 == m.size() );
99 
100  std::bitset<2> found;
101  auto pr = m.equal_range(i);
102  for (auto it = pr.first; it != pr.second; ++it)
103  {
104  auto val = it->second;
105  TIMPI_UNIT_ASSERT( val > 3*i && val < 3*i+3 );
106  TIMPI_UNIT_ASSERT( !found[val-3*i-1] );
107  found[val-3*i-1] = true;
108  }
109  TIMPI_UNIT_ASSERT( found.count() == 2 );
110 }
111 
112 void tester(const std::unordered_multimap<int, int> & m, int i)
113 {
114  TIMPI_UNIT_ASSERT( m.count(-1) * 3 == m.size() );
115 
116  std::bitset<2> found;
117  const auto pr = m.equal_range(i);
118  for (auto it = pr.first; it != pr.second; ++it)
119  {
120  auto val = it->second;
121  TIMPI_UNIT_ASSERT( val > 3*i && val < 3*i+3 );
122  TIMPI_UNIT_ASSERT( !found[val-3*i-1] );
123  found[val-3*i-1] = true;
124  }
125  TIMPI_UNIT_ASSERT( found.count() == 2 );
126 }
127 
128 void tester(const std::map<int, std::vector<int>> & m, int i)
129 {
130  TIMPI_UNIT_ASSERT( m.count(i) == std::size_t(1) );
131  TIMPI_UNIT_ASSERT( m.at(i).size() == std::size_t(i) );
132  for (auto val : m.at(i))
133  TIMPI_UNIT_ASSERT( val == 2*i+3 );
134 }
135 
136 void tester(const std::unordered_map<int, int> & m, int i)
137 {
138  TIMPI_UNIT_ASSERT( m.count(i) == std::size_t(1) );
139  TIMPI_UNIT_ASSERT( m.at(i) == 2*i+3 );
140 }
141 
142 void tester(const std::unordered_map<int, std::vector<int>> & m, int i)
143 {
144  TIMPI_UNIT_ASSERT( m.count(i) == std::size_t(1) );
145  TIMPI_UNIT_ASSERT( m.at(i).size() == std::size_t(i) );
146  for (auto val : m.at(i))
147  TIMPI_UNIT_ASSERT( val == 2*i+3 );
148 }
149 
150 
151  template <class Set>
152  void testBigUnion(int n_multi = 1)
153  {
154  Set data;
155 
156  const int N = TestCommWorld->size();
157 
158  my_inserter(data, 150*N + TestCommWorld->rank());
159 
160  TestCommWorld->set_union(data);
161 
162  // The real assertions here are the internal ones in that
163  // set_union
164  TIMPI_UNIT_ASSERT( data.size() == n_multi * std::size_t(N) );
165  for (int p=0; p<N; ++p)
166  {
167  tester(data, 150*N + p);
168  }
169  }
170 
171 
172 
173  template <class Set>
174  void testUnion()
175  {
176  Set data;
177 
178  const int N = TestCommWorld->size();
179 
180  my_inserter(data, TestCommWorld->rank());
181  my_inserter(data, 2*N);
182  my_inserter(data, 3*N + TestCommWorld->rank());
183 
184  TestCommWorld->set_union(data);
185 
186  TIMPI_UNIT_ASSERT( data.size() == std::size_t(2*N+1) );
187  tester(data, 2*N);
188  for (int p=0; p<N; ++p)
189  {
190  tester(data, p);
191  tester(data, 3*N+p);
192  }
193  }
194 
195 
196  void testMapSet()
197  {
198  std::map<unsigned int, std::set<unsigned short>> mapset;
199 
200  // Values on all procs
201  mapset[0].insert(20201);
202 
203  // Insert extra values on procs 0 and 2
204  switch (TestCommWorld->rank())
205  {
206  case 0:
207  case 2:
208  mapset[0].insert(60201);
209  break;
210  default:
211  break;
212  }
213 
214  TestCommWorld->set_union(mapset);
215 
216  // Check results on all procs. In a broken 4-processor run what we
217  // saw was:
218  // key = 0, surface_ids = 20201 60201
219  // key = 0, surface_ids = 20201
220  // key = 0, surface_ids = 20201 60201
221  // key = 0, surface_ids = 20201
222  // whereas what we expect to see is that all procs have the
223  // same surface_ids, the ones from pid 0.
224  TIMPI_UNIT_ASSERT( mapset.size() == 1 );
225  const std::set<unsigned short> goodset {20201, 60201};
226  for (const auto & pr : mapset)
227  {
228  const auto & key = pr.first;
229  const auto & boundary_id_set = pr.second;
230  TIMPI_UNIT_ASSERT( key == 0 );
231  TIMPI_UNIT_ASSERT( boundary_id_set == goodset );
232  }
233  }
234 
235 
236  void testMapMap()
237  {
238  std::map<unsigned int, std::map<unsigned short, double>> mapmap;
239 
240  // Values on all procs
241  mapmap[0].emplace(20201, 0.8);
242 
243  // Insert extra values on procs 0 and 2
244  switch (TestCommWorld->rank())
245  {
246  case 0:
247  case 2:
248  mapmap[0].emplace(60201, 1.);
249  break;
250  default:
251  break;
252  }
253 
254  TestCommWorld->set_union(mapmap);
255 
256  TIMPI_UNIT_ASSERT( mapmap.size() == 1 );
257  const std::map<unsigned short, double> goodmap {{20201, 0.8},
258  {60201, 1}};
259  for (const auto & pr : mapmap)
260  {
261  const auto & key = pr.first;
262  const auto & boundary_id_map = pr.second;
263  TIMPI_UNIT_ASSERT( key == 0 );
264  TIMPI_UNIT_ASSERT( boundary_id_map == goodmap );
265  }
266  }
267 
268 
269 int main(int argc, const char * const * argv)
270 {
271  TIMPI::TIMPIInit init(argc, argv);
272  TestCommWorld = &init.comm();
273 
274  testBigUnion<std::set<int>>();
275  testBigUnion<std::multiset<int>>(3);
276  testBigUnion<std::unordered_multiset<int>>(3);
277  testBigUnion<std::unordered_set<int>>();
278  testBigUnion<std::map<int, int>>();
279  testBigUnion<std::multimap<int, int>>(3);
280  testBigUnion<std::unordered_multimap<int, int>>(3);
281  testBigUnion<std::unordered_map<int, int>>();
282 
283  testUnion<std::set<int>>();
284  testUnion<std::unordered_set<int>>();
285  testUnion<std::map<int, int>>();
286  testUnion<std::unordered_map<int, int>>();
287 
288  // TODO: allgather(vector<vector>)
289  // testUnion<std::set<std::vector<int>>>();
290 
291  // No std::hash<vector<non-bool>>
292  // testUnion<std::unordered_set<std::vector<int>>>();
293 
294  testUnion<std::map<int, std::vector<int>>>();
295  testUnion<std::unordered_map<int, std::vector<int>>>();
296 
297  testMapSet();
298  testMapMap();
299 
300  return 0;
301 }
void testBigUnion(int n_multi=1)
Definition: set_unit.C:152
The TIMPIInit class, when constructed, initializes any dependent libraries (e.g.
Definition: timpi_init.h:57
processor_id_type rank() const
Definition: communicator.h:208
Encapsulates the MPI_Comm object.
Definition: communicator.h:108
void testMapMap()
Definition: set_unit.C:236
processor_id_type size() const
Definition: communicator.h:211
Communicator * TestCommWorld
Definition: set_unit.C:15
void testUnion()
Definition: set_unit.C:174
void my_inserter(std::set< int > &s, int i)
Definition: set_unit.C:17
int main(int argc, const char *const *argv)
Definition: set_unit.C:269
void tester(const std::set< int > &s, int i)
Definition: set_unit.C:67
const Communicator & comm() const
Returns the Communicator created by this object, which will be a compatibility shim if MPI is not ena...
Definition: timpi_init.h:100
void testMapSet()
Definition: set_unit.C:196
void set_union(T &data, const unsigned int root_id) const
Take a container (set, map, unordered_set, multimap, etc) of local variables on each processor...