Zoltan2
Loading...
Searching...
No Matches
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>
26#include <unordered_map>
27
28namespace Zoltan2 {
29
31
43template <typename Adapter>
44class GraphModel : public Model<Adapter>
45{
46public:
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
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
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
208private:
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
266template <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
349template <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
433template <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
555template <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
830template <typename Adapter>
831template <typename AdapterWithCoords>
832void 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>
858void 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
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition Metric.cpp:39
typename Zoltan2::InputTraits< ztcrsmatrix_t >::node_t node_t
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
Defines the GraphAdapter interface.
Defines the IdentifierAdapter interface.
Traits for application input objects.
Defines the MatrixAdapter interface.
Defines the MeshAdapter interface.
Defines helper functions for use in the models.
Defines the Model interface.
This file defines the StridedData class.
Defines the VectorAdapter interface.
GraphAdapter defines the interface for graph-based user data.
GraphModel defines the interface required for graph models.
GraphModel(const RCP< const VectorAdapter< userCoord_t > > &, const RCP< const Environment > &, const RCP< const Comm< int > > &, modelFlag_t &)
size_t getLocalNumObjects() const
Return the local number of objects.
int getCoordinateDim() const
Returns the dimension (0 to 3) of vertex coordinates.
const RCP< const Comm< int > > getComm()
Return the communicator used by the model.
GraphModel(const RCP< const IdentifierAdapter< user_t > > &ia, const RCP< const Environment > &env, const RCP< const Comm< int > > &comm, modelFlag_t &flags)
size_t getGlobalNumVertices() const
Returns the global number vertices.
void getVertexDist(ArrayView< size_t > &vtxdist) const
Return the vtxDist array Array of size comm->getSize() + 1 Array[n+1] - Array[n] is number of vertice...
size_t getLocalNumEdges() const
Returns the number of edges on this process. In global or subset graphs, includes off-process edges.
int getNumWeightsPerVertex() const
Returns the number (0 or greater) of weights per vertex.
size_t getEdgeList(ArrayView< const gno_t > &edgeIds, ArrayView< const offset_t > &offsets, ArrayView< input_t > &wgts) const
Sets pointers to this process' edge (neighbor) global Ids, including off-process edges.
size_t getVertexCoords(ArrayView< input_t > &xyz) const
Sets pointers to this process' vertex coordinates, if available. Order of coordinate info matches tha...
size_t getGlobalNumObjects() const
Return the global number of objects.
size_t getLocalNumVertices() const
Returns the number vertices on this process.
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.
size_t getVertexList(ArrayView< const gno_t > &Ids, ArrayView< input_t > &wgts) const
Sets pointers to this process' vertex Ids and their weights.
size_t getGlobalNumEdges() const
Returns the global number edges. For local graphs, the number of global edges is the number of local ...
int getNumWeightsPerEdge() const
Returns the number (0 or greater) of weights per edge.
IdentifierAdapter defines the interface for identifiers.
MatrixAdapter defines the adapter interface for matrices.
MeshAdapter defines the interface for mesh input.
The base class for all model classes.
The StridedData class manages lists of weights or coordinates.
VectorAdapter defines the interface for vector input.
map_t::local_ordinal_type lno_t
map_t::global_ordinal_type gno_t
Created by mbenlioglu on Aug 31, 2020.
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
@ MACRO_TIMERS
Time an algorithm (or other entity) as a whole.
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)
@ BASIC_ASSERTION
fast typical checks for valid arguments
MeshEntityType
Enumerate entity types for meshes: Regions, Faces, Edges, or Vertices.
@ BUILD_SUBSET_GRAPH
ignore invalid neighbors
@ GENERATE_CONSECUTIVE_IDS
algorithm requires consecutive ids
@ SYMMETRIZE_INPUT_TRANSPOSE
model must symmetrize input
@ SYMMETRIZE_INPUT_BIPARTITE
model must symmetrize input
@ REMOVE_SELF_EDGES
algorithm requires no self edges
@ VERTICES_ARE_MATRIX_COLUMNS
use columns as graph vertices
@ VERTICES_ARE_MATRIX_NONZEROS
use nonzeros as graph vertices
@ BUILD_LOCAL_GRAPH
model represents graph within only one rank
static ArrayRCP< ArrayRCP< zscalar_t > > weights