Zoltan2
Zoltan2_TpetraRowGraphAdapter.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Zoltan2: A package of combinatorial algorithms for scientific computing
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 Karen Devine (kddevin@sandia.gov)
39 // Erik Boman (egboman@sandia.gov)
40 // Siva Rajamanickam (srajama@sandia.gov)
41 //
42 // ***********************************************************************
43 //
44 // @HEADER
45 
50 #ifndef _ZOLTAN2_TPETRAROWGRAPHADAPTER_HPP_
51 #define _ZOLTAN2_TPETRAROWGRAPHADAPTER_HPP_
52 
53 #include <Zoltan2_GraphAdapter.hpp>
54 #include <Zoltan2_StridedData.hpp>
56 #include <Tpetra_RowGraph.hpp>
57 
58 namespace Zoltan2 {
59 
81 template <typename User, typename UserCoord=User>
82  class TpetraRowGraphAdapter : public GraphAdapter<User,UserCoord> {
83 
84 public:
85 
86 #ifndef DOXYGEN_SHOULD_SKIP_THIS
87  typedef typename InputTraits<User>::scalar_t scalar_t;
88  typedef typename InputTraits<User>::lno_t lno_t;
89  typedef typename InputTraits<User>::gno_t gno_t;
90  typedef typename InputTraits<User>::part_t part_t;
91  typedef typename InputTraits<User>::node_t node_t;
92  typedef User user_t;
93  typedef UserCoord userCoord_t;
94 #endif
95 
99 
109  TpetraRowGraphAdapter(const RCP<const User> &ingraph,
110  int nVtxWeights=0, int nEdgeWeights=0);
111 
124  void setWeights(const scalar_t *val, int stride, int idx);
125 
141  void setVertexWeights(const scalar_t *val, int stride, int idx);
142 
148  void setWeightIsDegree(int idx);
149 
155  void setVertexWeightIsDegree(int idx);
156 
179  void setEdgeWeights(const scalar_t *val, int stride, int idx);
180 
182  // The Adapter interface.
184 
186  // The GraphAdapter interface.
188 
189  // TODO: Assuming rows == objects;
190  // TODO: Need to add option for columns or nonzeros?
191  size_t getLocalNumVertices() const { return graph_->getNodeNumRows(); }
192 
193  void getVertexIDsView(const gno_t *&ids) const
194  {
195  ids = NULL;
196  if (getLocalNumVertices())
197  ids = graph_->getRowMap()->getNodeElementList().getRawPtr();
198  }
199 
200  size_t getLocalNumEdges() const { return graph_->getNodeNumEntries(); }
201 
202  void getEdgesView(const lno_t *&offsets, const gno_t *&adjIds) const
203  {
204  offsets = offs_.getRawPtr();
205  adjIds = (getLocalNumEdges() ? adjids_.getRawPtr() : NULL);
206  }
207 
208  int getNumWeightsPerVertex() const { return nWeightsPerVertex_;}
209 
210  void getVertexWeightsView(const scalar_t *&weights, int &stride,
211  int idx) const
212  {
213  if(idx<0 || idx >= nWeightsPerVertex_)
214  {
215  std::ostringstream emsg;
216  emsg << __FILE__ << ":" << __LINE__
217  << " Invalid vertex weight index " << idx << std::endl;
218  throw std::runtime_error(emsg.str());
219  }
220 
221  size_t length;
222  vertexWeights_[idx].getStridedList(length, weights, stride);
223  }
224 
225  bool useDegreeAsVertexWeight(int idx) const {return vertexDegreeWeight_[idx];}
226 
227  int getNumWeightsPerEdge() const { return nWeightsPerEdge_;}
228 
229  void getEdgeWeightsView(const scalar_t *&weights, int &stride, int idx) const
230  {
231  if(idx<0 || idx >= nWeightsPerEdge_)
232  {
233  std::ostringstream emsg;
234  emsg << __FILE__ << ":" << __LINE__
235  << " Invalid edge weight index " << idx << std::endl;
236  throw std::runtime_error(emsg.str());
237  }
238 
239  size_t length;
240  edgeWeights_[idx].getStridedList(length, weights, stride);
241  }
242 
243 
244  template <typename Adapter>
245  void applyPartitioningSolution(const User &in, User *&out,
246  const PartitioningSolution<Adapter> &solution) const;
247 
248  template <typename Adapter>
249  void applyPartitioningSolution(const User &in, RCP<User> &out,
250  const PartitioningSolution<Adapter> &solution) const;
251 
252 private:
253 
254  RCP<const User> graph_;
255 
256  ArrayRCP<const lno_t> offs_;
257  ArrayRCP<const gno_t> adjids_;
258 
259  int nWeightsPerVertex_;
260  ArrayRCP<StridedData<lno_t, scalar_t> > vertexWeights_;
261  ArrayRCP<bool> vertexDegreeWeight_;
262 
263  int nWeightsPerEdge_;
264  ArrayRCP<StridedData<lno_t, scalar_t> > edgeWeights_;
265 
266  int coordinateDim_;
267  ArrayRCP<StridedData<lno_t, scalar_t> > coords_;
268 
269  RCP<User> doMigration(const User &from, size_t numLocalRows,
270  const gno_t *myNewRows) const;
271 };
272 
274 // Definitions
276 
277 template <typename User, typename UserCoord>
279  const RCP<const User> &ingraph, int nVtxWgts, int nEdgeWgts):
280  graph_(ingraph), offs_(),
281  adjids_(),
282  nWeightsPerVertex_(nVtxWgts), vertexWeights_(), vertexDegreeWeight_(),
283  nWeightsPerEdge_(nEdgeWgts), edgeWeights_(),
284  coordinateDim_(0), coords_()
285 {
286  typedef StridedData<lno_t,scalar_t> input_t;
287 
288  size_t nvtx = graph_->getNodeNumRows();
289  size_t nedges = graph_->getNodeNumEntries();
290  size_t maxnumentries =
291  graph_->getNodeMaxNumRowEntries(); // Diff from CrsMatrix
292 
293  // Unfortunately we have to copy the offsets and edge Ids
294  // because edge Ids are not usually stored in vertex id order.
295 
296  size_t n = nvtx + 1;
297  lno_t *offs = new lno_t [n];
298 
299  if (!offs)
300  {
301  std::cerr << "Error: " << __FILE__ << ", " << __LINE__<< std::endl;
302  std::cerr << n << " objects" << std::endl;
303  throw std::bad_alloc();
304  }
305 
306  gno_t *adjids = NULL;
307  if (nedges)
308  {
309  adjids = new gno_t [nedges];
310 
311  if (!adjids)
312  {
313  std::cerr << "Error: " << __FILE__ << ", " << __LINE__<< std::endl;
314  std::cerr << nedges << " objects" << std::endl;
315  throw std::bad_alloc();
316  }
317  }
318 
319  ArrayRCP<lno_t> nbors(maxnumentries); // Diff from CrsGraph
320 
321  offs[0] = 0;
322  for (size_t v=0; v < nvtx; v++){
323  graph_->getLocalRowCopy(v, nbors(), nedges); // Diff from CrsGraph
324  offs[v+1] = offs[v] + nedges;
325  for (lno_t e=offs[v], i=0; e < offs[v+1]; e++) {
326  adjids[e] = graph_->getColMap()->getGlobalElement(nbors[i++]);
327  }
328  }
329 
330  offs_ = arcp(offs, 0, n, true);
331  adjids_ = arcp(adjids, 0, nedges, true);
332 
333  if (nWeightsPerVertex_ > 0) {
334  vertexWeights_ =
335  arcp(new input_t[nWeightsPerVertex_], 0, nWeightsPerVertex_, true);
336  vertexDegreeWeight_ =
337  arcp(new bool[nWeightsPerVertex_], 0, nWeightsPerVertex_, true);
338  for (int i=0; i < nWeightsPerVertex_; i++)
339  vertexDegreeWeight_[i] = false;
340  }
341 
342  if (nWeightsPerEdge_ > 0)
343  edgeWeights_ = arcp(new input_t[nWeightsPerEdge_], 0, nWeightsPerEdge_, true);
344 }
345 
347 template <typename User, typename UserCoord>
349  const scalar_t *weightVal, int stride, int idx)
350 {
351  if (this->getPrimaryEntityType() == GRAPH_VERTEX)
352  setVertexWeights(weightVal, stride, idx);
353  else
354  setEdgeWeights(weightVal, stride, idx);
355 }
356 
358 template <typename User, typename UserCoord>
360  const scalar_t *weightVal, int stride, int idx)
361 {
362  typedef StridedData<lno_t,scalar_t> input_t;
363  if(idx<0 || idx >= nWeightsPerVertex_)
364  {
365  std::ostringstream emsg;
366  emsg << __FILE__ << ":" << __LINE__
367  << " Invalid vertex weight index " << idx << std::endl;
368  throw std::runtime_error(emsg.str());
369  }
370 
371  size_t nvtx = getLocalNumVertices();
372  ArrayRCP<const scalar_t> weightV(weightVal, 0, nvtx*stride, false);
373  vertexWeights_[idx] = input_t(weightV, stride);
374 }
375 
377 template <typename User, typename UserCoord>
379  int idx)
380 {
381  if (this->getPrimaryEntityType() == GRAPH_VERTEX)
383  else {
384  std::ostringstream emsg;
385  emsg << __FILE__ << "," << __LINE__
386  << " error: setWeightIsNumberOfNonZeros is supported only for"
387  << " vertices" << std::endl;
388  throw std::runtime_error(emsg.str());
389  }
390 }
391 
393 template <typename User, typename UserCoord>
395  int idx)
396 {
397  if(idx<0 || idx >= nWeightsPerVertex_)
398  {
399  std::ostringstream emsg;
400  emsg << __FILE__ << ":" << __LINE__
401  << " Invalid vertex weight index " << idx << std::endl;
402  throw std::runtime_error(emsg.str());
403  }
404 
405  vertexDegreeWeight_[idx] = true;
406 }
407 
409 template <typename User, typename UserCoord>
411  const scalar_t *weightVal, int stride, int idx)
412 {
413  typedef StridedData<lno_t,scalar_t> input_t;
414 
415  if(idx<0 || idx >= nWeightsPerEdge_)
416  {
417  std::ostringstream emsg;
418  emsg << __FILE__ << ":" << __LINE__
419  << " Invalid edge weight index " << idx << std::endl;
420  throw std::runtime_error(emsg.str());
421  }
422 
423  size_t nedges = getLocalNumEdges();
424  ArrayRCP<const scalar_t> weightV(weightVal, 0, nedges*stride, false);
425  edgeWeights_[idx] = input_t(weightV, stride);
426 }
427 
429 template <typename User, typename UserCoord>
430  template<typename Adapter>
432  const User &in, User *&out,
433  const PartitioningSolution<Adapter> &solution) const
434 {
435  // Get an import list (rows to be received)
436  size_t numNewVtx;
437  ArrayRCP<gno_t> importList;
438  try{
439  numNewVtx = Zoltan2::getImportList<Adapter,
441  (solution, this, importList);
442  }
444 
445  // Move the rows, creating a new graph.
446  RCP<User> outPtr = doMigration(in, numNewVtx, importList.getRawPtr());
447  out = outPtr.get();
448  outPtr.release();
449 }
450 
452 template <typename User, typename UserCoord>
453  template<typename Adapter>
455  const User &in, RCP<User> &out,
456  const PartitioningSolution<Adapter> &solution) const
457 {
458  // Get an import list (rows to be received)
459  size_t numNewVtx;
460  ArrayRCP<gno_t> importList;
461  try{
462  numNewVtx = Zoltan2::getImportList<Adapter,
464  (solution, this, importList);
465  }
467 
468  // Move the rows, creating a new graph.
469  out = doMigration(in, numNewVtx, importList.getRawPtr());
470 }
471 
472 
474 template < typename User, typename UserCoord>
476  const User &from,
477  size_t numLocalRows,
478  const gno_t *myNewRows
479 ) const
480 {
481  typedef Tpetra::Map<lno_t, gno_t, node_t> map_t;
482  typedef Tpetra::CrsGraph<lno_t, gno_t, node_t> tcrsgraph_t;
483 
484  // We cannot create a Tpetra::RowGraph, unless the underlying type is
485  // something we know (like Tpetra::CrsGraph).
486  // If the underlying type is something different, the user probably doesn't
487  // want a Tpetra::CrsGraph back, so we throw an error.
488 
489  // Try to cast "from" graph to a TPetra::CrsGraph
490  // If that fails we throw an error.
491  // We could cast as a ref which will throw std::bad_cast but with ptr
492  // approach it might be clearer what's going on here
493  const tcrsgraph_t *pCrsGraphSrc = dynamic_cast<const tcrsgraph_t *>(&from);
494 
495  if(!pCrsGraphSrc) {
496  throw std::logic_error("TpetraRowGraphAdapter cannot migrate data for "
497  "your RowGraph; it can migrate data only for "
498  "Tpetra::CrsGraph. "
499  "You can inherit from TpetraRowGraphAdapter and "
500  "implement migration for your RowGraph.");
501  }
502 
503  // source map
504  const RCP<const map_t> &smap = from.getRowMap();
505  int oldNumElts = smap->getNodeNumElements();
506  gno_t numGlobalRows = smap->getGlobalNumElements();
507  gno_t base = smap->getMinAllGlobalIndex();
508 
509  // target map
510  ArrayView<const gno_t> rowList(myNewRows, numLocalRows);
511  const RCP<const Teuchos::Comm<int> > &comm = from.getComm();
512  RCP<const map_t> tmap = rcp(new map_t(numGlobalRows, rowList, base, comm));
513 
514  // importer
515  Tpetra::Import<lno_t, gno_t, node_t> importer(smap, tmap);
516 
517  // number of entries in my new rows
518  typedef Tpetra::Vector<gno_t, lno_t, gno_t, node_t> vector_t;
519  vector_t numOld(smap);
520  vector_t numNew(tmap);
521  for (int lid=0; lid < oldNumElts; lid++){
522  numOld.replaceGlobalValue(smap->getGlobalElement(lid),
523  from.getNumEntriesInLocalRow(lid));
524  }
525  numNew.doImport(numOld, importer, Tpetra::INSERT);
526 
527  size_t numElts = tmap->getNodeNumElements();
528  ArrayRCP<const gno_t> nnz;
529  if (numElts > 0)
530  nnz = numNew.getData(0); // hangs if vector len == 0
531 
532  ArrayRCP<const size_t> nnz_size_t;
533 
534  if (numElts && sizeof(gno_t) != sizeof(size_t)){
535  size_t *vals = new size_t [numElts];
536  nnz_size_t = arcp(vals, 0, numElts, true);
537  for (size_t i=0; i < numElts; i++){
538  vals[i] = static_cast<size_t>(nnz[i]);
539  }
540  }
541  else{
542  nnz_size_t = arcp_reinterpret_cast<const size_t>(nnz);
543  }
544 
545  // target graph
546  RCP<tcrsgraph_t> G = rcp(new tcrsgraph_t(tmap, nnz_size_t,
547  Tpetra::StaticProfile));
548 
549  G->doImport(*pCrsGraphSrc, importer, Tpetra::INSERT);
550  G->fillComplete();
551  return Teuchos::rcp_dynamic_cast<User>(G);
552 }
553 
554 } //namespace Zoltan2
555 
556 #endif
InputTraits< User >::scalar_t scalar_t
Helper functions for Partitioning Problems.
void setWeightIsDegree(int idx)
Specify an index for which the weight should be the degree of the entity.
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
size_t getLocalNumEdges() const
Returns the number of edges on this process.
InputTraits< User >::gno_t gno_t
bool useDegreeAsVertexWeight(int idx) const
Indicate whether vertex weight with index idx should be the global degree of the vertex.
GraphAdapter defines the interface for graph-based user data.
void setVertexWeights(const scalar_t *val, int stride, int idx)
Provide a pointer to vertex weights.
default_part_t part_t
The data type to represent part numbers.
InputTraits< User >::lno_t lno_t
static ArrayRCP< ArrayRCP< zscalar_t > > weights
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 getEdgeWeightsView(const scalar_t *&weights, int &stride, int idx) const
void applyPartitioningSolution(const User &in, User *&out, const PartitioningSolution< Adapter > &solution) const
int getNumWeightsPerEdge() const
Returns the number (0 or greater) of edge weights.
dictionary vals
Definition: xml2dox.py:186
A PartitioningSolution is a solution to a partitioning problem.
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.
InputTraits< User >::part_t part_t
default_gno_t gno_t
The ordinal type (e.g., int, long, int64_t) that can represent global counts and identifiers.
default_node_t node_t
The Kokkos node type. This is only meaningful for users of Tpetra objects.
size_t getLocalNumVertices() const
Returns the number of vertices on this process.
enum GraphEntityType getPrimaryEntityType() const
Returns the entity to be partitioned, ordered, colored, etc. Valid values are GRAPH_VERTEX or GRAPH_E...
void setVertexWeightIsDegree(int idx)
Specify an index for which the vertex weight should be the degree of the vertex.
TpetraRowGraphAdapter(const RCP< const User > &ingraph, int nVtxWeights=0, int nEdgeWeights=0)
Constructor for graph with no weights or coordinates.
void setEdgeWeights(const scalar_t *val, int stride, int idx)
Provide a pointer to edge weights.
void getVertexIDsView(const gno_t *&ids) const
Sets pointers to this process&#39; graph entries.
Defines the GraphAdapter interface.
void getVertexWeightsView(const scalar_t *&weights, int &stride, int idx) const
void setWeights(const scalar_t *val, int stride, int idx)
Provide a pointer to weights for the primary entity type.
default_scalar_t scalar_t
The data type for weights and coordinates.
void getEdgesView(const lno_t *&offsets, const gno_t *&adjIds) const
Gets adjacency lists for all vertices in a compressed sparse row (CSR) format.
int getNumWeightsPerVertex() const
Returns the number (0 or greater) of weights per vertex.
Provides access for Zoltan2 to Tpetra::RowGraph data.
This file defines the StridedData class.