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