Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Zoltan2_MatrixPartitioningAlgs.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Zoltan2: A package of combinatorial algorithms for scientific computing
4 //
5 // Copyright 2012 NTESS and the Zoltan2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef _ZOLTAN2_ALGMATRIX_HPP_
11 #define _ZOLTAN2_ALGMATRIX_HPP_
12 
13 // #include <Zoltan2_IdentifierModel.hpp>
16 // #include <Zoltan2_Algorithm.hpp>
17 
19 
20 // #include <sstream>
21 // #include <string>
22 // #include <bitset>
23 
28 namespace Zoltan2{
29 
30 
44 template <typename Adapter>
45 class AlgMatrix : public Algorithm<Adapter>
46 {
47 
48 public:
49  typedef typename Adapter::lno_t lno_t; // local ids
50  typedef typename Adapter::gno_t gno_t; // global ids
51  typedef typename Adapter::scalar_t scalar_t; // scalars
52  typedef typename Adapter::part_t part_t; // part numbers
53 
54  typedef typename Adapter::user_t user_t;
55  typedef typename Adapter::userCoord_t userCoord_t;
56 
58 
59 
60 
61  // Constructor
62  AlgMatrix(const RCP<const Environment> &_env,
63  const RCP<const Comm<int> > &_problemComm,
64  const RCP<const MatrixAdapter<user_t, userCoord_t> > &_matrixAdapter)
65  : mEnv(_env), mProblemComm(_problemComm), mMatrixAdapter(_matrixAdapter)
66  {}
67 
68 
69  // AlgMatrix(const RCP<const Environment> &_env,
70  // const RCP<const Comm<int> > &_problemComm,
71  // const RCP<const Adapter> &_matrixAdapter)
72  // : mEnv(_env), mProblemComm(_problemComm), mMatrixAdapter(_matrixAdapter)
73  // {}
74 
75  // Partitioning method
76  void partitionMatrix(const RCP<MatrixPartitioningSolution<Adapter> > &solution);
77 
78 
79 private:
80  const RCP<const Environment> mEnv;
81  const RCP<const Comm<int> > mProblemComm;
82 
83  const RCP<const MatrixAdapter<user_t, userCoord_t> > mMatrixAdapter;
84  //const RCP<const Adapter > mMatrixAdapter;
85 
86  //typedef Tpetra::CrsMatrix<z2TestScalar, z2TestLO, z2TestGO> SparseMatrix;
87  // const RCP<const XpetraCrsMatrixAdapter<user_t, userCoord_t> > mMatrixAdapter;
88 
89 
90 
91 
92 };
93 
94 
96 // Partitioning method
97 //
98 // -- For now implementing 2D Random Cartesian
100 template <typename Adapter>
102 {
103  mEnv->debug(DETAILED_STATUS, std::string("Entering AlgBlock"));
104 
105  int myrank = mEnv->myRank_;
106  int nprocs = mEnv->numProcs_;
107 
109  // Determine processor dimension d for 2D block partitioning d = sqrt(p)
110  // Determine processor row and processor column for this rank for 2D partitioning
112  int procDim = sqrt(nprocs);
113  assert(procDim * procDim == nprocs); // TODO: Should check this earlier and produce more useful error
114 
115  int myProcRow = myrank / procDim;
116  int myProcCol = myrank % procDim;
118 
120  // Create 1D Random partitioning problem to create partitioning for the 2D partitioning
122 
124  // Create parameters for 1D partitioning
126  Teuchos::ParameterList params1D("Params for 1D partitioning");
127  // params1D.set("algorithm", "random"); //TODO add support for random
128  params1D.set("algorithm", "block");
129  params1D.set("imbalance_tolerance", 1.1);
130  params1D.set("num_global_parts", procDim);
132 
134  // Create Zoltan2 partitioning problem
135  // -- Alternatively we could simply call algorithm directly
138  const_cast<MatrixAdapter<user_t, userCoord_t>*>(mMatrixAdapter.getRawPtr());
139 
140 
142  new Zoltan2::PartitioningProblem<base_adapter_t>(adapterPtr, &params1D);
143 
145 
147  // Solve the problem, get the solution
149  problem->solve();
150 
151  // Zoltan2::PartitioningSolution<SparseMatrixAdapter_t> solution = problem.getSolution();
152  const Zoltan2::PartitioningSolution<base_adapter_t> &solution1D = problem->getSolution();
153 
155 
157  // Get part assignments for each local_id
159  // size_t numGlobalParts = solution1D->getTargetGlobalNumberOfParts();
160 
161  const part_t *parts = solution1D.getPartListView();
162 
164 
166 
167 
169  // Create column Ids ArrayRCP colIDs to store in solution
170  // This will define which column IDs are allowed in a particular processor
171  // column.
173 
175  // Group gids corresponding to local ids based on process column
177  const gno_t *rowIds;
178  mMatrixAdapter->getRowIDsView(rowIds);
179 
180  size_t nLocIDs = mMatrixAdapter->getLocalNumRows();
181 
182  std::vector<std::vector<gno_t> > idsInProcColI(procDim);
183  Teuchos::ArrayRCP<gno_t> colIDs;
184 
185  for(size_t i=0; i<nLocIDs; i++)
186  {
187  // Nonzeros with columns of index rowIds[i] belong to some processor
188  // in processor column parts[i]
189  idsInProcColI[ parts[i] ].push_back(rowIds[i]);
190  }
192 
193  delete problem; // delete 1D partitioning problem
194 
195 
197  // Communicate gids to process col roots
199 
200  // Loop over each of the processor columns
201  for(int procColI=0; procColI<procDim; procColI++)
202  {
203 
205  // This rank is root of procColI, need to receive
207  if(myProcCol==procColI && myProcRow==0)
208  {
209  assert(myrank==procColI); // Could make this above conditional?
210 
211 
212  std::set<gno_t> gidSet; // to get sorted list of gids
213 
215  // Copy local gids to sorted gid set
217  for(int i=0;i<idsInProcColI[procColI].size();i++)
218  {
219  gidSet.insert(idsInProcColI[procColI][i]);
220  }
222 
224  // Receive gids from remote processors, insert into set
226  std::vector<gno_t> recvBuf;
227  for(int src=0;src<nprocs;src++)
228  {
229  if(src!=myrank)
230  {
231  int buffSize;
232 
233  Teuchos::receive<int,int>(*mProblemComm, src, 1, &buffSize);
234 
235  if(buffSize>0)
236  {
237  recvBuf.resize(buffSize);
238 
239  Teuchos::receive<int,gno_t>(*mProblemComm, src, buffSize, recvBuf.data());
240 
241  for(int i=0;i<buffSize;i++)
242  {
243  gidSet.insert(recvBuf[i]);
244  }
245  }
246  }
247  }
249 
251  //Copy data to std::vector
253  colIDs.resize(gidSet.size());
254 
255  typename std::set<gno_t>::const_iterator iter;
256  int indx=0;
257  for (iter=gidSet.begin(); iter!=gidSet.end(); ++iter)
258  {
259  colIDs[indx] = *iter;
260  indx++;
261  }
263  }
265 
267  // This rank is not root of procColI, need to senddata block to root
269  else
270  {
271  int sizeToSend = idsInProcColI[procColI].size();
272 
273  //is the dst proc info correct here?
274 
275  // Root of procColI is rank procColI
276  Teuchos::send<int,int>(*mProblemComm,1,&sizeToSend,procColI);
277 
278  Teuchos::send<int,gno_t>(*mProblemComm,sizeToSend,idsInProcColI[procColI].data(),procColI);
279  }
281 
282  }
284 
285  // Free memory if possible
286 
287 
289  // Communicate gids from process col root down process column to other procs
291 
293  // This rank is root of its processor column, need to send
295  if(myProcRow==0)
296  {
298  // Send data to remote processors in processor column
300  for(int procColRank=0; procColRank<procDim; procColRank++)
301  {
302  // Convert from proc column rank to global rank
303  int dstRank = procColRank*procDim + myProcCol;
304 
305  if(dstRank!=myrank)
306  {
307  int sizeToSend = colIDs.size();
308 
309  Teuchos::send<int,int>(*mProblemComm,1,&sizeToSend,dstRank);
310  Teuchos::send<int,gno_t>(*mProblemComm,sizeToSend,colIDs.get(),dstRank);
311 
312  }
313  }
315 
316  }
318 
320  // This rank is not root of processor, need to recv data from root
322  else
323  {
324  // Src rank is root of processor column = myProcCol
325  int srcRank = myProcCol;
326 
327  int buffSize;
328  Teuchos::receive<int,int>(*mProblemComm, srcRank, 1, &buffSize);
329 
330  colIDs.resize(buffSize);
331  Teuchos::receive<int,gno_t>(*mProblemComm, srcRank, buffSize, colIDs.get());
332  }
334 
336  // Create domain/range IDs (same for both now) Array RCP to store in solution
337  // Created from equal division of column IDs
339 
340  // Split processor column ids into nDim parts
341  // Processor column i ids split between ranks 0+i, nDim+i, 2*nDim+i, ...
342 
343  //
344 
345  ArrayRCP<gno_t> domRangeIDs; // Domain/Range vector Ids assigned to this process
346 
347  size_t nCols = colIDs.size();
348  lno_t nColsDivDim = nCols / procDim;
349  lno_t nColsModDim = nCols % procDim;
350 
351  size_t sColIndx;
352  size_t domRangeSize;
353 
354  // This proc will have nColsDivDim+1 domain/range ids
355  if(myProcRow < nColsModDim)
356  {
357  sColIndx = myProcRow * (nColsDivDim+1);
358  domRangeSize = nColsDivDim+1;
359  }
360  // This proc will have nColsDivDim domain/range ids
361  else
362  {
363  sColIndx = nColsModDim*(nColsDivDim+1) + (myProcRow-nColsModDim) * nColsDivDim;
364  domRangeSize = nColsDivDim;
365  }
366 
367  domRangeIDs.resize(domRangeSize);
368 
369  for(size_t i=0;i<domRangeSize;i++)
370  {
371  domRangeIDs[i] = colIDs[sColIndx+i];
372  }
374 
376  // Create row IDs Array RCP to store in solution
377  // Created from union of domRangeIDs
378  //
379  // Procs 0, 1, ... nDim-1 share the same set of rowIDs
380  // Procs nDim, nDim+1, ..., 2*nDim-1 share the same set of rowIDs
382 
384  // Create subcommunicator for processor row
386  std::vector<int> subcommRanks(procDim);
387 
388  for(unsigned int i=0; i<procDim; i++)
389  {
390  subcommRanks[i] = myProcRow*procDim + i;
391  }
392 
393  ArrayView<const int> subcommRanksView = Teuchos::arrayViewFromVector (subcommRanks);
394 
395  RCP<Teuchos::Comm<int> > rowcomm = mProblemComm->createSubcommunicator(subcommRanksView);
397 
399  // Determine max number of columns in this process row
401  size_t maxProcRowNCols=0;
402 
403  Teuchos::reduceAll<int, size_t>(*rowcomm,Teuchos::REDUCE_MAX,1,&domRangeSize,&maxProcRowNCols);
405 
407  // Communicate all domRangeIDs to all processes in procRow
409  gno_t MAXVAL = std::numeric_limits<gno_t>::max();
410 
411  std::vector<gno_t> locRowIDs(maxProcRowNCols,MAXVAL);
412 
413  Teuchos::ArrayRCP<gno_t> rowIDs(maxProcRowNCols * procDim);
414 
415  // Copy local domRangeIDs into local row IDs, "extra elements" will have
416  // value MAXVAL
417  for(size_t i=0;i<domRangeIDs.size();i++)
418  {
419  locRowIDs[i] = domRangeIDs[i];
420  }
421 
422  // Gather all ids onto all processes in procRow
423  Teuchos::gatherAll<int,gno_t>(*rowcomm,maxProcRowNCols, locRowIDs.data(),
424  maxProcRowNCols*procDim, rowIDs.get());
426 
427  // Free local data
428  std::vector<int>().swap(locRowIDs);
429 
430 
432  // Insert local domRangeIDs into row IDs set, filter out extra items
434  std::set<gno_t> setRowIDs;
435 
436  for(size_t i=0;i<rowIDs.size();i++)
437  {
438  if(rowIDs[i]!=MAXVAL)
439  {
440  setRowIDs.insert(rowIDs[i]);
441  }
442  }
444 
446  // Resize rowIDs array and copy data to array (now sorted)
448  rowIDs.resize(setRowIDs.size());
449 
450  typename std::set<gno_t>::const_iterator iter;
451  size_t indx=0;
452 
453  for(iter=setRowIDs.begin(); iter!=setRowIDs.end(); ++iter)
454  {
455  rowIDs[indx] = *iter;
456  indx++;
457  }
459 
461 
463  // Finished. Store partition in solution.
465  solution->setIDLists(rowIDs,colIDs,domRangeIDs,domRangeIDs);
467 
468  mEnv->debug(DETAILED_STATUS, std::string("Exiting AlgMatrix"));
469 }
471 
472 
473 
474 } // namespace Zoltan2
475 
476 #endif
Zoltan2::BaseAdapter< userTypes_t > base_adapter_t
MatrixAdapter defines the adapter interface for matrices.
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
Defines the PartitioningSolution class.
sub-steps, each method&#39;s entry and exit
SparseMatrixAdapter_t::part_t part_t
AlgMatrix(const RCP< const Environment > &_env, const RCP< const Comm< int > > &_problemComm, const RCP< const MatrixAdapter< user_t, userCoord_t > > &_matrixAdapter)
A PartitioningSolution is a solution to a partitioning problem.
const part_t * getPartListView() const
Returns the part list corresponding to the global ID list.
Algorithm defines the base class for all algorithms.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
void partitionMatrix(const RCP< MatrixPartitioningSolution< Adapter > > &solution)
Matrix Partitioning method.
PartitioningProblem sets up partitioning problems for the user.
Defines the PartitioningProblem class.
Adapter::base_adapter_t base_adapter_t
A PartitioningSolution is a solution to a partitioning problem.
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition: Metric.cpp:39