Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
mj_backwardcompat.cpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Zoltan2: A package of combinatorial algorithms for scientific computing
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Karen Devine (kddevin@sandia.gov)
39 // Erik Boman (egboman@sandia.gov)
40 // Siva Rajamanickam (srajama@sandia.gov)
41 //
42 // ***********************************************************************
43 //
44 // @HEADER
45 
53 #include <Zoltan2_InputTraits.hpp>
54 #include <Tpetra_Map.hpp>
55 #include <vector>
56 #include <cstdlib>
57 
59 // Simple adapter with contiguous coordinates
60 template <typename User>
62 {
63 public:
67  typedef typename node_t::device_type device_t;
68 
70  const size_t nids_,
71  const gno_t *gids_,
72  const int dim_,
73  const scalar_t *coords_,
74  const scalar_t *weights_ = NULL)
75  : nids(nids_), gids(gids_), dim(dim_), coords(coords_), weights(weights_)
76  { }
77 
78  size_t getLocalNumIDs() const { return nids; }
79 
80  void getIDsView(const gno_t *&ids) const { ids = gids; }
81 
82  int getNumWeightsPerID() const { return (weights != NULL); }
83 
84  void getWeightsView(const scalar_t *&wgt, int &stride, int idx = 0) const
85  { wgt = weights; stride = 1; }
86 
87  int getNumEntriesPerID() const { return dim; }
88 
89  void getEntriesView(const scalar_t *&coo, int &stride, int idx = 0) const
90  {
91  coo = &(coords[idx*nids]);
92  stride = 1;
93  }
94 
95 private:
96  const size_t nids;
97  const gno_t *gids;
98  const int dim;
99  const scalar_t *coords;
100  const scalar_t *weights;
101 };
102 
104 // Simple adapter with strided coordinates
105 template <typename User>
107 {
108 public:
111 
113  const size_t nids_,
114  const gno_t *gids_,
115  const int dim_,
116  const scalar_t *coords_,
117  const scalar_t *weights_ = NULL)
118  : nids(nids_), gids(gids_), dim(dim_), coords(coords_), weights(weights_)
119  { }
120 
121  size_t getLocalNumIDs() const { return nids; }
122 
123  void getIDsView(const gno_t *&ids) const { ids = gids; }
124 
125  int getNumWeightsPerID() const { return (weights != NULL); }
126 
127  void getWeightsView(const scalar_t *&wgt, int &stride, int idx = 0) const
128  { wgt = weights; stride = 1; }
129 
130  int getNumEntriesPerID() const { return dim; }
131 
132  void getEntriesView(const scalar_t *&coo, int &stride, int idx = 0) const
133  {
134  coo = &(coords[idx]);
135  stride = dim;
136  }
137 
138 private:
139  const size_t nids;
140  const gno_t *gids;
141  const int dim;
142  const scalar_t *coords;
143  const scalar_t *weights;
144 };
145 
147 // Same adapter as above but now we supply the Kokkos calls, not the original
148 // calls. This is to verify that backwards and forward compatibility are all
149 // working properly.
150 template <typename User>
152 {
153 public:
156  typedef Tpetra::Map<>::node_type node_t;
157  typedef typename node_t::device_type device_t;
158 
160  const size_t nids_,
161  const gno_t *gids_,
162  const int dim_,
163  const scalar_t *coords_,
164  const scalar_t *weights_ = NULL)
165  : nids(nids_), dim(dim_)
166  {
167  // create kokkos_gids in default memory space
168  {
169  typedef Kokkos::DualView<gno_t *, device_t> view_ids_t;
170  kokkos_gids = view_ids_t(
171  Kokkos::ViewAllocateWithoutInitializing("gids"), nids);
172 
173  auto host_gids = kokkos_gids.h_view;
174  for(size_t n = 0; n < nids; ++n) {
175  host_gids(n) = gids_[n];
176  }
177 
178  kokkos_gids.template modify<typename view_ids_t::host_mirror_space>();
179  kokkos_gids.sync_host();
180  kokkos_gids.template sync<device_t>();
181  }
182 
183  // create kokkos_weights in default memory space
184  if(weights_ != NULL)
185  {
186  typedef Kokkos::DualView<scalar_t **, device_t> view_weights_t;
187  kokkos_weights = view_weights_t(
188  Kokkos::ViewAllocateWithoutInitializing("weights"), nids, 0);
189  auto host_kokkos_weights = kokkos_weights.h_view;
190  for(size_t n = 0; n < nids; ++n) {
191  host_kokkos_weights(n,0) = weights_[n];
192  }
193 
194  kokkos_weights.template modify<typename view_weights_t::host_mirror_space>();
195  kokkos_weights.sync_host();
196  kokkos_weights.template sync<device_t>();
197  }
198 
199  // create kokkos_coords in default memory space
200  {
201  typedef Kokkos::DualView<scalar_t **, Kokkos::LayoutLeft, device_t> kokkos_coords_t;
202  kokkos_coords = kokkos_coords_t(
203  Kokkos::ViewAllocateWithoutInitializing("coords"), nids, dim);
204  auto host_kokkos_coords = kokkos_coords.h_view;
205 
206  for(size_t n = 0; n < nids; ++n) {
207  for(int idx = 0; idx < dim; ++idx) {
208  host_kokkos_coords(n,idx) = coords_[n+idx*nids];
209  }
210  }
211 
212  kokkos_coords.template modify<typename kokkos_coords_t::host_mirror_space>();
213  kokkos_coords.sync_host();
214  kokkos_coords.template sync<device_t>();
215  }
216  }
217 
218  size_t getLocalNumIDs() const { return nids; }
219 
220  void getIDsView(const gno_t *&ids) const override {
221  auto kokkosIds = kokkos_gids.view_host();
222  ids = kokkosIds.data();
223  }
224 
225  virtual void getIDsKokkosView(Kokkos::View<const gno_t *, device_t> &ids) const {
226  ids = kokkos_gids.template view<device_t>();
227  }
228 
229  int getNumWeightsPerID() const { return (kokkos_weights.h_view.size() != 0); }
230 
231  void getWeightsView(const scalar_t *&wgt, int &stride,
232  int idx = 0) const override
233  {
234  auto h_wgts_2d = kokkos_weights.view_host();
235 
236  wgt = Kokkos::subview(h_wgts_2d, Kokkos::ALL, idx).data();
237  stride = 1;
238  }
239 
240  virtual void getWeightsKokkosView(Kokkos::View<scalar_t **, device_t> & wgt) const {
241  wgt = kokkos_weights.template view<device_t>();
242  }
243 
244  int getNumEntriesPerID() const { return dim; }
245 
246  void getEntriesView(const scalar_t *&elements,
247  int &stride, int idx = 0) const override {
248  elements = kokkos_coords.view_host().data();
249  stride = 1;
250  }
251 
252  virtual void getEntriesKokkosView(Kokkos::View<scalar_t **,
253  Kokkos::LayoutLeft, device_t> & coo) const {
254  coo = kokkos_coords.template view<device_t>();
255  }
256 
257 private:
258  const size_t nids;
259  Kokkos::DualView<gno_t *, device_t> kokkos_gids;
260  const int dim;
261  Kokkos::DualView<scalar_t **, Kokkos::LayoutLeft, device_t> kokkos_coords;
262  Kokkos::DualView<scalar_t **, device_t> kokkos_weights;
263 };
264 
266 int run_test_strided_versus_contig(const std::string & algorithm) {
267 
268  int nFail = 0;
269 
270  const Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
271 
272  int rank = comm->getRank();
273  int nprocs = comm->getSize();
274 
275  typedef Tpetra::Map<> Map_t;
276  typedef Map_t::local_ordinal_type localId_t;
277  typedef Map_t::global_ordinal_type globalId_t;
278  typedef double scalar_t;
279 
281  typedef OldSchoolVectorAdapterStrided<myTypes> stridedAdapter_t;
282  typedef OldSchoolVectorAdapterContig<myTypes> contigAdapter_t;
283  typedef KokkosVectorAdapter<myTypes> kokkosAdapter_t;
285 
287  // Create input data.
288 
289  size_t localCount = 40;
290  int dim = 3; // no higher since we are testing rcb as a control which supports dim <= 3
291 
292  // Create coordinates strided
293  scalar_t *cStrided = new scalar_t [dim * localCount];
294  size_t cnt = 0;
295  for (size_t i = 0; i < localCount; i++)
296  for (int d = 0; d < dim; d++)
297  cStrided[cnt++] = d*1000 + rank*100 + i;
298 
299  // Create same coords, stored contiguously
300  scalar_t *cContig = new scalar_t [dim * localCount];
301  cnt = 0;
302  for (int d = 0; d < dim; d++)
303  for (size_t i = 0; i < localCount; i++)
304  cContig[cnt++] = d*1000 + rank*100 + i;
305 
306  // Create global ids for the coordinates.
307  globalId_t *globalIds = new globalId_t [localCount];
308  globalId_t offset = rank * localCount;
309  for (size_t i=0; i < localCount; i++) globalIds[i] = offset++;
310 
312  // Create parameters for an MJ problem
313 
314  Teuchos::ParameterList params("test params");
315  params.set("debug_level", "basic_status");
316  params.set("error_check_level", "debug_mode_assertions");
317 
318  params.set("algorithm", algorithm); // test runs multijagged and rcb
319  params.set("num_global_parts", nprocs+1);
320 
322  // Test one: No weights
323 
324  // Partition using strided coords
325  stridedAdapter_t *ia1 =
326  new stridedAdapter_t(localCount,globalIds,dim,cStrided);
327 
330 
331  problem1->solve();
332 
333  quality_t *metricObject1 = new quality_t(ia1, &params, comm,
334  &problem1->getSolution());
335  if (rank == 0){
336 
337  metricObject1->printMetrics(std::cout);
338 
339  double imb = metricObject1->getObjectCountImbalance();
340  if (imb <= 1.03) // Should get perfect balance
341  std::cout << "no weights -- balance satisfied: " << imb << std::endl;
342  else {
343  std::cout << "no weights -- balance failure: " << imb << std::endl;
344  nFail++;
345  }
346  std::cout << std::endl;
347  }
348 
349  // Partition using contiguous coords
350  contigAdapter_t *ia2 = new contigAdapter_t(localCount,globalIds,dim,cContig);
351 
354 
355  problem2->solve();
356 
357  // Partition using contiguous coords to generate kokkos adapter
358  kokkosAdapter_t *ia3 = new kokkosAdapter_t(localCount,globalIds,dim,cContig);
359 
362 
363  problem3->solve();
364 
365  // compare strided vs contiguous vs kokkos
366  size_t ndiff = 0;
367  for (size_t i = 0; i < localCount; i++) {
368  if((problem1->getSolution().getPartListView()[i] !=
369  problem2->getSolution().getPartListView()[i]) ||
370  (problem2->getSolution().getPartListView()[i] !=
371  problem3->getSolution().getPartListView()[i]))
372  {
373  std::cout << rank << " Error: differing parts for index " << i
374  << problem1->getSolution().getPartListView()[i] << " "
375  << problem2->getSolution().getPartListView()[i] << " "
376  << problem3->getSolution().getPartListView()[i] << std::endl;
377 
378  ndiff++;
379  }
380  }
381  if (ndiff > 0) nFail++;
382  else if (rank == 0) std::cout << "no weights -- comparisons OK " << std::endl;
383 
384  delete metricObject1;
385  delete problem1;
386  delete problem2;
387  delete problem3;
388  delete ia1;
389  delete ia2;
390  delete ia3;
391 
393  // Test two: weighted
394  // Create a Zoltan2 input adapter that includes weights.
395 
396  scalar_t *weights = new scalar_t [localCount];
397  for (size_t i=0; i < localCount; i++) weights[i] = 1 + scalar_t(rank);
398 
399  // Test with strided coords
400  ia1 = new stridedAdapter_t(localCount, globalIds, dim, cStrided, weights);
401 
402  problem1 = new Zoltan2::PartitioningProblem<stridedAdapter_t>(ia1, &params);
403 
404  problem1->solve();
405 
406  metricObject1 = new quality_t(ia1, &params, comm, &problem1->getSolution());
407 
408  if (rank == 0){
409 
410  metricObject1->printMetrics(std::cout);
411 
412  double imb = metricObject1->getWeightImbalance(0);
413  if (imb <= 1.03)
414  std::cout << "weighted -- balance satisfied " << imb << std::endl;
415  else {
416  std::cout << "weighted -- balance failed " << imb << std::endl;
417  nFail++;
418  }
419  std::cout << std::endl;
420  }
421 
422  // Partition using contiguous coords
423  ia2 = new contigAdapter_t(localCount, globalIds, dim, cContig, weights);
424 
425  problem2 = new Zoltan2::PartitioningProblem<contigAdapter_t>(ia2, &params);
426 
427  problem2->solve();
428 
429  // compare strided vs contiguous
430  ndiff = 0;
431  for (size_t i = 0; i < localCount; i++) {
432  if (problem1->getSolution().getPartListView()[i] !=
433  problem2->getSolution().getPartListView()[i]) {
434  std::cout << rank << " Error: differing parts for index " << i
435  << problem1->getSolution().getPartListView()[i] << " "
436  << problem2->getSolution().getPartListView()[i] << std::endl;
437 
438  ndiff++;
439  }
440  }
441  if (ndiff > 0) nFail++;
442  else if (rank == 0) std::cout << "weighted -- comparisons OK " << std::endl;
443 
444  delete metricObject1;
445  delete problem1;
446  delete problem2;
447  delete ia1;
448  delete ia2;
449 
450  // Test with strided coords
451  if (weights) delete [] weights;
452  if (cStrided) delete [] cStrided;
453  if (cContig) delete [] cContig;
454  if (globalIds) delete [] globalIds;
455 
456  // check result
457 
458  int gnFail;
459  Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, 1, &nFail, &gnFail);
460  return gnFail;
461 }
462 
463 
464 int main(int narg, char *arg[])
465 {
466  Tpetra::ScopeGuard scope(&narg, &arg);
467  const Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
468 
469  int err = 0;
470 
471  // err += run_test_strided_versus_contig("multijagged");
472  err += run_test_strided_versus_contig("rcb");
473 
474  if (comm->getRank() == 0) {
475  if (err == 0) std::cout << "PASS" << std::endl;
476  else std::cout << "FAIL: " << err << " tests failed" << std::endl;
477  }
478 
479  return 0;
480 }
481 
OldSchoolVectorAdapterStrided(const size_t nids_, const gno_t *gids_, const int dim_, const scalar_t *coords_, const scalar_t *weights_=NULL)
void printMetrics(std::ostream &os) const
Print all metrics.
size_t getLocalNumIDs() const
Returns the number of objects on this process.
Zoltan2::InputTraits< User >::gno_t gno_t
static ArrayRCP< ArrayRCP< zscalar_t > > weights
void getEntriesView(const scalar_t *&coo, int &stride, int idx=0) const
int getNumEntriesPerID() const
Return the number of vectors.
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:18
Zoltan2::InputTraits< User >::scalar_t scalar_t
A simple class that can be the User template argument for an InputAdapter.
Defines the VectorAdapter interface.
void getWeightsView(const scalar_t *&wgt, int &stride, int idx=0) const override
Zoltan2::EvaluatePartition< matrixAdapter_t > quality_t
int main(int narg, char **arg)
Definition: coloring1.cpp:199
Defines the PartitioningSolution class.
virtual void getWeightsKokkosView(Kokkos::View< scalar_t **, device_t > &wgt) const
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater...
void getEntriesView(const scalar_t *&elements, int &stride, int idx=0) const override
Zoltan2::InputTraits< User >::node_t node_t
scalar_t getWeightImbalance(int weightIndex) const
Return the imbalance for the requested weight.
void getIDsView(const gno_t *&ids) const
void getWeightsView(const scalar_t *&wgt, int &stride, int idx=0) const
virtual void getEntriesKokkosView(Kokkos::View< scalar_t **, Kokkos::LayoutLeft, device_t > &coo) const
void getEntriesView(const scalar_t *&coo, int &stride, int idx=0) const
void getIDsView(const gno_t *&ids) const
virtual void getIDsKokkosView(Kokkos::View< const gno_t *, device_t > &ids) const
size_t getLocalNumIDs() const
Returns the number of objects on this process.
VectorAdapter defines the interface for vector input.
int run_test_strided_versus_contig(const std::string &algorithm)
Traits for application input objects.
default_gno_t gno_t
The ordinal type (e.g., int, long, int64_t) that can represent global counts and identifiers.
int getNumEntriesPerID() const
Return the number of vectors.
default_node_t node_t
The Kokkos node type. This is only meaningful for users of Tpetra objects.
Zoltan2::InputTraits< User >::gno_t gno_t
node_t::device_type device_t
const PartitioningSolution< Adapter > & getSolution()
Get the solution to the problem.
PartitioningProblem sets up partitioning problems for the user.
void getIDsView(const gno_t *&ids) const override
Tpetra::Map::node_type node_t
void getWeightsView(const scalar_t *&wgt, int &stride, int idx=0) const
Defines the PartitioningProblem class.
Zoltan2::InputTraits< User >::gno_t gno_t
A class that computes and returns quality metrics.
size_t getLocalNumIDs() const
Returns the number of objects on this process.
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater...
void solve(bool updateInputData=true)
Direct the problem to create a solution.
default_scalar_t scalar_t
The data type for weights and coordinates.
int getNumEntriesPerID() const
Return the number of vectors.
OldSchoolVectorAdapterContig(const size_t nids_, const gno_t *gids_, const int dim_, const scalar_t *coords_, const scalar_t *weights_=NULL)
scalar_t getObjectCountImbalance() const
Return the object count imbalance.
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater...
Zoltan2::InputTraits< User >::scalar_t scalar_t
KokkosVectorAdapter(const size_t nids_, const gno_t *gids_, const int dim_, const scalar_t *coords_, const scalar_t *weights_=NULL)
Zoltan2::InputTraits< User >::scalar_t scalar_t