Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Zoltan2_XpetraCrsMatrixAdapter.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 
14 #ifndef _ZOLTAN2_XPETRACRSMATRIXADAPTER_HPP_
15 #define _ZOLTAN2_XPETRACRSMATRIXADAPTER_HPP_
16 
18 #include <Zoltan2_StridedData.hpp>
19 #include <Zoltan2_XpetraTraits.hpp>
21 
22 #include <Xpetra_CrsMatrix.hpp>
23 
24 #include <iostream>
25 #include <cassert>
26 
27 namespace Zoltan2 {
28 
30 
52 template <typename User, typename UserCoord=User>
53  class XpetraCrsMatrixAdapter : public MatrixAdapter<User, UserCoord> {
54 public:
55 
56 #ifndef DOXYGEN_SHOULD_SKIP_THIS
57  using scalar_t = typename InputTraits<User>::scalar_t;
58  using lno_t = typename InputTraits<User>::lno_t;
59  using gno_t = typename InputTraits<User>::gno_t;
60  using part_t = typename InputTraits<User>::part_t;
61  using node_t = typename InputTraits<User>::node_t;
62  using offset_t = typename InputTraits<User>::offset_t;
63  using xmatrix_t = Xpetra::CrsMatrix<scalar_t, lno_t, gno_t, node_t>;
64 
65  using userCoord_t = UserCoord;
66  using user_t = User;
67 #endif
68 
72 
78  XpetraCrsMatrixAdapter(const RCP<const User> &inmatrix,
79  int nWeightsPerRow=0);
80 
93  void setWeights(const scalar_t *weightVal, int stride, int idx = 0);
94 
110  void setRowWeights(const scalar_t *weightVal, int stride, int idx = 0);
111 
117  void setWeightIsDegree(int idx);
118 
124  void setRowWeightIsNumberOfNonZeros(int idx);
125 
127  // The MatrixAdapter interface.
129 
130  size_t getLocalNumRows() const {
131  return matrix_->getLocalNumRows();
132  }
133 
134  size_t getLocalNumColumns() const {
135  return matrix_->getLocalNumCols();
136  }
137 
138  size_t getLocalNumEntries() const {
139  return matrix_->getLocalNumEntries();
140  }
141 
142  void getRowIDsView(const gno_t *&rowIds) const
143  {
144  ArrayView<const gno_t> rowView = rowMap_->getLocalElementList();
145  rowIds = rowView.getRawPtr();
146  }
147 
148  void getColumnIDsView(const gno_t *&colIds) const
149  {
150  ArrayView<const gno_t> colView = colMap_->getLocalElementList();
151  colIds = colView.getRawPtr();
152  }
153 
154  void getCRSView(ArrayRCP<const offset_t> &offsets, ArrayRCP<const gno_t> &colIds) const
155  {
156  ArrayRCP< const lno_t > localColumnIds;
157  ArrayRCP<const scalar_t> values;
158  matrix_->getAllValues(offsets,localColumnIds,values);
159  colIds = columnIds_;
160  }
161 
162  bool CRSViewAvailable() const { return true; }
163 
164  void getCRSView(ArrayRCP<const offset_t> &offsets,
165  ArrayRCP<const gno_t> &colIds,
166  ArrayRCP<const scalar_t> &values) const {
167  ArrayRCP< const lno_t > localColumnIds;
168  matrix_->getAllValues(offsets,localColumnIds,values);
169  colIds = columnIds_;
170  }
171 
172  void getCCSView(ArrayRCP<const offset_t> &offsets,
173  ArrayRCP<const gno_t> &rowIds) const override {
174  ArrayRCP<const offset_t> crsOffsets;
175  ArrayRCP<const lno_t> crsLocalColumnIds;
176  ArrayRCP<const scalar_t> values;
177  matrix_->getAllValues(crsOffsets, crsLocalColumnIds, values);
178 
179  const auto localRowIds = rowMap_->getLocalElementList();
180  const auto numLocalCols = colMap_->getLocalNumElements();
181 
182  // Lambda used to compute local row based on column index from CRS view
183  auto determineRow = [&crsOffsets, &localRowIds](const int columnIdx) {
184  int curLocalRow = 0;
185  for (int rowIdx = 0; rowIdx < localRowIds.size(); ++rowIdx) {
186  if (rowIdx < (localRowIds.size() - 1)) {
187  if (static_cast<offset_t>(columnIdx) < crsOffsets[rowIdx + 1]) {
188  return curLocalRow;
189  }
190  ++curLocalRow;
191  } else {
192  return curLocalRow;
193  }
194  }
195 
196  return -1;
197  };
198 
199  // Vector of global rows per each local column
200  std::vector<std::vector<gno_t>> rowIDsPerCol(numLocalCols);
201 
202  for (int colIdx = 0; colIdx < crsLocalColumnIds.size(); ++colIdx) {
203  const auto colID = crsLocalColumnIds[colIdx];
204  const auto globalRow = rowMap_->getGlobalElement(determineRow(colIdx));
205 
206  rowIDsPerCol[colID].push_back(globalRow);
207  }
208 
209  size_t offsetWrite = 0;
210  ArrayRCP<gno_t> ccsRowIds(values.size());
211  ArrayRCP<offset_t> ccsOffsets(colMap_->getLocalNumElements() + 1);
212 
213  ccsOffsets[0] = 0;
214  for (int64_t colID = 1; colID < ccsOffsets.size(); ++colID) {
215  const auto &rowIDs = rowIDsPerCol[colID - 1];
216 
217  if (not rowIDs.empty()) {
218  std::copy(rowIDs.begin(), rowIDs.end(),
219  ccsRowIds.begin() + offsetWrite);
220  offsetWrite += rowIDs.size();
221  }
222 
223  ccsOffsets[colID] = offsetWrite;
224  }
225 
226  ccsOffsets[numLocalCols] = crsLocalColumnIds.size();
227 
228  rowIds = ccsRowIds;
229  offsets = ccsOffsets;
230  }
231 
232  int getNumWeightsPerRow() const { return nWeightsPerRow_; }
233 
234  void getRowWeightsView(const scalar_t *&weights, int &stride,
235  int idx = 0) const
236  {
237  if(idx<0 || idx >= nWeightsPerRow_)
238  {
239  std::ostringstream emsg;
240  emsg << __FILE__ << ":" << __LINE__
241  << " Invalid row weight index " << idx << std::endl;
242  throw std::runtime_error(emsg.str());
243  }
244 
245  size_t length;
246  rowWeights_[idx].getStridedList(length, weights, stride);
247  }
248 
249  bool useNumNonzerosAsRowWeight(int idx) const { return numNzWeight_[idx];}
250 
251  template <typename Adapter>
252  void applyPartitioningSolution(const User &in, User *&out,
253  const PartitioningSolution<Adapter> &solution) const;
254 
255  template <typename Adapter>
256  void applyPartitioningSolution(const User &in, RCP<User> &out,
257  const PartitioningSolution<Adapter> &solution) const;
258 
259 private:
260 
261  RCP<const User> inmatrix_;
262  RCP<const xmatrix_t> matrix_;
263  RCP<const Xpetra::Map<lno_t, gno_t, node_t> > rowMap_;
264  RCP<const Xpetra::Map<lno_t, gno_t, node_t> > colMap_;
265  lno_t base_;
266  ArrayRCP<gno_t> columnIds_; // TODO: Refactor adapter to localColumnIds_
267 
268  int nWeightsPerRow_;
269  ArrayRCP<StridedData<lno_t, scalar_t> > rowWeights_;
270  ArrayRCP<bool> numNzWeight_;
271 
272  bool mayHaveDiagonalEntries;
273 };
274 
276 // Definitions
278 
279 template <typename User, typename UserCoord>
281  const RCP<const User> &inmatrix, int nWeightsPerRow):
282  inmatrix_(inmatrix), matrix_(), rowMap_(), colMap_(),
283  columnIds_(),
284  nWeightsPerRow_(nWeightsPerRow), rowWeights_(), numNzWeight_(),
285  mayHaveDiagonalEntries(true)
286 {
287  typedef StridedData<lno_t,scalar_t> input_t;
288  try {
289  matrix_ = rcp_const_cast<const xmatrix_t>(
290  XpetraTraits<User>::convertToXpetra(rcp_const_cast<User>(inmatrix)));
291  }
293 
294  rowMap_ = matrix_->getRowMap();
295  colMap_ = matrix_->getColMap();
296 
297  size_t nrows = matrix_->getLocalNumRows();
298  size_t nnz = matrix_->getLocalNumEntries();
299 
300  // Get ArrayRCP pointers to the structures in the underlying matrix
301  ArrayRCP< const offset_t > offset;
302  ArrayRCP< const lno_t > localColumnIds;
303  ArrayRCP< const scalar_t > values;
304  matrix_->getAllValues(offset,localColumnIds,values);
305  columnIds_.resize(nnz, 0);
306 
307  for (offset_t i = 0; i < offset[nrows]; i++) {
308  columnIds_[i] = colMap_->getGlobalElement(localColumnIds[i]);
309  }
310 
311  if (nWeightsPerRow_ > 0){
312  rowWeights_ = arcp(new input_t [nWeightsPerRow_], 0, nWeightsPerRow_, true);
313  numNzWeight_ = arcp(new bool [nWeightsPerRow_], 0, nWeightsPerRow_, true);
314  for (int i=0; i < nWeightsPerRow_; i++)
315  numNzWeight_[i] = false;
316  }
317 }
318 
320 template <typename User, typename UserCoord>
322  const scalar_t *weightVal, int stride, int idx)
323 {
324  if (this->getPrimaryEntityType() == MATRIX_ROW)
325  setRowWeights(weightVal, stride, idx);
326  else {
327  // TODO: Need to allow weights for columns and/or nonzeros
328  std::ostringstream emsg;
329  emsg << __FILE__ << "," << __LINE__
330  << " error: setWeights not yet supported for"
331  << " columns or nonzeros."
332  << std::endl;
333  throw std::runtime_error(emsg.str());
334  }
335 }
336 
338 template <typename User, typename UserCoord>
340  const scalar_t *weightVal, int stride, int idx)
341 {
342  typedef StridedData<lno_t,scalar_t> input_t;
343  if(idx<0 || idx >= nWeightsPerRow_)
344  {
345  std::ostringstream emsg;
346  emsg << __FILE__ << ":" << __LINE__
347  << " Invalid row weight index " << idx << std::endl;
348  throw std::runtime_error(emsg.str());
349  }
350 
351  size_t nvtx = getLocalNumRows();
352  ArrayRCP<const scalar_t> weightV(weightVal, 0, nvtx*stride, false);
353  rowWeights_[idx] = input_t(weightV, stride);
354 }
355 
357 template <typename User, typename UserCoord>
359  int idx)
360 {
361  if (this->getPrimaryEntityType() == MATRIX_ROW)
362  setRowWeightIsNumberOfNonZeros(idx);
363  else {
364  // TODO: Need to allow weights for columns and/or nonzeros
365  std::ostringstream emsg;
366  emsg << __FILE__ << "," << __LINE__
367  << " error: setWeightIsNumberOfNonZeros not yet supported for"
368  << " columns" << std::endl;
369  throw std::runtime_error(emsg.str());
370  }
371 }
372 
374 template <typename User, typename UserCoord>
376  int idx)
377 {
378  if(idx<0 || idx >= nWeightsPerRow_)
379  {
380  std::ostringstream emsg;
381  emsg << __FILE__ << ":" << __LINE__
382  << " Invalid row weight index " << idx << std::endl;
383  throw std::runtime_error(emsg.str());
384  }
385 
386 
387  numNzWeight_[idx] = true;
388 }
389 
391 template <typename User, typename UserCoord>
392  template <typename Adapter>
394  const User &in, User *&out,
395  const PartitioningSolution<Adapter> &solution) const
396 {
397  // Get an import list (rows to be received)
398  size_t numNewRows;
399  ArrayRCP<gno_t> importList;
400  try{
401  numNewRows = Zoltan2::getImportList<Adapter,
403  (solution, this, importList);
404  }
406 
407  // Move the rows, creating a new matrix.
408  RCP<User> outPtr = XpetraTraits<User>::doMigration(in, numNewRows,
409  importList.getRawPtr());
410  out = const_cast<User *>(outPtr.get());
411  outPtr.release();
412 }
413 
415 template <typename User, typename UserCoord>
416  template <typename Adapter>
418  const User &in, RCP<User> &out,
419  const PartitioningSolution<Adapter> &solution) const
420 {
421  // Get an import list (rows to be received)
422  size_t numNewRows;
423  ArrayRCP<gno_t> importList;
424  try{
425  numNewRows = Zoltan2::getImportList<Adapter,
427  (solution, this, importList);
428  }
430 
431  // Move the rows, creating a new matrix.
432  out = XpetraTraits<User>::doMigration(in, numNewRows,
433  importList.getRawPtr());
434 }
435 
436 } //namespace Zoltan2
437 
438 #endif
Helper functions for Partitioning Problems.
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
void setRowWeights(const scalar_t *weightVal, int stride, int idx=0)
Specify a weight for each row.
typename InputTraits< User >::scalar_t scalar_t
MatrixAdapter defines the adapter interface for matrices.
void getColumnIDsView(const gno_t *&colIds) const
static ArrayRCP< ArrayRCP< zscalar_t > > weights
Provides access for Zoltan2 to Xpetra::CrsMatrix data.
void getRowWeightsView(const scalar_t *&weights, int &stride, int idx=0) const
Provide a pointer to the row weights, if any.
default_part_t part_t
The data type to represent part numbers.
default_offset_t offset_t
The data type to represent offsets.
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
Xpetra::CrsMatrix< zscalar_t, zlno_t, zgno_t, znode_t > xmatrix_t
static RCP< User > doMigration(const User &from, size_t numLocalRows, const gno_t *myNewRows)
Migrate the object Given a user object and a new row distribution, create and return a new user objec...
typename Zoltan2::InputTraits< ztcrsmatrix_t >::node_t node_t
int getNumWeightsPerRow() const
Returns the number of weights per row (0 or greater). Row weights may be used when partitioning matri...
size_t getLocalNumColumns() const
Returns the number of columns on this process.
void getCRSView(ArrayRCP< const offset_t > &offsets, ArrayRCP< const gno_t > &colIds) const
Traits of Xpetra classes, including migration method.
typename InputTraits< User >::part_t part_t
void getCCSView(ArrayRCP< const offset_t > &offsets, ArrayRCP< const gno_t > &rowIds) const override
static RCP< User > convertToXpetra(const RCP< User > &a)
Convert the object to its Xpetra wrapped version.
size_t getImportList(const PartitioningSolution< SolutionAdapter > &solution, const DataAdapter *const data, ArrayRCP< typename DataAdapter::gno_t > &imports)
From a PartitioningSolution, get a list of IDs to be imported. Assumes part numbers in PartitioningSo...
void getCRSView(ArrayRCP< const offset_t > &offsets, ArrayRCP< const gno_t > &colIds, ArrayRCP< const scalar_t > &values) const
A PartitioningSolution is a solution to a partitioning problem.
XpetraCrsMatrixAdapter(const RCP< const User > &inmatrix, int nWeightsPerRow=0)
Constructor.
void setWeightIsDegree(int idx)
Specify an index for which the weight should be the degree of the entity.
size_t getLocalNumRows() const
Returns the number of rows on this process.
default_lno_t lno_t
The ordinal type (e.g., int, long, int64_t) that represents local counts and local indices...
The StridedData class manages lists of weights or coordinates.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
default_gno_t gno_t
The ordinal type (e.g., int, long, int64_t) that can represent global counts and identifiers.
size_t getLocalNumEntries() const
Returns the number of nonzeros on this process.
default_node_t node_t
The Kokkos node type. This is only meaningful for users of Tpetra objects.
typename InputTraits< User >::offset_t offset_t
Defines the MatrixAdapter interface.
void setWeights(const scalar_t *weightVal, int stride, int idx=0)
Specify a weight for each entity of the primaryEntityType.
bool useNumNonzerosAsRowWeight(int idx) const
Indicate whether row weight with index idx should be the global number of nonzeros in the row...
void applyPartitioningSolution(const User &in, User *&out, const PartitioningSolution< Adapter > &solution) const
void setRowWeightIsNumberOfNonZeros(int idx)
Specify an index for which the row weight should be the global number of nonzeros in the row...
bool CRSViewAvailable() const
Indicates whether the MatrixAdapter implements a view of the matrix in compressed sparse row (CRS) fo...
default_scalar_t scalar_t
The data type for weights and coordinates.
void getRowIDsView(const gno_t *&rowIds) const
This file defines the StridedData class.