14 #ifndef _ZOLTAN2_GRAPHMODEL_HPP_
15 #define _ZOLTAN2_GRAPHMODEL_HPP_
26 #include <unordered_map>
43 template <
typename Adapter>
48 #ifndef DOXYGEN_SHOULD_SKIP_THIS
49 typedef typename Adapter::scalar_t scalar_t;
54 typedef typename Adapter::userCoord_t userCoord_t;
56 typedef typename Adapter::offset_t offset_t;
74 const RCP<const Environment> &env,
const RCP<
const Comm<int> > &comm,
78 const RCP<const Environment> &env,
const RCP<
const Comm<int> > &comm,
82 const RCP<const Environment> &env,
const RCP<
const Comm<int> > &comm,
86 const RCP<const Environment> &,
const RCP<
const Comm<int> > &,
89 throw std::runtime_error(
"cannot build GraphModel from VectorAdapter");
93 const RCP<const Environment> &env,
const RCP<
const Comm<int> > &comm,
96 throw std::runtime_error(
"cannot build GraphModel from IdentifierAdapter");
101 const RCP<const Comm<int> >
getComm() {
return comm_; }
142 ArrayView<const gno_t> &Ids,
143 ArrayView<input_t> &wgts)
const
145 Ids = vGids_.view(0, nLocalVertices_);
146 wgts = vWeights_.view(0, nWeightsPerVertex_);
147 return nLocalVertices_;
158 xyz = vCoords_.view(0, vCoordDim_);
159 return nLocalVertices_;
178 ArrayView<const offset_t> &offsets,
179 ArrayView<input_t> &wgts)
const
181 edgeIds = eGids_.view(0, nLocalEdges_);
182 offsets = eOffsets_.view(0, nLocalVertices_+1);
183 wgts = eWeights_.view(0, nWeightsPerEdge_);
193 vtxdist = vtxDist_();
194 if (vtxDist_.size() == 0) {
195 throw std::runtime_error(
"getVertexDist is available only "
196 "when consecutiveIdsRequired");
210 void shared_constructor(
const RCP<const Adapter>&ia,
modelFlag_t &modelFlags);
212 template <
typename AdapterWithCoords>
217 const RCP<const Environment > env_;
218 const RCP<const Comm<int> > comm_;
226 size_t nLocalVertices_;
227 size_t nGlobalVertices_;
228 ArrayRCP<gno_t> vGids_;
232 int nWeightsPerVertex_;
233 ArrayRCP<input_t> vWeights_;
236 ArrayRCP<input_t> vCoords_;
243 size_t nGlobalEdges_;
244 ArrayRCP<gno_t> eGids_;
245 ArrayRCP<offset_t> eOffsets_;
251 int nWeightsPerEdge_;
252 ArrayRCP<input_t> eWeights_;
257 ArrayRCP<size_t> vtxDist_;
266 template <
typename Adapter>
269 const RCP<const Environment> &env,
270 const RCP<
const Comm<int> > &comm,
278 nWeightsPerVertex_(0),
298 if (symTranspose || symBipartite || vertexCols || vertexNz){
299 throw std::runtime_error(
"graph build option not yet implemented");
303 gno_t const *vtxIds=NULL;
304 ArrayRCP<const gno_t> nborIds;
305 ArrayRCP<const offset_t> offsets;
308 nLocalVertices_ = ia->getLocalNumIDs();
309 ia->getIDsView(vtxIds);
313 if (ia->CRSViewAvailable()) {
314 ia->getCRSView(offsets, nborIds);
318 throw std::runtime_error(
"Only MatrixAdapter::getCRSView is supported "
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);
332 nWeightsPerEdge_ = 0;
336 shared_constructor(ia, modelFlags);
339 if (ia->coordinatesAvailable()) {
341 shared_GetVertexCoords<adapterWithCoords_t>(ia->getCoordinateInput());
349 template <
typename Adapter>
352 const RCP<const Environment> &env,
353 const RCP<
const Comm<int> > &comm,
361 nWeightsPerVertex_(0),
378 env_->localInputAssertion(__FILE__, __LINE__,
379 "GraphModel from GraphAdapter is implemented only for "
380 "Graph Vertices as primary object, not for Graph Edges",
385 gno_t const *vtxIds=NULL, *nborIds=NULL;
386 offset_t
const *offsets=NULL;
388 nLocalVertices_ = ia->getLocalNumVertices();
389 ia->getVertexIDsView(vtxIds);
390 ia->getEdgesView(offsets, nborIds);
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));
404 nWeightsPerEdge_ = ia->getNumWeightsPerEdge();
405 if (nWeightsPerEdge_ > 0){
406 input_t *wgts =
new input_t [nWeightsPerEdge_];
407 eWeights_ = arcp(wgts, 0, nWeightsPerEdge_,
true);
410 for (
int w=0; w < nWeightsPerEdge_; w++){
411 const scalar_t *ewgts=NULL;
414 ia->getEdgeWeightsView(ewgts, stride, w);
416 ArrayRCP<const scalar_t> wgtArray(ewgts, 0, nLocalEdges_,
false);
417 eWeights_[w] = input_t(wgtArray, stride);
421 shared_constructor(ia, modelFlags);
424 if (ia->coordinatesAvailable()) {
426 shared_GetVertexCoords<adapterWithCoords_t>(ia->getCoordinateInput());
433 template <
typename Adapter>
436 const RCP<const Environment> &env,
437 const RCP<
const Comm<int> > &comm,
445 nWeightsPerVertex_(0),
457 env_->timerStart(
MACRO_TIMERS,
"GraphModel constructed from MeshAdapter");
472 gno_t const *vtxIds=NULL;
474 nLocalVertices_ = ia->getLocalNumOf(primaryEType);
475 ia->getIDsViewOf(primaryEType, vtxIds);
479 vGids_ = arcp_const_cast<
gno_t>(
480 arcp<const gno_t>(vtxIds, 0, nLocalVertices_,
false));
484 if (!ia->avail2ndAdjs(primaryEType, secondAdjEType)) {
495 nLocalEdges_ = eOffsets_[nLocalVertices_];
502 gno_t
const *nborIds=NULL;
503 offset_t
const *offsets=NULL;
505 ia->get2ndAdjsView(primaryEType, secondAdjEType, offsets, nborIds);
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));
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);
529 for (
int w=0; w < nWeightsPerEdge_; w++){
530 const scalar_t *ewgts=NULL;
533 ia->get2ndAdjWeightsView(primaryEType, secondAdjEType,
536 ArrayRCP<const scalar_t> wgtArray(ewgts, 0,
537 nLocalEdges_*stride,
false);
538 eWeights_[w] = input_t(wgtArray, stride);
543 shared_constructor(ia, modelFlags);
547 shared_GetVertexCoords<adapterWithCoords_t>(&(*ia));
549 env_->timerStop(
MACRO_TIMERS,
"GraphModel constructed from MeshAdapter");
555 template <
typename Adapter>
557 const RCP<const Adapter> &ia,
567 size_t adapterNLocalEdges = nLocalEdges_;
568 ArrayRCP<gno_t> adapterVGids = vGids_;
569 ArrayRCP<gno_t> adapterEGids = eGids_;
570 ArrayRCP<offset_t> adapterEOffsets = eOffsets_;
571 ArrayRCP<input_t> adapterEWeights = eWeights_;
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);
589 scalar_t **tmpEWeights = NULL;
590 if (nWeightsPerEdge_ > 0){
591 eWeights_ = arcp(
new input_t[nWeightsPerEdge_], 0,
592 nWeightsPerEdge_,
true);
595 tmpEWeights =
new scalar_t*[nWeightsPerEdge_];
596 for (
int w = 0; w < nWeightsPerEdge_; w++)
597 tmpEWeights[w] =
new scalar_t[adapterNLocalEdges];
601 std::unordered_map<gno_t, lno_t> globalToLocal(nLocalVertices_);
602 for (
size_t i = 0; i < nLocalVertices_; i++)
603 globalToLocal[adapterVGids[i]] = i;
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++) {
612 if (removeSelfEdges && (adapterEGids[j] == adapterVGids[i]))
616 typename std::unordered_map<gno_t, lno_t>::iterator localidx;
617 if ((localidx = globalToLocal.find(adapterEGids[j])) !=
618 globalToLocal.end()) {
621 eGids_[ecnt] = localidx->second;
622 for (
int w = 0; w < nWeightsPerEdge_; w++)
623 tmpEWeights[w][ecnt] = adapterEWeights[w][j];
628 eOffsets_[i+1] = ecnt;
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);
637 delete [] tmpEWeights;
641 else if (consecutiveIdsRequired || removeSelfEdges || subsetGraph) {
649 if (consecutiveIdsRequired) {
651 vGids_ = arcp(
new gno_t[nLocalVertices_], 0, nLocalVertices_,
true);
654 int np = comm_->getSize();
655 vtxDist_ = arcp(
new size_t[np+1], 0, np+1,
true);
657 Teuchos::gatherAll(*comm_, 1, &nLocalVertices_, np, &vtxDist_[1]);
658 for (
int i = 0; i < np; i++)
659 vtxDist_[i+1] += vtxDist_[i];
665 eGids_ = arcp(
new gno_t[adapterNLocalEdges],
666 0, adapterNLocalEdges,
true);
668 scalar_t **tmpEWeights = NULL;
669 if (subsetGraph || removeSelfEdges) {
671 eOffsets_ = arcp(
new offset_t[nLocalVertices_+1],
672 0, nLocalVertices_+1,
true);
676 if (nWeightsPerEdge_ > 0){
677 eWeights_ = arcp(
new input_t[nWeightsPerEdge_], 0,
678 nWeightsPerEdge_,
true);
681 tmpEWeights =
new scalar_t*[nWeightsPerEdge_];
682 for (
int w = 0; w < nWeightsPerEdge_; w++)
683 tmpEWeights[w] =
new scalar_t[adapterNLocalEdges];
688 Teuchos::ArrayRCP<int> edgeRemoteRanks;
689 Teuchos::ArrayRCP<lno_t> edgeRemoteLids;
690 std::unordered_map<gno_t, size_t> edgeRemoteUniqueMap;
692 if (subsetGraph || consecutiveIdsRequired) {
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];
701 reduceAll<int, gno_t>(*comm_, Teuchos::REDUCE_MIN, 1,
704 gno_t dummy = Teuchos::OrdinalTraits<gno_t>::invalid();
705 Tpetra::Map<lno_t,gno_t> vtxMap(dummy, adapterVGids(), minGID, comm_);
712 Teuchos::ArrayRCP<gno_t> edgeRemoteUniqueGids =
713 arcp(
new gno_t[adapterNLocalEdges], 0, adapterNLocalEdges,
true);
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;
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());
733 int me = comm_->getRank();
734 for (
size_t i = 0; i < nLocalVertices_; i++) {
736 if (consecutiveIdsRequired)
737 vGids_[i] = vtxDist_[me] + i;
739 for (offset_t j = adapterEOffsets[i]; j < adapterEOffsets[i+1]; j++) {
741 if (removeSelfEdges && (adapterVGids[i] == adapterEGids[j]))
744 size_t remoteIdx = edgeRemoteUniqueMap[adapterEGids[j]];
746 if (subsetGraph && (edgeRemoteRanks[remoteIdx] == -1))
750 if (consecutiveIdsRequired)
753 eGids_[ecnt] = edgeRemoteLids[remoteIdx]
754 + vtxDist_[edgeRemoteRanks[remoteIdx]];
756 eGids_[ecnt] = adapterEGids[j];
758 if (subsetGraph || removeSelfEdges) {
760 for (
int w = 0; w < nWeightsPerEdge_; w++)
761 tmpEWeights[w][ecnt] = adapterEWeights[w][j];
766 if (subsetGraph || removeSelfEdges)
767 eOffsets_[i+1] = 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);
776 delete [] tmpEWeights;
781 nWeightsPerVertex_ = ia->getNumWeightsPerID();
783 if (nWeightsPerVertex_ > 0){
784 input_t *weightInfo =
new input_t [nWeightsPerVertex_];
785 env_->localMemoryAssertion(__FILE__, __LINE__, nWeightsPerVertex_,
788 for (
int idx=0; idx < nWeightsPerVertex_; idx++){
789 bool useNumNZ = ia->useDegreeAsWeight(idx);
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);
802 ia->getWeightsView(weights, stride, idx);
803 ArrayRCP<const scalar_t> wgtArray = arcp(weights, 0,
804 stride*nLocalVertices_,
806 weightInfo[idx] = input_t(wgtArray, stride);
810 vWeights_ = arcp<input_t>(weightInfo, 0, nWeightsPerVertex_,
true);
815 nGlobalVertices_ = nLocalVertices_;
816 nGlobalEdges_ = nLocalEdges_;
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_);
825 env_->memory(
"After construction of graph model");
830 template <
typename Adapter>
831 template <
typename AdapterWithCoords>
832 void GraphModel<Adapter>::shared_GetVertexCoords(
const AdapterWithCoords *ia)
836 vCoordDim_ = ia->getDimension();
839 input_t *coordInfo =
new input_t [vCoordDim_];
840 env_->localMemoryAssertion(__FILE__, __LINE__, vCoordDim_, coordInfo);
842 for (
int dim=0; dim < vCoordDim_; dim++){
843 const scalar_t *coords=NULL;
845 ia->getCoordinatesView(coords, stride, dim);
846 ArrayRCP<const scalar_t> coordArray = arcp(coords, 0,
847 stride*nLocalVertices_,
849 coordInfo[dim] = input_t(coordArray, stride);
852 vCoords_ = arcp<input_t>(coordInfo, 0, vCoordDim_,
true);
857 template <
typename Adapter>
858 void GraphModel<Adapter>::print()
863 std::ostream *os = env_->getDebugOStream();
865 int me = comm_->getRank();
868 <<
" " << (localGraph_ ?
"LOCAL GRAPH " :
"GLOBAL GRAPH ")
869 <<
" Nvtx " << nLocalVertices_
870 <<
" Nedge " << nLocalEdges_
871 <<
" NVWgt " << nWeightsPerVertex_
872 <<
" NEWgt " << nWeightsPerEdge_
873 <<
" CDim " << vCoordDim_
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] <<
" " ;
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] <<
" ";
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] <<
" ";
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] <<
" ";
914 *os << me <<
" NO COORDINATES AVAIL " << std::endl;
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' vertex Ids and their weights.
Time an algorithm (or other entity) as a whole.
IdentifierAdapter defines the interface for identifiers.
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.
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
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->getSize() + 1 Array[n+1] - Array[n] is number of vertice...
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' 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' 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.
map_t::local_ordinal_type lno_t
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