Zoltan2
Loading...
Searching...
No Matches
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
28namespace Zoltan2{
29
30
44template <typename Adapter>
45class AlgMatrix : public Algorithm<Adapter>
46{
47
48public:
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
57 typedef typename Adapter::base_adapter_t base_adapter_t;
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
79private:
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
100template <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
Defines the PartitioningProblem class.
Defines the PartitioningSolution class.
AlgMatrix(const RCP< const Environment > &_env, const RCP< const Comm< int > > &_problemComm, const RCP< const MatrixAdapter< user_t, userCoord_t > > &_matrixAdapter)
Adapter::base_adapter_t base_adapter_t
void partitionMatrix(const RCP< MatrixPartitioningSolution< Adapter > > &solution)
Matrix Partitioning method.
Algorithm defines the base class for all algorithms.
MatrixAdapter defines the adapter interface for matrices.
A PartitioningSolution is a solution to a partitioning problem.
PartitioningProblem sets up partitioning problems for the user.
A PartitioningSolution is a solution to a partitioning problem.
const part_t * getPartListView() const
Returns the part list corresponding to the global ID list.
Created by mbenlioglu on Aug 31, 2020.
@ DETAILED_STATUS
sub-steps, each method's entry and exit