50#ifndef _ZOLTAN2_GRAPHMODEL_HPP_
51#define _ZOLTAN2_GRAPHMODEL_HPP_
62#include <unordered_map>
79template <
typename Adapter>
84#ifndef DOXYGEN_SHOULD_SKIP_THIS
85 typedef typename Adapter::scalar_t scalar_t;
86 typedef typename Adapter::gno_t
gno_t;
87 typedef typename Adapter::lno_t
lno_t;
88 typedef typename Adapter::node_t node_t;
89 typedef typename Adapter::user_t
user_t;
90 typedef typename Adapter::userCoord_t userCoord_t;
91 typedef StridedData<lno_t, scalar_t> input_t;
92 typedef typename Adapter::offset_t offset_t;
109 GraphModel(
const RCP<
const MatrixAdapter<user_t,userCoord_t> > &ia,
110 const RCP<const Environment> &env,
const RCP<
const Comm<int> > &comm,
113 GraphModel(
const RCP<
const GraphAdapter<user_t,userCoord_t> > &ia,
114 const RCP<const Environment> &env,
const RCP<
const Comm<int> > &comm,
117 GraphModel(
const RCP<
const MeshAdapter<user_t> > &ia,
118 const RCP<const Environment> &env,
const RCP<
const Comm<int> > &comm,
122 const RCP<const Environment> &,
const RCP<
const Comm<int> > &,
125 throw std::runtime_error(
"cannot build GraphModel from VectorAdapter");
129 const RCP<const Environment> &env,
const RCP<
const Comm<int> > &comm,
132 throw std::runtime_error(
"cannot build GraphModel from IdentifierAdapter");
137 const RCP<const Comm<int> >
getComm() {
return comm_; }
178 ArrayView<const gno_t> &Ids,
179 ArrayView<input_t> &wgts)
const
181 Ids = vGids_.view(0, nLocalVertices_);
182 wgts = vWeights_.view(0, nWeightsPerVertex_);
183 return nLocalVertices_;
194 xyz = vCoords_.view(0, vCoordDim_);
195 return nLocalVertices_;
214 ArrayView<const offset_t> &offsets,
215 ArrayView<input_t> &wgts)
const
217 edgeIds = eGids_.view(0, nLocalEdges_);
218 offsets = eOffsets_.view(0, nLocalVertices_+1);
219 wgts = eWeights_.view(0, nWeightsPerEdge_);
229 vtxdist = vtxDist_();
230 if (vtxDist_.size() == 0) {
231 throw std::runtime_error(
"getVertexDist is available only "
232 "when consecutiveIdsRequired");
246 void shared_constructor(
const RCP<const Adapter>&ia,
modelFlag_t &modelFlags);
248 template <
typename AdapterWithCoords>
253 const RCP<const Environment > env_;
254 const RCP<const Comm<int> > comm_;
262 size_t nLocalVertices_;
263 size_t nGlobalVertices_;
264 ArrayRCP<gno_t> vGids_;
268 int nWeightsPerVertex_;
269 ArrayRCP<input_t> vWeights_;
272 ArrayRCP<input_t> vCoords_;
279 size_t nGlobalEdges_;
280 ArrayRCP<gno_t> eGids_;
281 ArrayRCP<offset_t> eOffsets_;
287 int nWeightsPerEdge_;
288 ArrayRCP<input_t> eWeights_;
293 ArrayRCP<size_t> vtxDist_;
302template <
typename Adapter>
304 const RCP<
const MatrixAdapter<user_t,userCoord_t> > &ia,
305 const RCP<const Environment> &env,
306 const RCP<
const Comm<int> > &comm,
314 nWeightsPerVertex_(0),
334 if (symTranspose || symBipartite || vertexCols || vertexNz){
335 throw std::runtime_error(
"graph build option not yet implemented");
339 gno_t const *vtxIds=NULL;
340 ArrayRCP<const gno_t> nborIds;
341 ArrayRCP<const offset_t> offsets;
344 nLocalVertices_ = ia->getLocalNumIDs();
345 ia->getIDsView(vtxIds);
349 if (ia->CRSViewAvailable()) {
350 ia->getCRSView(offsets, nborIds);
354 throw std::runtime_error(
"Only MatrixAdapter::getCRSView is supported "
361 nLocalEdges_ = offsets[nLocalVertices_];
362 vGids_ = arcp_const_cast<gno_t>(
363 arcp<const gno_t>(vtxIds, 0, nLocalVertices_,
false));
364 eGids_ = arcp_const_cast<gno_t>(nborIds);
365 eOffsets_ = arcp_const_cast<offset_t>(offsets);
368 nWeightsPerEdge_ = 0;
372 shared_constructor(ia, modelFlags);
375 if (ia->coordinatesAvailable()) {
376 typedef VectorAdapter<userCoord_t> adapterWithCoords_t;
377 shared_GetVertexCoords<adapterWithCoords_t>(ia->getCoordinateInput());
385template <
typename Adapter>
387 const RCP<
const GraphAdapter<user_t,userCoord_t> > &ia,
388 const RCP<const Environment> &env,
389 const RCP<
const Comm<int> > &comm,
397 nWeightsPerVertex_(0),
414 env_->localInputAssertion(__FILE__, __LINE__,
415 "GraphModel from GraphAdapter is implemented only for "
416 "Graph Vertices as primary object, not for Graph Edges",
421 gno_t const *vtxIds=NULL, *nborIds=NULL;
422 offset_t
const *offsets=NULL;
424 nLocalVertices_ = ia->getLocalNumVertices();
425 ia->getVertexIDsView(vtxIds);
426 ia->getEdgesView(offsets, nborIds);
431 nLocalEdges_ = offsets[nLocalVertices_];
432 vGids_ = arcp_const_cast<gno_t>(
433 arcp<const gno_t>(vtxIds, 0, nLocalVertices_,
false));
434 eGids_ = arcp_const_cast<gno_t>(
435 arcp<const gno_t>(nborIds, 0, nLocalEdges_,
false));
436 eOffsets_ = arcp_const_cast<offset_t>(
437 arcp<const offset_t>(offsets, 0, nLocalVertices_+1,
false));
440 nWeightsPerEdge_ = ia->getNumWeightsPerEdge();
441 if (nWeightsPerEdge_ > 0){
442 input_t *wgts =
new input_t [nWeightsPerEdge_];
443 eWeights_ = arcp(wgts, 0, nWeightsPerEdge_,
true);
446 for (
int w=0; w < nWeightsPerEdge_; w++){
447 const scalar_t *ewgts=NULL;
450 ia->getEdgeWeightsView(ewgts, stride, w);
452 ArrayRCP<const scalar_t> wgtArray(ewgts, 0, nLocalEdges_,
false);
453 eWeights_[w] = input_t(wgtArray, stride);
457 shared_constructor(ia, modelFlags);
460 if (ia->coordinatesAvailable()) {
461 typedef VectorAdapter<userCoord_t> adapterWithCoords_t;
462 shared_GetVertexCoords<adapterWithCoords_t>(ia->getCoordinateInput());
469template <
typename Adapter>
471 const RCP<
const MeshAdapter<user_t> > &ia,
472 const RCP<const Environment> &env,
473 const RCP<
const Comm<int> > &comm,
481 nWeightsPerVertex_(0),
493 env_->timerStart(MACRO_TIMERS,
"GraphModel constructed from MeshAdapter");
508 gno_t const *vtxIds=NULL;
510 nLocalVertices_ = ia->getLocalNumOf(primaryEType);
511 ia->getIDsViewOf(primaryEType, vtxIds);
515 vGids_ = arcp_const_cast<gno_t>(
516 arcp<const gno_t>(vtxIds, 0, nLocalVertices_,
false));
520 if (!ia->avail2ndAdjs(primaryEType, secondAdjEType)) {
531 nLocalEdges_ = eOffsets_[nLocalVertices_];
538 gno_t const *nborIds=NULL;
539 offset_t
const *offsets=NULL;
541 ia->get2ndAdjsView(primaryEType, secondAdjEType, offsets, nborIds);
544 nLocalEdges_ = offsets[nLocalVertices_];
545 eGids_ = arcp_const_cast<gno_t>(
546 arcp<const gno_t>(nborIds, 0, nLocalEdges_,
false));
547 eOffsets_ = arcp_const_cast<offset_t>(
548 arcp<const offset_t>(offsets, 0, nLocalVertices_+1,
false));
558 if (ia->avail2ndAdjs(primaryEType, secondAdjEType)) {
559 nWeightsPerEdge_ = ia->getNumWeightsPer2ndAdj(primaryEType, secondAdjEType);
560 if (nWeightsPerEdge_ > 0){
561 input_t *wgts =
new input_t [nWeightsPerEdge_];
562 eWeights_ = arcp(wgts, 0, nWeightsPerEdge_,
true);
565 for (
int w=0; w < nWeightsPerEdge_; w++){
566 const scalar_t *ewgts=NULL;
569 ia->get2ndAdjWeightsView(primaryEType, secondAdjEType,
572 ArrayRCP<const scalar_t> wgtArray(ewgts, 0,
573 nLocalEdges_*stride,
false);
574 eWeights_[w] = input_t(wgtArray, stride);
579 shared_constructor(ia, modelFlags);
582 typedef MeshAdapter<user_t> adapterWithCoords_t;
583 shared_GetVertexCoords<adapterWithCoords_t>(&(*ia));
585 env_->timerStop(MACRO_TIMERS,
"GraphModel constructed from MeshAdapter");
591template <
typename Adapter>
593 const RCP<const Adapter> &ia,
603 size_t adapterNLocalEdges = nLocalEdges_;
604 ArrayRCP<gno_t> adapterVGids = vGids_;
605 ArrayRCP<gno_t> adapterEGids = eGids_;
606 ArrayRCP<offset_t> adapterEOffsets = eOffsets_;
607 ArrayRCP<input_t> adapterEWeights = eWeights_;
618 vGids_ = arcp(
new gno_t[nLocalVertices_],
619 0, nLocalVertices_,
true);
620 eGids_ = arcp(
new gno_t[adapterNLocalEdges],
621 0, adapterNLocalEdges,
true);
622 eOffsets_ = arcp(
new offset_t[nLocalVertices_+1],
623 0, nLocalVertices_+1,
true);
625 scalar_t **tmpEWeights = NULL;
626 if (nWeightsPerEdge_ > 0){
627 eWeights_ = arcp(
new input_t[nWeightsPerEdge_], 0,
628 nWeightsPerEdge_,
true);
631 tmpEWeights =
new scalar_t*[nWeightsPerEdge_];
632 for (
int w = 0; w < nWeightsPerEdge_; w++)
633 tmpEWeights[w] =
new scalar_t[adapterNLocalEdges];
637 std::unordered_map<gno_t, lno_t> globalToLocal(nLocalVertices_);
638 for (
size_t i = 0; i < nLocalVertices_; i++)
639 globalToLocal[adapterVGids[i]] = i;
644 for (
size_t i = 0; i < nLocalVertices_; i++) {
645 vGids_[i] =
gno_t(i);
646 for (offset_t j = adapterEOffsets[i]; j < adapterEOffsets[i+1]; j++) {
648 if (removeSelfEdges && (adapterEGids[j] == adapterVGids[i]))
652 typename std::unordered_map<gno_t, lno_t>::iterator localidx;
653 if ((localidx = globalToLocal.find(adapterEGids[j])) !=
654 globalToLocal.end()) {
657 eGids_[ecnt] = localidx->second;
658 for (
int w = 0; w < nWeightsPerEdge_; w++)
659 tmpEWeights[w][ecnt] = adapterEWeights[w][j];
664 eOffsets_[i+1] = ecnt;
666 nLocalEdges_ = eOffsets_[nLocalVertices_];
667 if (nWeightsPerEdge_) {
668 for (
int w = 0; w < nWeightsPerEdge_; w++) {
669 ArrayRCP<const scalar_t> wgtArray(tmpEWeights[w],
670 0, adapterNLocalEdges,
true);
671 eWeights_[w] = input_t(wgtArray, 0);
673 delete [] tmpEWeights;
677 else if (consecutiveIdsRequired || removeSelfEdges || subsetGraph) {
685 if (consecutiveIdsRequired) {
687 vGids_ = arcp(
new gno_t[nLocalVertices_], 0, nLocalVertices_,
true);
690 int np = comm_->getSize();
691 vtxDist_ = arcp(
new size_t[np+1], 0, np+1,
true);
693 Teuchos::gatherAll(*comm_, 1, &nLocalVertices_, np, &vtxDist_[1]);
694 for (
int i = 0; i < np; i++)
695 vtxDist_[i+1] += vtxDist_[i];
701 eGids_ = arcp(
new gno_t[adapterNLocalEdges],
702 0, adapterNLocalEdges,
true);
704 scalar_t **tmpEWeights = NULL;
705 if (subsetGraph || removeSelfEdges) {
707 eOffsets_ = arcp(
new offset_t[nLocalVertices_+1],
708 0, nLocalVertices_+1,
true);
712 if (nWeightsPerEdge_ > 0){
713 eWeights_ = arcp(
new input_t[nWeightsPerEdge_], 0,
714 nWeightsPerEdge_,
true);
717 tmpEWeights =
new scalar_t*[nWeightsPerEdge_];
718 for (
int w = 0; w < nWeightsPerEdge_; w++)
719 tmpEWeights[w] =
new scalar_t[adapterNLocalEdges];
724 Teuchos::ArrayRCP<int> edgeRemoteRanks;
725 Teuchos::ArrayRCP<lno_t> edgeRemoteLids;
726 std::unordered_map<gno_t, size_t> edgeRemoteUniqueMap;
728 if (subsetGraph || consecutiveIdsRequired) {
731 gno_t myMinGID = std::numeric_limits<gno_t>::max();
732 size_t nVtx = adapterVGids.size();
733 for (
size_t i = 0; i < nVtx; i++)
734 if (adapterVGids[i] < myMinGID) myMinGID = adapterVGids[i];
737 reduceAll<int, gno_t>(*comm_, Teuchos::REDUCE_MIN, 1,
740 gno_t dummy = Teuchos::OrdinalTraits<gno_t>::invalid();
741 Tpetra::Map<lno_t,gno_t> vtxMap(dummy, adapterVGids(), minGID, comm_);
748 Teuchos::ArrayRCP<gno_t> edgeRemoteUniqueGids =
749 arcp(
new gno_t[adapterNLocalEdges], 0, adapterNLocalEdges,
true);
751 size_t nEdgeUnique = 0;
752 for (
size_t i = 0; i < adapterNLocalEdges; i++) {
753 if (edgeRemoteUniqueMap.find(adapterEGids[i]) ==
754 edgeRemoteUniqueMap.end()) {
755 edgeRemoteUniqueGids[nEdgeUnique] = adapterEGids[i];
756 edgeRemoteUniqueMap[adapterEGids[i]] = nEdgeUnique;
761 edgeRemoteRanks = arcp(
new int[nEdgeUnique], 0, nEdgeUnique,
true);
762 edgeRemoteLids = arcp(
new lno_t[nEdgeUnique], 0, nEdgeUnique,
true);
763 vtxMap.getRemoteIndexList(edgeRemoteUniqueGids(0, nEdgeUnique),
764 edgeRemoteRanks(), edgeRemoteLids());
769 int me = comm_->getRank();
770 for (
size_t i = 0; i < nLocalVertices_; i++) {
772 if (consecutiveIdsRequired)
773 vGids_[i] = vtxDist_[me] + i;
775 for (offset_t j = adapterEOffsets[i]; j < adapterEOffsets[i+1]; j++) {
777 if (removeSelfEdges && (adapterVGids[i] == adapterEGids[j]))
780 size_t remoteIdx = edgeRemoteUniqueMap[adapterEGids[j]];
782 if (subsetGraph && (edgeRemoteRanks[remoteIdx] == -1))
786 if (consecutiveIdsRequired)
789 eGids_[ecnt] = edgeRemoteLids[remoteIdx]
790 + vtxDist_[edgeRemoteRanks[remoteIdx]];
792 eGids_[ecnt] = adapterEGids[j];
794 if (subsetGraph || removeSelfEdges) {
796 for (
int w = 0; w < nWeightsPerEdge_; w++)
797 tmpEWeights[w][ecnt] = adapterEWeights[w][j];
802 if (subsetGraph || removeSelfEdges)
803 eOffsets_[i+1] = ecnt;
806 if (nWeightsPerEdge_ && (subsetGraph || removeSelfEdges)) {
807 for (
int w = 0; w < nWeightsPerEdge_; w++) {
808 ArrayRCP<const scalar_t> wgtArray(tmpEWeights[w],
809 0, nLocalEdges_,
true);
810 eWeights_[w] = input_t(wgtArray, 1);
812 delete [] tmpEWeights;
817 nWeightsPerVertex_ = ia->getNumWeightsPerID();
819 if (nWeightsPerVertex_ > 0){
820 input_t *weightInfo =
new input_t [nWeightsPerVertex_];
821 env_->localMemoryAssertion(__FILE__, __LINE__, nWeightsPerVertex_,
824 for (
int idx=0; idx < nWeightsPerVertex_; idx++){
825 bool useNumNZ = ia->useDegreeAsWeight(idx);
827 scalar_t *wgts =
new scalar_t [nLocalVertices_];
828 env_->localMemoryAssertion(__FILE__, __LINE__, nLocalVertices_, wgts);
829 ArrayRCP<const scalar_t> wgtArray = arcp(wgts,
830 0, nLocalVertices_,
true);
831 for (
size_t i=0; i < nLocalVertices_; i++)
832 wgts[i] = eOffsets_[i+1] - eOffsets_[i];
833 weightInfo[idx] = input_t(wgtArray, 1);
838 ia->getWeightsView(
weights, stride, idx);
839 ArrayRCP<const scalar_t> wgtArray = arcp(
weights, 0,
840 stride*nLocalVertices_,
842 weightInfo[idx] = input_t(wgtArray, stride);
846 vWeights_ = arcp<input_t>(weightInfo, 0, nWeightsPerVertex_,
true);
851 nGlobalVertices_ = nLocalVertices_;
852 nGlobalEdges_ = nLocalEdges_;
855 reduceAll<int, size_t>(*comm_, Teuchos::REDUCE_SUM, 1,
856 &nLocalVertices_, &nGlobalVertices_);
857 reduceAll<int, size_t>(*comm_, Teuchos::REDUCE_SUM, 1,
858 &nLocalEdges_, &nGlobalEdges_);
861 env_->memory(
"After construction of graph model");
866template <
typename Adapter>
867template <
typename AdapterWithCoords>
868void GraphModel<Adapter>::shared_GetVertexCoords(
const AdapterWithCoords *ia)
872 vCoordDim_ = ia->getDimension();
875 input_t *coordInfo =
new input_t [vCoordDim_];
876 env_->localMemoryAssertion(__FILE__, __LINE__, vCoordDim_, coordInfo);
878 for (
int dim=0; dim < vCoordDim_; dim++){
879 const scalar_t *coords=NULL;
881 ia->getCoordinatesView(coords, stride, dim);
882 ArrayRCP<const scalar_t> coordArray = arcp(coords, 0,
883 stride*nLocalVertices_,
885 coordInfo[dim] = input_t(coordArray, stride);
888 vCoords_ = arcp<input_t>(coordInfo, 0, vCoordDim_,
true);
893 template <
typename Adapter>
894void GraphModel<Adapter>::print()
899 std::ostream *os = env_->getDebugOStream();
901 int me = comm_->getRank();
904 <<
" " << (localGraph_ ?
"LOCAL GRAPH " :
"GLOBAL GRAPH ")
905 <<
" Nvtx " << nLocalVertices_
906 <<
" Nedge " << nLocalEdges_
907 <<
" NVWgt " << nWeightsPerVertex_
908 <<
" NEWgt " << nWeightsPerEdge_
909 <<
" CDim " << vCoordDim_
912 for (
size_t i = 0; i < nLocalVertices_; i++) {
913 *os << me <<
" " << i <<
" GID " << vGids_[i] <<
": ";
914 for (offset_t j = eOffsets_[i]; j < eOffsets_[i+1]; j++)
915 *os << eGids_[j] <<
" " ;
919 if (nWeightsPerVertex_) {
920 for (
size_t i = 0; i < nLocalVertices_; i++) {
921 *os << me <<
" " << i <<
" VWGTS " << vGids_[i] <<
": ";
922 for (
int j = 0; j < nWeightsPerVertex_; j++)
923 *os << vWeights_[j][i] <<
" ";
928 if (nWeightsPerEdge_) {
929 for (
size_t i = 0; i < nLocalVertices_; i++) {
930 *os << me <<
" " << i <<
" EWGTS " << vGids_[i] <<
": ";
931 for (offset_t j = eOffsets_[i]; j < eOffsets_[i+1]; j++) {
932 *os << eGids_[j] <<
" (";
933 for (
int w = 0; w < nWeightsPerEdge_; w++)
934 *os << eWeights_[w][j] <<
" ";
942 for (
size_t i = 0; i < nLocalVertices_; i++) {
943 *os << me <<
" " << i <<
" COORDS " << vGids_[i] <<
": ";
944 for (
int j = 0; j < vCoordDim_; j++)
945 *os << vCoords_[j][i] <<
" ";
950 *os << me <<
" NO COORDINATES AVAIL " << std::endl;
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
Defines the GraphAdapter interface.
Defines the IdentifierAdapter interface.
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.
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.
The base class for all model classes.
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
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