MueLu  Version of the Day
MueLu_CoupledAggregationCommHelper_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
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
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_COUPLEDAGGREGATIONCOMMHELPER_DEF_HPP
47 #define MUELU_COUPLEDAGGREGATIONCOMMHELPER_DEF_HPP
48 
49 #include <Xpetra_MapFactory.hpp>
50 #include <Xpetra_BlockedMultiVector.hpp>
51 #include <Xpetra_BlockedVector.hpp>
52 #include <Xpetra_VectorFactory.hpp>
53 #include <Xpetra_ImportFactory.hpp>
54 #include <Xpetra_ExportFactory.hpp>
55 
57 
58 #include "MueLu_Utilities.hpp" // MueLu_maxAll
59 
60 namespace MueLu {
61 
62  template <class LocalOrdinal, class GlobalOrdinal, class Node>
63  CoupledAggregationCommHelper<LocalOrdinal, GlobalOrdinal, Node>::CoupledAggregationCommHelper(const RCP<const Map> & uniqueMap, const RCP<const Map> & nonUniqueMap) {
64  import_ = ImportFactory::Build(uniqueMap, nonUniqueMap);
65  tempVec_ = VectorFactory::Build(uniqueMap,false); //zeroed out before use
66  numMyWinners_ = 0;
67  numCalls_ = 0;
68  myPID_ = uniqueMap->getComm()->getRank();
69  }
70 
71  template <class LocalOrdinal, class GlobalOrdinal, class Node>
72  void CoupledAggregationCommHelper<LocalOrdinal, GlobalOrdinal, Node>::ArbitrateAndCommunicate(Vector &weight_, LOVector &procWinner_, LOVector *companion, const bool perturb) const {
73  const RCP<const Map> weightMap = weight_.getMap();
74  const size_t nodeNumElements = weightMap->getNodeNumElements();
75  const RCP<const Teuchos::Comm<int> > & comm = weightMap->getComm();
76  int MyPid = comm->getRank(); // TODO:remove the getMap() step
77  ++numCalls_;
78 
79  //short-circuit if only one process
80  if (comm->getSize() == 1) {
81  ArrayRCP<SC> serialWeight = weight_.getDataNonConst(0);
82  ArrayRCP<LO> serialProcWinner = procWinner_.getDataNonConst(0);
83  for (size_t i=0; i < nodeNumElements; ++i) {
84  if (serialWeight[i] > 0) {
85  serialWeight[i] = 0;
86  serialProcWinner[i] = MyPid;
87  }
88  }
89  //companion doesn't change
90  return;
91  }
92 
93 #ifdef COMPARE_IN_OUT_VECTORS
94  RCP<Vector> in_weight_ = VectorFactory::Build(weight_.getMap());
95  {
96  ArrayRCP<SC> in_weight = in_weight_->getDataNonConst(0);
97  ArrayRCP<SC> weight = weight_.getDataNonConst(0);
98  for (size_t i=0; i < nodeNumElements; ++i) in_weight[i] = weight[i];
99  }
100  RCP<LOVector> in_procWinner_ = LOVectorFactory::Build(procWinner_.getMap());
101  {
102  ArrayRCP<LO> in_procWinner = in_procWinner_->getDataNonConst(0);
103  ArrayRCP<LO> procWinner = procWinner_.getDataNonConst(0);
104  for (size_t i=0; i < nodeNumElements; ++i) in_procWinner[i] = procWinner[i];
105  }
106  RCP<LOVector> in_companion;
107  {
108  if (companion != NULL) {
109  in_companion = LOVectorFactory::Build(companion->getMap());
110  ArrayRCP<LO> in_comp = in_companion->getDataNonConst(0);
111  ArrayRCP<LO> comp = companion->getDataNonConst(0);
112  for (size_t i=0; i < nodeNumElements; ++i) in_comp[i] = comp[i];
113  }
114  }
115 #endif
116 
117  typedef Teuchos::ScalarTraits<SC> ST;
118 
119  if (perturb) {
120  if (perturbWt_ == Teuchos::null || !perturbWt_->getMap()->isSameAs(*weightMap)) {
121  perturbWt_ = VectorFactory::Build(weightMap,false); //no need to zero out because this will be randomized
122 
123  // Modify seed of the random algorithm used by perturbWt_->randomize()
124  {
125  ST::seedrandom( Teuchos::as<unsigned int>(MyPid*47) );
126  for (int i = 0; i < 10; ++i) ST::random();
127  }
128  //Note that we must not use perturbWt_->randomize(). This produces the same
129  //local random vector on each processor. The whole point of the weights
130  //is to provide tie-breaking that isn't based on the highest PID.
131  ArrayRCP<SC> lperturbWt = perturbWt_->getDataNonConst(0);
132  for (size_t i=0; i < nodeNumElements; ++i)
133  lperturbWt[i] = 1e-7*fabs(ST::random()); //FIXME this won't work for general SC
134 #ifdef COMPARE_IN_OUT_VECTORS
135  ArrayRCP<SC> locperturbWt = perturbWt_->getDataNonConst(0);
136  for (size_t i=0; i < nodeNumElements; ++i)
137  printf("perturbWt[%d] = %15.10e\n",i,locperturbWt[i]);
138 #endif
139  } //if (perturbWt_ == Teuchos::null || ...
140 
141  ArrayRCP<SC> weight = weight_.getDataNonConst(0); // TODO: const?
142  ArrayRCP<SC> perturbWt = perturbWt_->getDataNonConst(0);
143 
144  // Note: maxValue() not available for Tpetra
145  //SC largestGlobalWeight = weight_.maxValue();
146  SC largestGlobalWeight = weight_.normInf();
147  for (size_t i=0; i < nodeNumElements; ++i) {
148  if (weight[i] != 0.) {
149  weight[i] += largestGlobalWeight*perturbWt[i];
150  }
151  }
152  //TODO is it necessary to return the *perturbed* weights?
153  } //if (perturb)
154 
155  // Communicate weights and store results in PostComm (which will be copied
156  // back into weights later. When multiple processors have different weights
157  // for the same GID, we take the largest weight. After this fragment every
158  // processor should have the same value for PostComm[] even when multiple
159  // copies of the same Gid are involved.
160 
161  if (postComm_ == Teuchos::null || !postComm_->getMap()->isSameAs(*weightMap) )
162  postComm_ = VectorFactory::Build(weightMap);
163 
164  //note: postComm_ is zeroed either in build above, or in loop below upon last touch.
165 
166  NonUnique2NonUnique(weight_, *postComm_, Xpetra::ABSMAX);
167 
168  // Let every processor know who is the procWinner. For nonunique
169  // copies of the same Gid, this corresponds to the processor with
170  // the highest Wt[]. When several processors have the same positive value
171  // for weight[] (which is also the maximum value), the highest proc id
172  // is declared the procWinner.
173  //
174  // Note:This is accomplished by filling a vector with MyPid+1 if weight[k] is
175  // nonzero and PostComm[k]==weight[k]. NonUnique2NonUnique(...,AbsMax)
176  // is invoked to let everyone know the procWinner.
177  // One is then subtracted so that procWinner[i] indicates the
178  // Pid of the winning processor.
179  // When all weight's for a GID are zero, the associated procWinner's
180  // are left untouched.
181 
182  if (candidateWinners_ == Teuchos::null || !candidateWinners_->getMap()->isSameAs(*weightMap) )
183  candidateWinners_ = VectorFactory::Build(weightMap,false);
184  //note: candidateWinners_ is initialized below
185 
186  ArrayRCP<SC> weight = weight_.getDataNonConst(0);
187 
188  {
189  ArrayRCP<SC> candidateWinners = candidateWinners_->getDataNonConst(0);
190  ArrayRCP<SC> postComm = postComm_->getDataNonConst(0);
191  for (size_t i=0; i < nodeNumElements; ++i) {
192  if (postComm[i] == weight[i]) candidateWinners[i] = (SC) MyPid+1;
193  else candidateWinners[i] = 0;
194  weight[i]=postComm[i];
195  }
196  }
197  NonUnique2NonUnique(*candidateWinners_, *postComm_, Xpetra::ABSMAX);
198 
199  // Note:
200  // associated CandidateWinners[]
201  // weight[i]!=0 ==> on some proc is equal to its ==> postComm[i]!=0
202  // MyPid+1.
203  //
204  int numMyWinners = 0;
205  ArrayRCP<LO> procWinner = procWinner_.getDataNonConst(0);
206  {
207  ArrayRCP<SC> postComm = postComm_->getDataNonConst(0);
208  for (size_t i=0; i < nodeNumElements; ++i) {
209  if ( weight[i] != 0.) procWinner[i] = ((int) (postComm[i])) - 1;
210  weight[i] = 0.; //we are done with weight
211  postComm[i] = 0.; //avoids having to initialize postComm_ on next call to ArbitrateAndCommunicate
212  if (procWinner[i] == MyPid) ++numMyWinners;
213  }
214  }
215 
216  weight = Teuchos::null; //TODO why do we do this?
217 
218  if (companion != NULL) {
219  // Now build a new Map, WinnerMap which just consists of procWinners.
220  // This is done by extracting the Gids for Wt, and shoving
221  // the subset that correspond to procWinners in MyWinners.
222  // WinnerMap is then constructed using MyWinners.
223  //
224  // In order to avoid regenerating winnerMap_, the following are checked:
225  // 1) Do the local number of entries in MyWinners differ? If so, regenerate/repopulate MyWinners and regenerate winnerMap_.
226  // 2) If the local number of entries in MyWinners are the same, do any entries differ? If so, repopulate MyWinners and
227  // regenerate winnerMap_.
228 
229  ArrayView<const GO> myGids = weightMap->getNodeElementList(); //== weightMap->MyGlobalElements(myGids);
230  bool realloc=false;
231  if (numMyWinners != numMyWinners_ || winnerMap_ == Teuchos::null) {
232  // The local number of entries in MyWinners_ have changed since the last invocation, so reallocate myWinners_.
233  myWinners_ = ArrayRCP<GO>(numMyWinners);
234  realloc=true;
235  //std::cout << MyPid << ": numMyWinners has changed : (old) " << numMyWinners_ << ", (new) " << numMyWinners << std::endl;
236  numMyWinners_ = numMyWinners;
237  }
238 
239 #ifdef JG_DEBUG
240  procWinner = Teuchos::null;
241  std::cout << MyPid << ": nodeNumElements=" << nodeNumElements << std::endl;
242  std::cout << MyPid << ": procWinner=" << procWinner_ << std::endl;
243  procWinner = procWinner_.getDataNonConst(0);
244 #endif
245 
246  if (realloc==true) {
247  // The local number of entries in MyWinners have changed since the last invocation, so repopulate MyWinners_.
248  numMyWinners = 0;
249  for (size_t i = 0; i < nodeNumElements; ++i) {
250  if (procWinner[i] == MyPid) {
251  myWinners_[numMyWinners++] = myGids[i];
252  }
253  }
254  } else {
255  // The local number of entries in MyWinners are the same as the last invocation, but
256  // we still must check if any entries differ from the last invocation.
257  bool entryMismatch=false;
258  numMyWinners = 0;
259  for (size_t i = 0; i < nodeNumElements; ++i) {
260  if (procWinner[i] == MyPid) {
261  if (myWinners_[numMyWinners++] != myGids[i]) {
262  entryMismatch=true;
263  break;
264  }
265  }
266  }
267 
268  if (entryMismatch == true) {
269  // Entries differ from last invocation, so repopulate myWinners_.
270  realloc=true;
271  numMyWinners = 0;
272  for (size_t i = 0; i < nodeNumElements; ++i) {
273  if (procWinner[i] == MyPid) {
274  myWinners_[numMyWinners++] = myGids[i];
275  }
276  }
277  }
278  } //if (realloc==true) ... else
279 
280  procWinner = Teuchos::null;
281 
282 #ifdef JG_DEBUG
283  std::cout << MyPid << ": numMyWinners=" << numMyWinners << std::endl;
284  std::cout << MyPid << ": myWinners_" << myWinners_ << std::endl;
285  for(int i=0;i<numMyWinners; i++)
286  std::cout << MyPid << ": myWinners_[locId=" << i << "] = " << myWinners_[i] << std::endl;
287 
288 #endif
289 
290 #ifdef HAVE_MPI
291  //See whether any process has determined that winnerMap_ must be regenerated.
292  int irealloc,orealloc;
293  if (realloc) irealloc=1;
294  else irealloc=0;
295  MueLu_maxAll(comm,irealloc,orealloc);
296  if (orealloc == 1) realloc=true;
297  else realloc=false;
298 #endif
299 
300  if (realloc) {
301  // Either the number of entries or the value have changed since the last invocation, so reallocation the map.
302  const Xpetra::global_size_t GSTI = Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid();
303  winnerMap_ = MapFactory::Build(weightMap->lib(), GSTI, myWinners_(), 0, weightMap->getComm());
304  }
305 
306  // Pull the Winners out of companion
307  // JustWinners <-- companion[Winners];
308 
309  RCP<LOVector> justWinners = LOVectorFactory::Build(winnerMap_);
310 
311 #ifdef JG_DEBUG
312  RCP<Teuchos::FancyOStream> out = rcp(new Teuchos::FancyOStream(rcp(&std::cout,false)));
313  std::cout << MyPid << ": justWinners(Vector in)=" << *justWinners << std::endl;
314  justWinners->describe(*out, Teuchos::VERB_EXTREME);
315 #endif
316 
317  if ( winnerImport_ == Teuchos::null
318  || !winnerImport_->getSourceMap()->isSameAs(*weightMap)
319  || !winnerImport_->getTargetMap()->isSameAs(*winnerMap_) )
320  winnerImport_ = ImportFactory::Build(weightMap, winnerMap_);
321  RCP<const Import> winnerImport = winnerImport_;
322  try
323  {
324  justWinners->doImport(*companion, *winnerImport, Xpetra::INSERT);
325  }
326  catch(std::exception& e)
327  {
328  std::cout << MyPid << ": ERR2: An exception occurred." << std::endl;
329  throw e;
330  }
331 
332  // Put the JustWinner values back into companion so that
333  // all nonunique copies of the same Gid have the procWinner's
334  // version of the companion.
335  //#define JG_DEBUG
336 #ifdef JG_DEBUG
337  RCP<Teuchos::FancyOStream> fos = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
338  fos->setOutputToRootOnly(-1);
339  if (!weightMap->getComm()->getRank())
340  std::cout << "------ winnerMap_ ------" << std::endl;
341  winnerMap_->describe(*fos,Teuchos::VERB_EXTREME);
342  if (!weightMap->getComm()->getRank())
343  std::cout << "------ weightMap ------" << std::endl;
344  weightMap->getComm()->barrier();
345  weightMap->describe(*fos,Teuchos::VERB_EXTREME);
346  //std::cout << *winnerMap_ << std::endl;
347  //std::cout << *weightMap << std::endl;
348  sleep(5);
349  exit(1);
350 #endif
351 #ifdef JG_DEBUG
352 #undef JG_DEBUG
353 #endif
354 
355  if ( pushWinners_ == Teuchos::null
356  || !pushWinners_->getSourceMap()->isSameAs(*winnerMap_)
357  || !pushWinners_->getTargetMap()->isSameAs(*weightMap) )
358  pushWinners_ = ImportFactory::Build(winnerMap_,weightMap);
359  RCP<Import> pushWinners = pushWinners_;
360  //RCP<Import> pushWinners = ImportFactory::Build(winnerMap_, weightMap); // VERSION1
361  //RCP<Export> pushWinners = ExportFactory::Build(winnerMap_, weightMap); // VERSION4
362  try
363  {
364  companion->doImport(*justWinners, *pushWinners, Xpetra::INSERT); // VERSION1 Slow
365  //companion->doExport(*justWinners, *winnerImport_, Xpetra::INSERT); // JJH this should work... but exception
366  // if (weightMap->lib() == Xpetra::UseEpetra)
367  // justWinners->doExport(*companion, *winnerImport, Xpetra::INSERT); // VERSION2 Tpetra doc is wrong
368  // else if (weightMap->lib() == Xpetra::UseTpetra)
369  // companion->doExport(*justWinners, *winnerImport, Xpetra::INSERT); // VERSION3 - TODO: will certainly not work with Epetra? (change Xpetra?)
370  //companion->doExport(*justWinners, *pushWinners, Xpetra::INSERT); // VERSION4
371  // else throw "lib()";
372  }
373  catch(std::exception& e)
374  {
375  throw e;
376  }
377  //#define JG_DEBUG
378 #ifdef JG_DEBUG
379  // RCP<Teuchos::FancyOStream> out = rcp(new Teuchos::FancyOStream(rcp(&std::cout,false)));
380  //->describe(*out, Teuchos::VERB_EXTREME);
381 
382  // std::cout << MyPid << ": ERR3: An exception occurred." << std::endl;
383 
384  std::cout << MyPid << ": numMyWinners=" << numMyWinners << std::endl;
385 
386  std::cout << MyPid << ": justWinners(Vector in)=" << std::endl;
387  justWinners->describe(*out, Teuchos::VERB_EXTREME);
388 
389  std::cout << MyPid << ": companion(Vector out)=" << std::endl;
390  companion->describe(*out, Teuchos::VERB_EXTREME);
391 
392  // std::cout << MyPid << ": pushWinners(Import(winnerMap_, weight_.Map))=" << *pushWinners << std::endl;
393  std::cout << MyPid << ": winnerMap_=" << *winnerMap_ << std::endl;
394  std::cout << MyPid << ": weight_.Map=" << *weightMap << std::endl;
395 #endif
396  // throw e;
397  // throw 1;
398  }
399 
400 #ifdef COMPARE_IN_OUT_VECTORS
401  if (MyPid == 0) {
402  std::cout << "==============" << std::endl;
403  std::cout << "call #" << numCalls << " (1-based)" << std::endl;
404  std::cout << "==============" << std::endl;
405  }
406  /*
407  bool sameWeight=true;
408  bool sameWinner=true;
409  bool sameComp=true;
410  */
411  std::string sameOrDiff;
412  {
413  ArrayRCP<SC> in_weight = in_weight_->getDataNonConst(0);
414  ArrayRCP<SC> weight = weight_.getDataNonConst(0);
415  if (MyPid == 0) std::cout << "==============\nweight\n==============\n" << std::endl;
416  for (size_t i=0; i < weight_.getLocalLength(); ++i) {
417  if (in_weight[i] - weight[i] != 0) sameOrDiff = " <<<<";
418  else sameOrDiff = " ";
419  std::cout << std::setw(3) << i<<": " << in_weight[i] << " " << weight[i] << sameOrDiff << in_weight[i] - weight[i] << std::endl;
420  /*
421  if (in_weight[i] != weight[i]) {
422  sameWeight=false;
423  std::cout << "\n\nin and out weight DIFFER\n\n" << std::endl;
424  std::cout << "i="<<i<<", in=" << in_weight[i] << " , out=" << weight[i] << std::endl;
425  break;
426  }
427  */
428  }
429  }
430 
431  {
432  ArrayRCP<LO> in_procWinner = in_procWinner_->getDataNonConst(0);
433  ArrayRCP<LO> procWinner = procWinner_.getDataNonConst(0);
434  if (MyPid == 0) std::cout << "==============\nprocWinner\n==============\n" << std::endl;
435  for (size_t i=0; i < procWinner_.getLocalLength(); ++i) {
436  if (in_procWinner[i] != procWinner[i]) sameOrDiff = " <<<<";
437  else sameOrDiff = " ";
438  std::cout << std::setw(3) << i<<": " << in_procWinner[i] << " " << procWinner[i] << sameOrDiff << std::endl;
439  /*
440  if (in_procWinner[i] != procWinner[i]) {
441  sameWinner=false;
442  std::cout << "\n\nin and out procWinner DIFFER\n\n" << std::endl;
443  std::cout << "i="<<i<<", in=" << in_procWinner[i] << ", out=" << procWinner[i] << std::endl;
444  break;
445  }
446  */
447  }
448  }
449 
450  {
451  if (companion != NULL) {
452  ArrayRCP<LO> in_comp = in_companion->getDataNonConst(0);
453  ArrayRCP<LO> comp = companion->getDataNonConst(0);
454  if (MyPid == 0) std::cout << "==============\ncompanion\n==============\n" << std::endl;
455  for (size_t i=0; i < companion->getLocalLength(); ++i) {
456  if (in_comp[i] != comp[i]) sameOrDiff = " <<<<";
457  else sameOrDiff = " ";
458  std::cout << std::setw(3) << i<<": " << in_comp[i] << " " << comp[i] << sameOrDiff << std::endl;
459  /*
460  if (in_comp[i] != comp[i]) {
461  sameComp=false;
462  std::cout << "\n\nin and out companion DIFFER\n\n" << std::endl;
463  std::cout << "i="<<i<<", in=" << in_comp[i] << ", out=" << comp[i] << std::endl;
464  break;
465  }
466  */
467  }
468  }
469  }
470 #endif
471  } //ArbitrateAndCommunicate(Vector&, LOVector &, LOVector *, const bool) const
472 
473  template <class LocalOrdinal, class GlobalOrdinal, class Node>
474  void CoupledAggregationCommHelper<LocalOrdinal, GlobalOrdinal, Node>::NonUnique2NonUnique(const Vector &source, Vector &dest, const Xpetra::CombineMode what) const {
475  tempVec_->putScalar(0.);
476 
477  try
478  {
479  tempVec_->doExport(source, *import_, what);
480  dest.doImport(*tempVec_, *import_, Xpetra::INSERT);
481  }
482  catch(std::exception& e)
483  {
484  int MyPid = tempVec_->getMap()->getComm()->getRank();
485  std::cout << MyPid << ": ERR1: An exception occurred." << std::endl;
486  throw e;
487  }
488  }
489 
490 }
491 
492 #endif // MUELU_COUPLEDAGGREGATIONCOMMHELPER_DEF_HPP
493 
#define MueLu_maxAll(rcpComm, in, out)
Namespace for MueLu classes and methods.
void NonUnique2NonUnique(const Vector &source, Vector &dest, const Xpetra::CombineMode what) const
Redistribute data in source to dest where both source and dest might have multiple copies of the same...
CoupledAggregationCommHelper(const RCP< const Map > &uniqueMap, const RCP< const Map > &nonUniqueMap)
Constructor.
void realloc(DynRankView< T, P... > &v, const size_t n0=~size_t(0), const size_t n1=~size_t(0), const size_t n2=~size_t(0), const size_t n3=~size_t(0), const size_t n4=~size_t(0), const size_t n5=~size_t(0), const size_t n6=~size_t(0), const size_t n7=~size_t(0))
void ArbitrateAndCommunicate(Vector &weights, Aggregates &aggregates, const bool perturb) const
This method assigns unknowns to aggregates.