Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Zoltan2_GraphModel.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_GRAPHMODEL_HPP_
15 #define _ZOLTAN2_GRAPHMODEL_HPP_
16 
17 #include <Zoltan2_Model.hpp>
18 #include <Zoltan2_ModelHelpers.hpp>
19 #include <Zoltan2_InputTraits.hpp>
21 #include <Zoltan2_GraphAdapter.hpp>
24 #include <Zoltan2_MeshAdapter.hpp>
25 #include <Zoltan2_StridedData.hpp>
26 #include <unordered_map>
27 
28 namespace Zoltan2 {
29 
31 
43 template <typename Adapter>
44 class GraphModel : public Model<Adapter>
45 {
46 public:
47 
48 #ifndef DOXYGEN_SHOULD_SKIP_THIS
49  typedef typename Adapter::scalar_t scalar_t;
50  typedef typename Adapter::gno_t gno_t;
51  typedef typename Adapter::lno_t lno_t;
52  typedef typename Adapter::node_t node_t;
53  typedef typename Adapter::user_t user_t;
54  typedef typename Adapter::userCoord_t userCoord_t;
55  typedef StridedData<lno_t, scalar_t> input_t;
56  typedef typename Adapter::offset_t offset_t;
57 #endif
58 
61 
73  GraphModel(const RCP<const MatrixAdapter<user_t,userCoord_t> > &ia,
74  const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
75  modelFlag_t &modelFlags);
76 
77  GraphModel(const RCP<const GraphAdapter<user_t,userCoord_t> > &ia,
78  const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
79  modelFlag_t &modelFlags);
80 
81  GraphModel(const RCP<const MeshAdapter<user_t> > &ia,
82  const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
83  modelFlag_t &modelflags);
84 
85  GraphModel(const RCP<const VectorAdapter<userCoord_t> > &/* ia */,
86  const RCP<const Environment> &/* env */, const RCP<const Comm<int> > &/* comm */,
87  modelFlag_t &/* flags */)
88  {
89  throw std::runtime_error("cannot build GraphModel from VectorAdapter");
90  }
91 
92  GraphModel(const RCP<const IdentifierAdapter<user_t> > &ia,
93  const RCP<const Environment> &env, const RCP<const Comm<int> > &comm,
94  modelFlag_t &flags)
95  {
96  throw std::runtime_error("cannot build GraphModel from IdentifierAdapter");
97  }
98 
101  const RCP<const Comm<int> > getComm() { return comm_; }
102 
105  size_t getLocalNumVertices() const { return nLocalVertices_; }
106 
109  size_t getGlobalNumVertices() const { return nGlobalVertices_; }
110 
114  size_t getLocalNumEdges() const { return nLocalEdges_; }
115 
119  size_t getGlobalNumEdges() const { return nGlobalEdges_; }
120 
123  int getNumWeightsPerVertex() const { return nWeightsPerVertex_; }
124 
127  int getNumWeightsPerEdge() const { return nWeightsPerEdge_; }
128 
131  int getCoordinateDim() const { return vCoordDim_; }
132 
142  ArrayView<const gno_t> &Ids,
143  ArrayView<input_t> &wgts) const
144  {
145  Ids = vGids_.view(0, nLocalVertices_);
146  wgts = vWeights_.view(0, nWeightsPerVertex_);
147  return nLocalVertices_;
148  }
149 
156  size_t getVertexCoords(ArrayView<input_t> &xyz) const
157  {
158  xyz = vCoords_.view(0, vCoordDim_);
159  return nLocalVertices_;
160  }
161 
173  // Implied Vertex LNOs from getVertexList are used as indices to offsets
174  // array.
175  // Vertex GNOs are returned as neighbors in edgeIds.
176 
177  size_t getEdgeList( ArrayView<const gno_t> &edgeIds,
178  ArrayView<const offset_t> &offsets,
179  ArrayView<input_t> &wgts) const
180  {
181  edgeIds = eGids_.view(0, nLocalEdges_);
182  offsets = eOffsets_.view(0, nLocalVertices_+1);
183  wgts = eWeights_.view(0, nWeightsPerEdge_);
184  return nLocalEdges_;
185  }
186 
191  inline void getVertexDist(ArrayView<size_t> &vtxdist) const
192  {
193  vtxdist = vtxDist_();
194  if (vtxDist_.size() == 0) {
195  throw std::runtime_error("getVertexDist is available only "
196  "when consecutiveIdsRequired");
197  }
198  }
199 
201  // The Model interface.
203 
204  size_t getLocalNumObjects() const { return nLocalVertices_; }
205 
206  size_t getGlobalNumObjects() const { return nGlobalVertices_; }
207 
208 private:
209 
210  void shared_constructor(const RCP<const Adapter>&ia, modelFlag_t &modelFlags);
211 
212  template <typename AdapterWithCoords>
213  void shared_GetVertexCoords(const AdapterWithCoords *ia);
214 
215  void print(); // For debugging
216 
217  const RCP<const Environment > env_;
218  const RCP<const Comm<int> > comm_;
219 
220  bool localGraph_; // Flag indicating whether this graph is
221  // LOCAL with respect to the process;
222  // if !localGraph_, graph is GLOBAL with respect to
223  // the communicator.
224 
225 
226  size_t nLocalVertices_; // # local vertices in built graph
227  size_t nGlobalVertices_; // # global vertices in built graph
228  ArrayRCP<gno_t> vGids_; // vertices of graph built in model;
229  // may be same as adapter's input
230  // or may be renumbered 0 to (N-1).
231 
232  int nWeightsPerVertex_;
233  ArrayRCP<input_t> vWeights_;
234 
235  int vCoordDim_;
236  ArrayRCP<input_t> vCoords_;
237 
238  // Note: in some cases, size of these arrays
239  // may be larger than nLocalEdges_. So do not use .size().
240  // Use nLocalEdges_, nGlobalEdges_
241 
242  size_t nLocalEdges_; // # local edges in built graph
243  size_t nGlobalEdges_; // # global edges in built graph
244  ArrayRCP<gno_t> eGids_; // edges of graph built in model
245  ArrayRCP<offset_t> eOffsets_; // edge offsets build in model
246  // May be same as adapter's input
247  // or may differ
248  // due to renumbering, self-edge
249  // removal, or local graph.
250 
251  int nWeightsPerEdge_;
252  ArrayRCP<input_t> eWeights_; // edge weights in built graph
253  // May be same as adapter's input
254  // or may differ due to self-edge
255  // removal, or local graph.
256 
257  ArrayRCP<size_t> vtxDist_; // If consecutiveIdsRequired,
258  // vtxDist (as needed by ParMETIS
259  // and Scotch) is also created.
260  // Otherwise, it is Teuchos::null.
261 };
262 
263 
265 // GraphModel from MatrixAdapter
266 template <typename Adapter>
268  const RCP<const MatrixAdapter<user_t,userCoord_t> > &ia,
269  const RCP<const Environment> &env,
270  const RCP<const Comm<int> > &comm,
271  modelFlag_t &modelFlags):
272  env_(env),
273  comm_(comm),
274  localGraph_(false),
275  nLocalVertices_(0),
276  nGlobalVertices_(0),
277  vGids_(),
278  nWeightsPerVertex_(0),
279  vWeights_(),
280  vCoordDim_(0),
281  vCoords_(),
282  nLocalEdges_(0),
283  nGlobalEdges_(0),
284  eGids_(),
285  eOffsets_(),
286  nWeightsPerEdge_(0),
287  eWeights_(),
288  vtxDist_()
289 {
290  // Model creation flags
291  localGraph_ = modelFlags.test(BUILD_LOCAL_GRAPH);
292 
293  bool symTranspose = modelFlags.test(SYMMETRIZE_INPUT_TRANSPOSE);
294  bool symBipartite = modelFlags.test(SYMMETRIZE_INPUT_BIPARTITE);
295  bool vertexCols = modelFlags.test(VERTICES_ARE_MATRIX_COLUMNS);
296  bool vertexNz = modelFlags.test(VERTICES_ARE_MATRIX_NONZEROS);
297 
298  if (symTranspose || symBipartite || vertexCols || vertexNz){
299  throw std::runtime_error("graph build option not yet implemented");
300  }
301 
302  // Get the matrix from the input adapter
303  gno_t const *vtxIds=NULL;
304  ArrayRCP<const gno_t> nborIds;
305  ArrayRCP<const offset_t> offsets;
306 
307  try{
308  nLocalVertices_ = ia->getLocalNumIDs();
309  ia->getIDsView(vtxIds);
310  }
312  try{
313  if (ia->CRSViewAvailable()) {
314  ia->getCRSView(offsets, nborIds);
315  }
316  else {
317  // TODO: Add support for CCS matrix layout
318  throw std::runtime_error("Only MatrixAdapter::getCRSView is supported "
319  "in graph model");
320  }
321  }
323 
324  // Save the pointers from the input adapter
325  nLocalEdges_ = offsets[nLocalVertices_];
326  vGids_ = arcp_const_cast<gno_t>(
327  arcp<const gno_t>(vtxIds, 0, nLocalVertices_, false));
328  eGids_ = arcp_const_cast<gno_t>(nborIds);
329  eOffsets_ = arcp_const_cast<offset_t>(offsets);
330 
331  // Edge weights
332  nWeightsPerEdge_ = 0; // no edge weights from a matrix yet.
333  // TODO: use matrix values as edge weights
334 
335  // Do constructor common to all adapters
336  shared_constructor(ia, modelFlags);
337 
338  // Get vertex coordinates, if available
339  if (ia->coordinatesAvailable()) {
340  typedef VectorAdapter<userCoord_t> adapterWithCoords_t;
341  shared_GetVertexCoords<adapterWithCoords_t>(ia->getCoordinateInput());
342  }
343  // print();
344 }
345 
346 
348 // GraphModel from GraphAdapter
349 template <typename Adapter>
351  const RCP<const GraphAdapter<user_t,userCoord_t> > &ia,
352  const RCP<const Environment> &env,
353  const RCP<const Comm<int> > &comm,
354  modelFlag_t &modelFlags):
355  env_(env),
356  comm_(comm),
357  localGraph_(false),
358  nLocalVertices_(0),
359  nGlobalVertices_(0),
360  vGids_(),
361  nWeightsPerVertex_(0),
362  vWeights_(),
363  vCoordDim_(0),
364  vCoords_(),
365  nLocalEdges_(0),
366  nGlobalEdges_(0),
367  eGids_(),
368  eOffsets_(),
369  nWeightsPerEdge_(0),
370  eWeights_(),
371  vtxDist_()
372 {
373  // Model creation flags
374  localGraph_ = modelFlags.test(BUILD_LOCAL_GRAPH);
375 
376  // This GraphModel is built with vertices == GRAPH_VERTEX from GraphAdapter.
377  // It is not ready to use vertices == GRAPH_EDGE from GraphAdapter.
378  env_->localInputAssertion(__FILE__, __LINE__,
379  "GraphModel from GraphAdapter is implemented only for "
380  "Graph Vertices as primary object, not for Graph Edges",
381  ia->getPrimaryEntityType() == Zoltan2::GRAPH_VERTEX, BASIC_ASSERTION);
382 
383  // Get the graph from the input adapter
384 
385  gno_t const *vtxIds=NULL, *nborIds=NULL;
386  offset_t const *offsets=NULL;
387  try{
388  nLocalVertices_ = ia->getLocalNumVertices();
389  ia->getVertexIDsView(vtxIds);
390  ia->getEdgesView(offsets, nborIds);
391  }
393 
394  // Save the pointers from the input adapter
395  nLocalEdges_ = offsets[nLocalVertices_];
396  vGids_ = arcp_const_cast<gno_t>(
397  arcp<const gno_t>(vtxIds, 0, nLocalVertices_, false));
398  eGids_ = arcp_const_cast<gno_t>(
399  arcp<const gno_t>(nborIds, 0, nLocalEdges_, false));
400  eOffsets_ = arcp_const_cast<offset_t>(
401  arcp<const offset_t>(offsets, 0, nLocalVertices_+1, false));
402 
403  // Edge weights
404  nWeightsPerEdge_ = ia->getNumWeightsPerEdge();
405  if (nWeightsPerEdge_ > 0){
406  input_t *wgts = new input_t [nWeightsPerEdge_];
407  eWeights_ = arcp(wgts, 0, nWeightsPerEdge_, true);
408  }
409 
410  for (int w=0; w < nWeightsPerEdge_; w++){
411  const scalar_t *ewgts=NULL;
412  int stride=0;
413 
414  ia->getEdgeWeightsView(ewgts, stride, w);
415 
416  ArrayRCP<const scalar_t> wgtArray(ewgts, 0, nLocalEdges_, false);
417  eWeights_[w] = input_t(wgtArray, stride);
418  }
419 
420  // Do constructor common to all adapters
421  shared_constructor(ia, modelFlags);
422 
423  // Get vertex coordinates, if available
424  if (ia->coordinatesAvailable()) {
425  typedef VectorAdapter<userCoord_t> adapterWithCoords_t;
426  shared_GetVertexCoords<adapterWithCoords_t>(ia->getCoordinateInput());
427  }
428  // print();
429 }
430 
432 // GraphModel from MeshAdapter
433 template <typename Adapter>
435  const RCP<const MeshAdapter<user_t> > &ia,
436  const RCP<const Environment> &env,
437  const RCP<const Comm<int> > &comm,
438  modelFlag_t &modelFlags):
439  env_(env),
440  comm_(comm),
441  localGraph_(false),
442  nLocalVertices_(0),
443  nGlobalVertices_(0),
444  vGids_(),
445  nWeightsPerVertex_(0),
446  vWeights_(),
447  vCoordDim_(0),
448  vCoords_(),
449  nLocalEdges_(0),
450  nGlobalEdges_(0),
451  eGids_(),
452  eOffsets_(),
453  nWeightsPerEdge_(0),
454  eWeights_(),
455  vtxDist_()
456 {
457  env_->timerStart(MACRO_TIMERS, "GraphModel constructed from MeshAdapter");
458 
459  // Model creation flags
460  localGraph_ = modelFlags.test(BUILD_LOCAL_GRAPH);
461 
462  // This GraphModel is built with vertices == ia->getPrimaryEntityType()
463  // from MeshAdapter.
464 
465  // Get the graph from the input adapter
466 
467  Zoltan2::MeshEntityType primaryEType = ia->getPrimaryEntityType();
468  Zoltan2::MeshEntityType secondAdjEType = ia->getSecondAdjacencyEntityType();
469 
470  // Get the IDs of the primary entity type; these are graph vertices
471 
472  gno_t const *vtxIds=NULL;
473  try {
474  nLocalVertices_ = ia->getLocalNumOf(primaryEType);
475  ia->getIDsViewOf(primaryEType, vtxIds);
476  }
478 
479  vGids_ = arcp_const_cast<gno_t>(
480  arcp<const gno_t>(vtxIds, 0, nLocalVertices_, false));
481 
482  // Get the second adjacencies to construct edges of the dual graph.
483 
484  if (!ia->avail2ndAdjs(primaryEType, secondAdjEType)) {
485  // KDDKDD TODO Want to do this differently for local and global graphs?
486  // KDDKDD TODO Currently getting global 2nd Adjs and filtering them for
487  // KDDKDD TODO local graphs. That approach is consistent with other
488  // KDDKDD TODO adapters, but is more expensive -- why build them just to
489  // KDDKDD TODO throw them away? Instead, perhaps should build
490  // KDDKDD TODO only local adjacencies.
491  // KDDKDD TODO Does it suffice to pass a serial comm for local graph?
492  try {
493  get2ndAdjsViewFromAdjs(ia, comm_, primaryEType, secondAdjEType, eOffsets_,
494  eGids_);
495  nLocalEdges_ = eOffsets_[nLocalVertices_];
496  }
498  }
499  else { // avail2ndAdjs
500  // Get the edges
501  try {
502  gno_t const *nborIds=NULL;
503  offset_t const *offsets=NULL;
504 
505  ia->get2ndAdjsView(primaryEType, secondAdjEType, offsets, nborIds);
506  // Save the pointers from the input adapter; we do not control the
507  // offsets and nborIds memory
508  nLocalEdges_ = offsets[nLocalVertices_];
509  eGids_ = arcp_const_cast<gno_t>(
510  arcp<const gno_t>(nborIds, 0, nLocalEdges_, false));
511  eOffsets_ = arcp_const_cast<offset_t>(
512  arcp<const offset_t>(offsets, 0, nLocalVertices_+1, false));
513  }
515  }
516 
517 
518  // Edge weights
519  // Cannot specify edge weights if Zoltan2 computes the second adjacencies;
520  // there's no way to know the correct order for the adjacencies and weights.
521  // InputAdapter must provide 2nd adjs in order for edge weights to be used.
522  if (ia->avail2ndAdjs(primaryEType, secondAdjEType)) {
523  nWeightsPerEdge_ = ia->getNumWeightsPer2ndAdj(primaryEType, secondAdjEType);
524  if (nWeightsPerEdge_ > 0){
525  input_t *wgts = new input_t [nWeightsPerEdge_];
526  eWeights_ = arcp(wgts, 0, nWeightsPerEdge_, true);
527  }
528 
529  for (int w=0; w < nWeightsPerEdge_; w++){
530  const scalar_t *ewgts=NULL;
531  int stride=0;
532 
533  ia->get2ndAdjWeightsView(primaryEType, secondAdjEType,
534  ewgts, stride, w);
535 
536  ArrayRCP<const scalar_t> wgtArray(ewgts, 0,
537  nLocalEdges_*stride, false);
538  eWeights_[w] = input_t(wgtArray, stride);
539  }
540  }
541 
542  // Do constructor common to all adapters
543  shared_constructor(ia, modelFlags);
544 
545  // Get vertex coordinates
546  typedef MeshAdapter<user_t> adapterWithCoords_t;
547  shared_GetVertexCoords<adapterWithCoords_t>(&(*ia));
548 
549  env_->timerStop(MACRO_TIMERS, "GraphModel constructed from MeshAdapter");
550  // print();
551 }
552 
553 
555 template <typename Adapter>
557  const RCP<const Adapter> &ia,
558  modelFlag_t &modelFlags)
559 {
560  // Model creation flags
561  bool consecutiveIdsRequired = modelFlags.test(GENERATE_CONSECUTIVE_IDS);
562  bool removeSelfEdges = modelFlags.test(REMOVE_SELF_EDGES);
563  bool subsetGraph = modelFlags.test(BUILD_SUBSET_GRAPH);
564 
565  // May modify the graph provided from input adapter; save pointers to
566  // the input adapter's data.
567  size_t adapterNLocalEdges = nLocalEdges_;
568  ArrayRCP<gno_t> adapterVGids = vGids_; // vertices of graph from adapter
569  ArrayRCP<gno_t> adapterEGids = eGids_; // edges of graph from adapter
570  ArrayRCP<offset_t> adapterEOffsets = eOffsets_; // edge offsets from adapter
571  ArrayRCP<input_t> adapterEWeights = eWeights_; // edge weights from adapter
572 
573  if (localGraph_) {
574  // Local graph is requested.
575  // Renumber vertices 0 to nLocalVertices_-1
576  // Filter out off-process edges
577  // Renumber edge neighbors to be in range [0,nLocalVertices_-1]
578 
579  // Allocate new space for local graph info
580  // Note that eGids_ and eWeights_[w] may be larger than needed;
581  // we would have to pre-count the number of local edges to avoid overalloc
582  vGids_ = arcp(new gno_t[nLocalVertices_],
583  0, nLocalVertices_, true);
584  eGids_ = arcp(new gno_t[adapterNLocalEdges],
585  0, adapterNLocalEdges, true);
586  eOffsets_ = arcp(new offset_t[nLocalVertices_+1],
587  0, nLocalVertices_+1, true);
588 
589  scalar_t **tmpEWeights = NULL;
590  if (nWeightsPerEdge_ > 0){
591  eWeights_ = arcp(new input_t[nWeightsPerEdge_], 0,
592  nWeightsPerEdge_, true);
593  // Need to use temporary array because StridedData has const data
594  // so we can't write to it.
595  tmpEWeights = new scalar_t*[nWeightsPerEdge_];
596  for (int w = 0; w < nWeightsPerEdge_; w++)
597  tmpEWeights[w] = new scalar_t[adapterNLocalEdges];
598  }
599 
600  // Build map between global and local vertex numbers
601  std::unordered_map<gno_t, lno_t> globalToLocal(nLocalVertices_);
602  for (size_t i = 0; i < nLocalVertices_; i++)
603  globalToLocal[adapterVGids[i]] = i;
604 
605  // Loop over edges; keep only those that are local (i.e., on-rank)
606  eOffsets_[0] = 0;
607  offset_t ecnt = 0;
608  for (size_t i = 0; i < nLocalVertices_; i++) {
609  vGids_[i] = gno_t(i);
610  for (offset_t j = adapterEOffsets[i]; j < adapterEOffsets[i+1]; j++) {
611 
612  if (removeSelfEdges && (adapterEGids[j] == adapterVGids[i]))
613  continue; // Skipping self edge
614 
615  // Determine whether neighbor vertex is local
616  typename std::unordered_map<gno_t, lno_t>::iterator localidx;
617  if ((localidx = globalToLocal.find(adapterEGids[j])) !=
618  globalToLocal.end()) {
619  // neighbor vertex is local
620  // Keep the edge and its weights
621  eGids_[ecnt] = localidx->second;
622  for (int w = 0; w < nWeightsPerEdge_; w++)
623  tmpEWeights[w][ecnt] = adapterEWeights[w][j];
624 
625  ecnt++;
626  }
627  }
628  eOffsets_[i+1] = ecnt;
629  }
630  nLocalEdges_ = eOffsets_[nLocalVertices_];
631  if (nWeightsPerEdge_) {
632  for (int w = 0; w < nWeightsPerEdge_; w++) {
633  ArrayRCP<const scalar_t> wgtArray(tmpEWeights[w],
634  0, adapterNLocalEdges, true);
635  eWeights_[w] = input_t(wgtArray, 0);
636  }
637  delete [] tmpEWeights;
638  }
639  } // localGraph_
640 
641  else if (consecutiveIdsRequired || removeSelfEdges || subsetGraph) {
642  // Build a Global graph
643  // If we are here, we expect SOMETHING in the graph to change from input:
644  // removing self edges, or converting to consecutive IDs, or subsetting
645  // the graph.
646 
647 
648  // Determine vertex GIDs for the global GraphModel
649  if (consecutiveIdsRequired) {
650  // Allocate new memory for vertices for consecutiveIds
651  vGids_ = arcp(new gno_t[nLocalVertices_], 0, nLocalVertices_, true);
652 
653  // Build vtxDist_ array with starting vGid on each rank
654  int np = comm_->getSize();
655  vtxDist_ = arcp(new size_t[np+1], 0, np+1, true);
656  vtxDist_[0] = 0;
657  Teuchos::gatherAll(*comm_, 1, &nLocalVertices_, np, &vtxDist_[1]);
658  for (int i = 0; i < np; i++)
659  vtxDist_[i+1] += vtxDist_[i];
660  }
661 
662  // Allocate new memory for edges and offsets, as needed
663  // Note that eGids_ may or may not be larger than needed;
664  // would have to pre-count number of edges kept otherwise
665  eGids_ = arcp(new gno_t[adapterNLocalEdges],
666  0, adapterNLocalEdges, true);
667 
668  scalar_t **tmpEWeights = NULL;
669  if (subsetGraph || removeSelfEdges) {
670  // May change number of edges and, thus, the offsets
671  eOffsets_ = arcp(new offset_t[nLocalVertices_+1],
672  0, nLocalVertices_+1, true);
673  eOffsets_[0] = 0;
674 
675  // Need to copy weights if remove edges
676  if (nWeightsPerEdge_ > 0){
677  eWeights_ = arcp(new input_t[nWeightsPerEdge_], 0,
678  nWeightsPerEdge_, true);
679  // Need to use temporary array because StridedData has const data
680  // so we can't write to it.
681  tmpEWeights = new scalar_t*[nWeightsPerEdge_];
682  for (int w = 0; w < nWeightsPerEdge_; w++)
683  tmpEWeights[w] = new scalar_t[adapterNLocalEdges];
684  }
685  }
686 
687  // If needed, determine the owning ranks and its local index off-proc
688  Teuchos::ArrayRCP<int> edgeRemoteRanks;
689  Teuchos::ArrayRCP<lno_t> edgeRemoteLids;
690  std::unordered_map<gno_t, size_t> edgeRemoteUniqueMap;
691 
692  if (subsetGraph || consecutiveIdsRequired) {
693 
694  // Find global minGID for map construction
695  gno_t myMinGID = std::numeric_limits<gno_t>::max();
696  size_t nVtx = adapterVGids.size();
697  for (size_t i = 0; i < nVtx; i++)
698  if (adapterVGids[i] < myMinGID) myMinGID = adapterVGids[i];
699 
700  gno_t minGID;
701  reduceAll<int, gno_t>(*comm_, Teuchos::REDUCE_MIN, 1,
702  &myMinGID, &minGID);
703 
704  gno_t dummy = Teuchos::OrdinalTraits<gno_t>::invalid();
705  Tpetra::Map<lno_t,gno_t> vtxMap(dummy, adapterVGids(), minGID, comm_);
706 
707  // Need to filter requested edges to make a unique list,
708  // as Tpetra::Map does not return correct info for duplicated entries
709  // (See bug 6412)
710  // The local filter may be more efficient anyway -- fewer communicated
711  // values in the Tpetra directory
712  Teuchos::ArrayRCP<gno_t> edgeRemoteUniqueGids =
713  arcp(new gno_t[adapterNLocalEdges], 0, adapterNLocalEdges, true);
714 
715  size_t nEdgeUnique = 0;
716  for (size_t i = 0; i < adapterNLocalEdges; i++) {
717  if (edgeRemoteUniqueMap.find(adapterEGids[i]) ==
718  edgeRemoteUniqueMap.end()) {
719  edgeRemoteUniqueGids[nEdgeUnique] = adapterEGids[i];
720  edgeRemoteUniqueMap[adapterEGids[i]] = nEdgeUnique;
721  nEdgeUnique++;
722  }
723  }
724 
725  edgeRemoteRanks = arcp(new int[nEdgeUnique], 0, nEdgeUnique, true);
726  edgeRemoteLids = arcp(new lno_t[nEdgeUnique], 0, nEdgeUnique, true);
727  vtxMap.getRemoteIndexList(edgeRemoteUniqueGids(0, nEdgeUnique),
728  edgeRemoteRanks(), edgeRemoteLids());
729  }
730 
731  // Renumber and/or filter the edges and vertices
732  offset_t ecnt = 0;
733  int me = comm_->getRank();
734  for (size_t i = 0; i < nLocalVertices_; i++) {
735 
736  if (consecutiveIdsRequired)
737  vGids_[i] = vtxDist_[me] + i;
738 
739  for (offset_t j = adapterEOffsets[i]; j < adapterEOffsets[i+1]; j++) {
740 
741  if (removeSelfEdges && (adapterVGids[i] == adapterEGids[j]))
742  continue; // Skipping self edge
743 
744  size_t remoteIdx = edgeRemoteUniqueMap[adapterEGids[j]];
745 
746  if (subsetGraph && (edgeRemoteRanks[remoteIdx] == -1))
747  continue; // Skipping edge with neighbor vertex that was not found
748  // in communicator
749 
750  if (consecutiveIdsRequired)
751  // Renumber edge using local number on remote rank plus first
752  // vtx number for remote rank
753  eGids_[ecnt] = edgeRemoteLids[remoteIdx]
754  + vtxDist_[edgeRemoteRanks[remoteIdx]];
755  else
756  eGids_[ecnt] = adapterEGids[j];
757 
758  if (subsetGraph || removeSelfEdges) {
759  // Need to copy weights only if number of edges might change
760  for (int w = 0; w < nWeightsPerEdge_; w++)
761  tmpEWeights[w][ecnt] = adapterEWeights[w][j];
762  }
763 
764  ecnt++;
765  }
766  if (subsetGraph || removeSelfEdges)
767  eOffsets_[i+1] = ecnt;
768  }
769  nLocalEdges_ = ecnt;
770  if (nWeightsPerEdge_ && (subsetGraph || removeSelfEdges)) {
771  for (int w = 0; w < nWeightsPerEdge_; w++) {
772  ArrayRCP<const scalar_t> wgtArray(tmpEWeights[w],
773  0, nLocalEdges_, true);
774  eWeights_[w] = input_t(wgtArray, 1);
775  }
776  delete [] tmpEWeights;
777  }
778  }
779 
780  // Vertex weights
781  nWeightsPerVertex_ = ia->getNumWeightsPerID();
782 
783  if (nWeightsPerVertex_ > 0){
784  input_t *weightInfo = new input_t [nWeightsPerVertex_];
785  env_->localMemoryAssertion(__FILE__, __LINE__, nWeightsPerVertex_,
786  weightInfo);
787 
788  for (int idx=0; idx < nWeightsPerVertex_; idx++){
789  bool useNumNZ = ia->useDegreeAsWeight(idx);
790  if (useNumNZ){
791  scalar_t *wgts = new scalar_t [nLocalVertices_];
792  env_->localMemoryAssertion(__FILE__, __LINE__, nLocalVertices_, wgts);
793  ArrayRCP<const scalar_t> wgtArray = arcp(wgts,
794  0, nLocalVertices_, true);
795  for (size_t i=0; i < nLocalVertices_; i++)
796  wgts[i] = eOffsets_[i+1] - eOffsets_[i];
797  weightInfo[idx] = input_t(wgtArray, 1);
798  }
799  else{
800  const scalar_t *weights=NULL;
801  int stride=0;
802  ia->getWeightsView(weights, stride, idx);
803  ArrayRCP<const scalar_t> wgtArray = arcp(weights, 0,
804  stride*nLocalVertices_,
805  false);
806  weightInfo[idx] = input_t(wgtArray, stride);
807  }
808  }
809 
810  vWeights_ = arcp<input_t>(weightInfo, 0, nWeightsPerVertex_, true);
811  }
812 
813  // Compute global values
814  if (localGraph_) {
815  nGlobalVertices_ = nLocalVertices_;
816  nGlobalEdges_ = nLocalEdges_;
817  }
818  else {
819  reduceAll<int, size_t>(*comm_, Teuchos::REDUCE_SUM, 1,
820  &nLocalVertices_, &nGlobalVertices_);
821  reduceAll<int, size_t>(*comm_, Teuchos::REDUCE_SUM, 1,
822  &nLocalEdges_, &nGlobalEdges_);
823  }
824 
825  env_->memory("After construction of graph model");
826 }
827 
829 
830 template <typename Adapter>
831 template <typename AdapterWithCoords>
832 void GraphModel<Adapter>::shared_GetVertexCoords(const AdapterWithCoords *ia)
833 {
834  // get pointers to vertex coordinates from input adapter
835 
836  vCoordDim_ = ia->getDimension();
837 
838  if (vCoordDim_ > 0){
839  input_t *coordInfo = new input_t [vCoordDim_];
840  env_->localMemoryAssertion(__FILE__, __LINE__, vCoordDim_, coordInfo);
841 
842  for (int dim=0; dim < vCoordDim_; dim++){
843  const scalar_t *coords=NULL;
844  int stride=0;
845  ia->getCoordinatesView(coords, stride, dim);
846  ArrayRCP<const scalar_t> coordArray = arcp(coords, 0,
847  stride*nLocalVertices_,
848  false);
849  coordInfo[dim] = input_t(coordArray, stride);
850  }
851 
852  vCoords_ = arcp<input_t>(coordInfo, 0, vCoordDim_, true);
853  }
854 }
855 
857  template <typename Adapter>
858 void GraphModel<Adapter>::print()
859 {
860 // if (env_->getDebugLevel() < VERBOSE_DETAILED_STATUS)
861 // return;
862 
863  std::ostream *os = env_->getDebugOStream();
864 
865  int me = comm_->getRank();
866 
867  *os << me
868  << " " << (localGraph_ ? "LOCAL GRAPH " : "GLOBAL GRAPH ")
869  << " Nvtx " << nLocalVertices_
870  << " Nedge " << nLocalEdges_
871  << " NVWgt " << nWeightsPerVertex_
872  << " NEWgt " << nWeightsPerEdge_
873  << " CDim " << vCoordDim_
874  << std::endl;
875 
876  for (size_t i = 0; i < nLocalVertices_; i++) {
877  *os << me << " " << i << " GID " << vGids_[i] << ": ";
878  for (offset_t j = eOffsets_[i]; j < eOffsets_[i+1]; j++)
879  *os << eGids_[j] << " " ;
880  *os << std::endl;
881  }
882 
883  if (nWeightsPerVertex_) {
884  for (size_t i = 0; i < nLocalVertices_; i++) {
885  *os << me << " " << i << " VWGTS " << vGids_[i] << ": ";
886  for (int j = 0; j < nWeightsPerVertex_; j++)
887  *os << vWeights_[j][i] << " ";
888  *os << std::endl;
889  }
890  }
891 
892  if (nWeightsPerEdge_) {
893  for (size_t i = 0; i < nLocalVertices_; i++) {
894  *os << me << " " << i << " EWGTS " << vGids_[i] << ": ";
895  for (offset_t j = eOffsets_[i]; j < eOffsets_[i+1]; j++) {
896  *os << eGids_[j] << " (";
897  for (int w = 0; w < nWeightsPerEdge_; w++)
898  *os << eWeights_[w][j] << " ";
899  *os << ") ";
900  }
901  *os << std::endl;
902  }
903  }
904 
905  if (vCoordDim_) {
906  for (size_t i = 0; i < nLocalVertices_; i++) {
907  *os << me << " " << i << " COORDS " << vGids_[i] << ": ";
908  for (int j = 0; j < vCoordDim_; j++)
909  *os << vCoords_[j][i] << " ";
910  *os << std::endl;
911  }
912  }
913  else
914  *os << me << " NO COORDINATES AVAIL " << std::endl;
915 }
916 
917 } // namespace Zoltan2
918 
919 
920 #endif
921 
use columns as graph vertices
size_t getLocalNumEdges() const
Returns the number of edges on this process. In global or subset graphs, includes off-process edges...
void get2ndAdjsViewFromAdjs(const Teuchos::RCP< const MeshAdapter< User > > &ia, const RCP< const Comm< int > > comm, Zoltan2::MeshEntityType sourcetarget, Zoltan2::MeshEntityType through, Teuchos::ArrayRCP< typename MeshAdapter< User >::offset_t > &offsets, Teuchos::ArrayRCP< typename MeshAdapter< User >::gno_t > &adjacencyIds)
size_t getVertexList(ArrayView< const gno_t > &Ids, ArrayView< input_t > &wgts) const
Sets pointers to this process&#39; vertex Ids and their weights.
Time an algorithm (or other entity) as a whole.
IdentifierAdapter defines the interface for identifiers.
ignore invalid neighbors
int getNumWeightsPerVertex() const
Returns the number (0 or greater) of weights per vertex.
size_t getGlobalNumObjects() const
Return the global number of objects.
fast typical checks for valid arguments
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
MatrixAdapter defines the adapter interface for matrices.
Defines the Model interface.
static ArrayRCP< ArrayRCP< zscalar_t > > weights
GraphAdapter defines the interface for graph-based user data.
algorithm requires consecutive ids
Defines the MeshAdapter interface.
MeshAdapter defines the interface for mesh input.
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
model must symmetrize input
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
Defines the IdentifierAdapter interface.
Defines the VectorAdapter interface.
GraphModel(const RCP< const MatrixAdapter< user_t, userCoord_t > > &ia, const RCP< const Environment > &env, const RCP< const Comm< int > > &comm, modelFlag_t &modelFlags)
Constructor.
model must symmetrize input
void getVertexDist(ArrayView< size_t > &vtxdist) const
Return the vtxDist array Array of size comm-&gt;getSize() + 1 Array[n+1] - Array[n] is number of vertice...
typename Zoltan2::InputTraits< ztcrsmatrix_t >::node_t node_t
size_t getGlobalNumVertices() const
Returns the global number vertices.
Defines helper functions for use in the models.
algorithm requires no self edges
int getCoordinateDim() const
Returns the dimension (0 to 3) of vertex coordinates.
size_t getVertexCoords(ArrayView< input_t > &xyz) const
Sets pointers to this process&#39; vertex coordinates, if available. Order of coordinate info matches tha...
use nonzeros as graph vertices
size_t getEdgeList(ArrayView< const gno_t > &edgeIds, ArrayView< const offset_t > &offsets, ArrayView< input_t > &wgts) const
Sets pointers to this process&#39; edge (neighbor) global Ids, including off-process edges.
size_t getGlobalNumEdges() const
Returns the global number edges. For local graphs, the number of global edges is the number of local ...
VectorAdapter defines the interface for vector input.
GraphModel(const RCP< const VectorAdapter< userCoord_t > > &, const RCP< const Environment > &, const RCP< const Comm< int > > &, modelFlag_t &)
The StridedData class manages lists of weights or coordinates.
Traits for application input objects.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
size_t getLocalNumVertices() const
Returns the number vertices on this process.
GraphModel defines the interface required for graph models.
MeshEntityType
Enumerate entity types for meshes: Regions, Faces, Edges, or Vertices.
size_t getLocalNumObjects() const
Return the local number of objects.
Defines the MatrixAdapter interface.
The base class for all model classes.
int getNumWeightsPerEdge() const
Returns the number (0 or greater) of weights per edge.
Defines the GraphAdapter interface.
GraphModel(const RCP< const IdentifierAdapter< user_t > > &ia, const RCP< const Environment > &env, const RCP< const Comm< int > > &comm, modelFlag_t &flags)
const RCP< const Comm< int > > getComm()
Return the communicator used by the model.
model represents graph within only one rank
This file defines the StridedData class.
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition: Metric.cpp:39