Zoltan2
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
54#include <Tpetra_Map.hpp>
55#include <vector>
56#include <cstdlib>
57
59// Simple adapter with contiguous coordinates
60template <typename User>
62{
63public:
66
68 const size_t nids_,
69 const gno_t *gids_,
70 const int dim_,
71 const scalar_t *coords_,
72 const scalar_t *weights_ = NULL)
73 : nids(nids_), gids(gids_), dim(dim_), coords(coords_), weights(weights_)
74 { }
75
76 size_t getLocalNumIDs() const { return nids; }
77
78 void getIDsView(const gno_t *&ids) const { ids = gids; }
79
80 int getNumWeightsPerID() const { return (weights != NULL); }
81
82 void getWeightsView(const scalar_t *&wgt, int &stride, int idx = 0) const
83 { wgt = weights; stride = 1; }
84
85 int getNumEntriesPerID() const { return dim; }
86
87 void getEntriesView(const scalar_t *&coo, int &stride, int idx = 0) const
88 {
89 coo = &(coords[idx*nids]);
90 stride = 1;
91 }
92
93private:
94 const size_t nids;
95 const gno_t *gids;
96 const int dim;
97 const scalar_t *coords;
98 const scalar_t *weights;
99};
100
102// Simple adapter with strided coordinates
103template <typename User>
105{
106public:
109
111 const size_t nids_,
112 const gno_t *gids_,
113 const int dim_,
114 const scalar_t *coords_,
115 const scalar_t *weights_ = NULL)
116 : nids(nids_), gids(gids_), dim(dim_), coords(coords_), weights(weights_)
117 { }
118
119 size_t getLocalNumIDs() const { return nids; }
120
121 void getIDsView(const gno_t *&ids) const { ids = gids; }
122
123 int getNumWeightsPerID() const { return (weights != NULL); }
124
125 void getWeightsView(const scalar_t *&wgt, int &stride, int idx = 0) const
126 { wgt = weights; stride = 1; }
127
128 int getNumEntriesPerID() const { return dim; }
129
130 void getEntriesView(const scalar_t *&coo, int &stride, int idx = 0) const
131 {
132 coo = &(coords[idx]);
133 stride = dim;
134 }
135
136private:
137 const size_t nids;
138 const gno_t *gids;
139 const int dim;
140 const scalar_t *coords;
141 const scalar_t *weights;
142};
143
145// Same adapter as above but now we supply the Kokkos calls, not the original
146// calls. This is to verify that backwards and forward compatibility are all
147// working properly.
148template <typename User>
150{
151public:
154 typedef Tpetra::Map<>::node_type node_t;
155
157 const size_t nids_,
158 const gno_t *gids_,
159 const int dim_,
160 const scalar_t *coords_,
161 const scalar_t *weights_ = NULL)
162 : nids(nids_), dim(dim_)
163 {
164 // create kokkos_gids in default memory space
165 {
166 typedef Kokkos::DualView<gno_t *> view_ids_t;
167 kokkos_gids = view_ids_t(
168 Kokkos::ViewAllocateWithoutInitializing("gids"), nids);
169
170 auto host_gids = kokkos_gids.h_view;
171 for(size_t n = 0; n < nids; ++n) {
172 host_gids(n) = gids_[n];
173 }
174
175 kokkos_gids.template modify<typename view_ids_t::host_mirror_space>();
176 kokkos_gids.sync_host();
177 kokkos_gids.template sync<typename node_t::device_type>();
178 }
179
180 // create kokkos_weights in default memory space
181 if(weights_ != NULL)
182 {
183 typedef Kokkos::DualView<scalar_t **> view_weights_t;
184 kokkos_weights = view_weights_t(
185 Kokkos::ViewAllocateWithoutInitializing("weights"), nids, 0);
186 auto host_kokkos_weights = kokkos_weights.h_view;
187 for(size_t n = 0; n < nids; ++n) {
188 host_kokkos_weights(n,0) = weights_[n];
189 }
190
191 kokkos_weights.template modify<typename view_weights_t::host_mirror_space>();
192 kokkos_weights.sync_host();
193 kokkos_weights.template sync<typename node_t::device_type>();
194 }
195
196 // create kokkos_coords in default memory space
197 {
198 typedef Kokkos::DualView<scalar_t **, Kokkos::LayoutLeft> kokkos_coords_t;
199 kokkos_coords = kokkos_coords_t(
200 Kokkos::ViewAllocateWithoutInitializing("coords"), nids, dim);
201 auto host_kokkos_coords = kokkos_coords.h_view;
202
203 for(size_t n = 0; n < nids; ++n) {
204 for(int idx = 0; idx < dim; ++idx) {
205 host_kokkos_coords(n,idx) = coords_[n+idx*nids];
206 }
207 }
208
209 kokkos_coords.template modify<typename kokkos_coords_t::host_mirror_space>();
210 kokkos_coords.sync_host();
211 kokkos_coords.template sync<typename node_t::device_type>();
212 }
213 }
214
215 size_t getLocalNumIDs() const { return nids; }
216
217 void getIDsView(const gno_t *&ids) const override {
218 auto kokkosIds = kokkos_gids.view_host();
219 ids = kokkosIds.data();
220 }
221
222 virtual void getIDsKokkosView(Kokkos::View<const gno_t *,
223 typename node_t::device_type> &ids) const {
224 ids = kokkos_gids.template view<typename node_t::device_type>();;
225 }
226
227 int getNumWeightsPerID() const { return (kokkos_weights.h_view.size() != 0); }
228
229 void getWeightsView(const scalar_t *&wgt, int &stride,
230 int idx = 0) const override
231 {
232 auto h_wgts_2d = kokkos_weights.view_host();
233
234 wgt = Kokkos::subview(h_wgts_2d, Kokkos::ALL, idx).data();
235 stride = 1;
236 }
237
238 virtual void getWeightsKokkosView(Kokkos::View<scalar_t **,
239 typename node_t::device_type> & wgt) const {
240 wgt = kokkos_weights.template view<typename node_t::device_type>();;
241 }
242
243 int getNumEntriesPerID() const { return dim; }
244
245 void getEntriesView(const scalar_t *&elements,
246 int &stride, int idx = 0) const override {
247 elements = kokkos_coords.view_host().data();
248 stride = 1;
249 }
250
251 virtual void getEntriesKokkosView(Kokkos::View<scalar_t **,
252 Kokkos::LayoutLeft, typename node_t::device_type> & coo) const {
253 coo = kokkos_coords.template view<typename node_t::device_type>();
254 }
255
256private:
257 const size_t nids;
258 Kokkos::DualView<gno_t *> kokkos_gids;
259 const int dim;
260 Kokkos::DualView<scalar_t **, Kokkos::LayoutLeft> kokkos_coords;
261 Kokkos::DualView<scalar_t **> kokkos_weights;
262};
263
265int run_test_strided_versus_contig(const std::string & algorithm) {
266
267 int nFail = 0;
268
269 const Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
270
271 int rank = comm->getRank();
272 int nprocs = comm->getSize();
273
274 typedef Tpetra::Map<> Map_t;
275 typedef Map_t::local_ordinal_type localId_t;
276 typedef Map_t::global_ordinal_type globalId_t;
277 typedef double scalar_t;
278
280 typedef OldSchoolVectorAdapterStrided<myTypes> stridedAdapter_t;
281 typedef OldSchoolVectorAdapterContig<myTypes> contigAdapter_t;
282 typedef KokkosVectorAdapter<myTypes> kokkosAdapter_t;
284
286 // Create input data.
287
288 size_t localCount = 40;
289 int dim = 3; // no higher since we are testing rcb as a control which supports dim <= 3
290
291 // Create coordinates strided
292 scalar_t *cStrided = new scalar_t [dim * localCount];
293 size_t cnt = 0;
294 for (size_t i = 0; i < localCount; i++)
295 for (int d = 0; d < dim; d++)
296 cStrided[cnt++] = d*1000 + rank*100 + i;
297
298 // Create same coords, stored contiguously
299 scalar_t *cContig = new scalar_t [dim * localCount];
300 cnt = 0;
301 for (int d = 0; d < dim; d++)
302 for (size_t i = 0; i < localCount; i++)
303 cContig[cnt++] = d*1000 + rank*100 + i;
304
305 // Create global ids for the coordinates.
306 globalId_t *globalIds = new globalId_t [localCount];
307 globalId_t offset = rank * localCount;
308 for (size_t i=0; i < localCount; i++) globalIds[i] = offset++;
309
311 // Create parameters for an MJ problem
312
313 Teuchos::ParameterList params("test params");
314 params.set("debug_level", "basic_status");
315 params.set("error_check_level", "debug_mode_assertions");
316
317 params.set("algorithm", algorithm); // test runs multijagged and rcb
318 params.set("num_global_parts", nprocs+1);
319
321 // Test one: No weights
322
323 // Partition using strided coords
324 stridedAdapter_t *ia1 =
325 new stridedAdapter_t(localCount,globalIds,dim,cStrided);
326
329
330 problem1->solve();
331
332 quality_t *metricObject1 = new quality_t(ia1, &params, comm,
333 &problem1->getSolution());
334 if (rank == 0){
335
336 metricObject1->printMetrics(std::cout);
337
338 double imb = metricObject1->getObjectCountImbalance();
339 if (imb <= 1.03) // Should get perfect balance
340 std::cout << "no weights -- balance satisfied: " << imb << std::endl;
341 else {
342 std::cout << "no weights -- balance failure: " << imb << std::endl;
343 nFail++;
344 }
345 std::cout << std::endl;
346 }
347
348 // Partition using contiguous coords
349 contigAdapter_t *ia2 = new contigAdapter_t(localCount,globalIds,dim,cContig);
350
353
354 problem2->solve();
355
356 // Partition using contiguous coords to generate kokkos adapter
357 kokkosAdapter_t *ia3 = new kokkosAdapter_t(localCount,globalIds,dim,cContig);
358
361
362 problem3->solve();
363
364 // compare strided vs contiguous vs kokkos
365 size_t ndiff = 0;
366 for (size_t i = 0; i < localCount; i++) {
367 if((problem1->getSolution().getPartListView()[i] !=
368 problem2->getSolution().getPartListView()[i]) ||
369 (problem2->getSolution().getPartListView()[i] !=
370 problem3->getSolution().getPartListView()[i]))
371 {
372 std::cout << rank << " Error: differing parts for index " << i
373 << problem1->getSolution().getPartListView()[i] << " "
374 << problem2->getSolution().getPartListView()[i] << " "
375 << problem3->getSolution().getPartListView()[i] << std::endl;
376
377 ndiff++;
378 }
379 }
380 if (ndiff > 0) nFail++;
381 else if (rank == 0) std::cout << "no weights -- comparisons OK " << std::endl;
382
383 delete metricObject1;
384 delete problem1;
385 delete problem2;
386 delete problem3;
387 delete ia1;
388 delete ia2;
389 delete ia3;
390
392 // Test two: weighted
393 // Create a Zoltan2 input adapter that includes weights.
394
395 scalar_t *weights = new scalar_t [localCount];
396 for (size_t i=0; i < localCount; i++) weights[i] = 1 + scalar_t(rank);
397
398 // Test with strided coords
399 ia1 = new stridedAdapter_t(localCount, globalIds, dim, cStrided, weights);
400
401 problem1 = new Zoltan2::PartitioningProblem<stridedAdapter_t>(ia1, &params);
402
403 problem1->solve();
404
405 metricObject1 = new quality_t(ia1, &params, comm, &problem1->getSolution());
406
407 if (rank == 0){
408
409 metricObject1->printMetrics(std::cout);
410
411 double imb = metricObject1->getWeightImbalance(0);
412 if (imb <= 1.03)
413 std::cout << "weighted -- balance satisfied " << imb << std::endl;
414 else {
415 std::cout << "weighted -- balance failed " << imb << std::endl;
416 nFail++;
417 }
418 std::cout << std::endl;
419 }
420
421 // Partition using contiguous coords
422 ia2 = new contigAdapter_t(localCount, globalIds, dim, cContig, weights);
423
424 problem2 = new Zoltan2::PartitioningProblem<contigAdapter_t>(ia2, &params);
425
426 problem2->solve();
427
428 // compare strided vs contiguous
429 ndiff = 0;
430 for (size_t i = 0; i < localCount; i++) {
431 if (problem1->getSolution().getPartListView()[i] !=
432 problem2->getSolution().getPartListView()[i]) {
433 std::cout << rank << " Error: differing parts for index " << i
434 << problem1->getSolution().getPartListView()[i] << " "
435 << problem2->getSolution().getPartListView()[i] << std::endl;
436
437 ndiff++;
438 }
439 }
440 if (ndiff > 0) nFail++;
441 else if (rank == 0) std::cout << "weighted -- comparisons OK " << std::endl;
442
443 delete metricObject1;
444 delete problem1;
445 delete problem2;
446 delete ia1;
447 delete ia2;
448
449 // Test with strided coords
450 if (weights) delete [] weights;
451 if (cStrided) delete [] cStrided;
452 if (cContig) delete [] cContig;
453 if (globalIds) delete [] globalIds;
454
455 // check result
456
457 int gnFail;
458 Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, 1, &nFail, &gnFail);
459 return gnFail;
460}
461
462
463int main(int narg, char *arg[])
464{
465 Tpetra::ScopeGuard scope(&narg, &arg);
466 const Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
467
468 int err = 0;
469
470 // err += run_test_strided_versus_contig("multijagged");
471 err += run_test_strided_versus_contig("rcb");
472
473 if (comm->getRank() == 0) {
474 if (err == 0) std::cout << "PASS" << std::endl;
475 else std::cout << "FAIL: " << err << " tests failed" << std::endl;
476 }
477
478 return 0;
479}
480
Traits for application input objects.
Defines the PartitioningProblem class.
Defines the PartitioningSolution class.
Defines the VectorAdapter interface.
int getNumEntriesPerID() const
Return the number of vectors.
void getIDsView(const gno_t *&ids) const override
Tpetra::Map ::node_type node_t
void getEntriesView(const scalar_t *&elements, int &stride, int idx=0) const override
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....
virtual void getWeightsKokkosView(Kokkos::View< scalar_t **, typename node_t::device_type > &wgt) const
KokkosVectorAdapter(const size_t nids_, const gno_t *gids_, const int dim_, const scalar_t *coords_, const scalar_t *weights_=NULL)
virtual void getEntriesKokkosView(Kokkos::View< scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type > &coo) const
Zoltan2::InputTraits< User >::gno_t gno_t
virtual void getIDsKokkosView(Kokkos::View< const gno_t *, typename node_t::device_type > &ids) const
Zoltan2::InputTraits< User >::scalar_t scalar_t
void getWeightsView(const scalar_t *&wgt, int &stride, int idx=0) const override
Zoltan2::InputTraits< User >::scalar_t scalar_t
int getNumEntriesPerID() const
Return the number of vectors.
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater....
OldSchoolVectorAdapterContig(const size_t nids_, const gno_t *gids_, const int dim_, const scalar_t *coords_, const scalar_t *weights_=NULL)
void getIDsView(const gno_t *&ids) const
size_t getLocalNumIDs() const
Returns the number of objects on this process.
Zoltan2::InputTraits< User >::gno_t gno_t
void getWeightsView(const scalar_t *&wgt, int &stride, int idx=0) const
void getEntriesView(const scalar_t *&coo, int &stride, int idx=0) const
Zoltan2::InputTraits< User >::scalar_t scalar_t
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater....
size_t getLocalNumIDs() const
Returns the number of objects on this process.
int getNumEntriesPerID() const
Return the number of vectors.
void getIDsView(const gno_t *&ids) const
void getEntriesView(const scalar_t *&coo, int &stride, int idx=0) const
void getWeightsView(const scalar_t *&wgt, int &stride, int idx=0) const
OldSchoolVectorAdapterStrided(const size_t nids_, const gno_t *gids_, const int dim_, const scalar_t *coords_, const scalar_t *weights_=NULL)
Zoltan2::InputTraits< User >::gno_t gno_t
A simple class that can be the User template argument for an InputAdapter.
A class that computes and returns quality metrics.
void printMetrics(std::ostream &os) const
Print all metrics.
scalar_t getWeightImbalance(int weightIndex) const
Return the imbalance for the requested weight.
scalar_t getObjectCountImbalance() const
Return the object count imbalance.
PartitioningProblem sets up partitioning problems for the user.
const PartitioningSolution< Adapter > & getSolution()
Get the solution to the problem.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
VectorAdapter defines the interface for vector input.
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:18
int run_test_strided_versus_contig(const std::string &algorithm)
int main(int narg, char *arg[])
static ArrayRCP< ArrayRCP< zscalar_t > > weights
default_gno_t gno_t
The ordinal type (e.g., int, long, int64_t) that can represent global counts and identifiers.
default_scalar_t scalar_t
The data type for weights and coordinates.
Zoltan2::EvaluatePartition< matrixAdapter_t > quality_t