/*! Prints the global minimum and all paired extrema whose persistence is greater or equal to threshold. By default, all pairs are printed. Supports Matlab indexing. @param[in] threshold Threshold value for pair persistence. @param[in] matlabIndexing Use Matlab indexing for printing. */ void PrintResults(const float threshold = 0.0, const bool matlabIndexing = false) const { if (threshold < 0) { std::cout << "Error. Threshold value must be greater than or equal to 0" << std::endl; } if (threshold==0 && !matlabIndexing) { PrintPairs(PairedExtrema); } else { std::vector<TPairedExtrema> pairs; GetPairedExtrema(pairs, threshold, matlabIndexing); PrintPairs(pairs); } std::cout << "Global minimum value: " << GetGlobalMinimumValue() << " index: " << GetGlobalMinimumIndex(matlabIndexing) << std::endl; }
/************************************************************************* * This function projects a partition. **************************************************************************/ void Moc_ProjectPartition(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace) { int i, nvtxs, nnbrs = -1, firstvtx, cfirstvtx; idxtype *match, *cmap, *where, *cwhere; idxtype *peind, *slens = NULL, *rlens = NULL; KeyValueType *rcand, *scand = NULL; GraphType *cgraph; IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); cgraph = graph->coarser; cwhere = cgraph->where; cfirstvtx = cgraph->vtxdist[ctrl->mype]; nvtxs = graph->nvtxs; match = graph->match; cmap = graph->cmap; where = graph->where = idxmalloc(nvtxs+graph->nrecv, "ProjectPartition: graph->where"); firstvtx = graph->vtxdist[ctrl->mype]; if (graph->match_type == MATCH_GLOBAL) { /* Only if global matching is on */ /*------------------------------------------------------------ / Start the transmission of the remote where information /------------------------------------------------------------*/ scand = wspace->pairs; nnbrs = graph->nnbrs; peind = graph->peind; slens = graph->slens; rlens = graph->rlens; rcand = graph->rcand; /* Issue the receives first */ for (i=0; i<nnbrs; i++) { if (slens[i+1]-slens[i] > 0) /* Issue a receive only if you are getting something */ MPI_Irecv((void *)(scand+slens[i]), 2*(slens[i+1]-slens[i]), IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->rreq+i); } #ifdef DEBUG_PROJECT PrintPairs(ctrl, rlens[nnbrs], rcand, "rcand"); #endif /* Put the where[rcand[].key] into the val field */ for (i=0; i<rlens[nnbrs]; i++) { ASSERT(ctrl, rcand[i].val >= 0 && rcand[i].val < cgraph->nvtxs); rcand[i].val = cwhere[rcand[i].val]; } #ifdef DEBUG_PROJECT PrintPairs(ctrl, rlens[nnbrs], rcand, "rcand"); PrintVector(ctrl, nvtxs, firstvtx, cmap, "cmap"); #endif /* Issue the sends next */ for (i=0; i<nnbrs; i++) { if (rlens[i+1]-rlens[i] > 0) /* Issue a send only if you are sending something */ MPI_Isend((void *)(rcand+rlens[i]), 2*(rlens[i+1]-rlens[i]), IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i); } } /*------------------------------------------------------------ / Project local vertices first /------------------------------------------------------------*/ for (i=0; i<nvtxs; i++) { if (match[i] >= KEEP_BIT) { ASSERT(ctrl, cmap[i]-cfirstvtx>=0 && cmap[i]-cfirstvtx<cgraph->nvtxs); where[i] = cwhere[cmap[i]-cfirstvtx]; } } if (graph->match_type == MATCH_GLOBAL) { /* Only if global matching is on */ /*------------------------------------------------------------ / Wait for the nonblocking operations to finish /------------------------------------------------------------*/ for (i=0; i<nnbrs; i++) { if (rlens[i+1]-rlens[i] > 0) MPI_Wait(ctrl->sreq+i, &ctrl->status); } for (i=0; i<nnbrs; i++) { if (slens[i+1]-slens[i] > 0) MPI_Wait(ctrl->rreq+i, &ctrl->status); } #ifdef DEBUG_PROJECT PrintPairs(ctrl, slens[nnbrs], scand, "scand"); #endif /*------------------------------------------------------------ / Project received vertices now /------------------------------------------------------------*/ for (i=0; i<slens[nnbrs]; i++) { ASSERTP(ctrl, scand[i].key-firstvtx>=0 && scand[i].key-firstvtx<graph->nvtxs, (ctrl, "%d %d %d\n", scand[i].key, firstvtx, graph->nvtxs)); where[scand[i].key-firstvtx] = scand[i].val; } } FreeGraph(graph->coarser); graph->coarser = NULL; IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); }
void CreateCoarseGraph_Global(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs) { idx_t h, i, j, k, l, ii, jj, ll, nnbrs, nvtxs, nedges, ncon; idx_t firstvtx, lastvtx, cfirstvtx, clastvtx, otherlastvtx; idx_t npes=ctrl->npes, mype=ctrl->mype; idx_t cnedges, nsend, nrecv, nkeepsize, nrecvsize, nsendsize, v, u; idx_t *xadj, *adjncy, *adjwgt, *vwgt, *vsize, *vtxdist, *home, *where; idx_t *match, *cmap; idx_t *cxadj, *cadjncy, *cadjwgt, *cvwgt, *cvsize = NULL, *chome = NULL, *cwhere = NULL, *cvtxdist; idx_t *rsizes, *ssizes, *rlens, *slens, *rgraph, *sgraph, *perm; idx_t *peind, *recvptr, *recvind; real_t *nvwgt, *cnvwgt; graph_t *cgraph; ikv_t *scand, *rcand; idx_t htable[LHTSIZE], htableidx[LHTSIZE]; WCOREPUSH; nvtxs = graph->nvtxs; ncon = graph->ncon; xadj = graph->xadj; vwgt = graph->vwgt; vsize = graph->vsize; nvwgt = graph->nvwgt; home = graph->home; where = graph->where; adjncy = graph->adjncy; adjwgt = graph->adjwgt; match = graph->match; vtxdist = graph->vtxdist; firstvtx = vtxdist[mype]; lastvtx = vtxdist[mype+1]; cmap = graph->cmap = ismalloc(nvtxs+graph->nrecv, -1, "Global_CreateCoarseGraph: cmap"); nnbrs = graph->nnbrs; peind = graph->peind; recvind = graph->recvind; recvptr = graph->recvptr; /* Initialize the coarser graph */ cgraph = CreateGraph(); cgraph->nvtxs = cnvtxs; cgraph->ncon = ncon; cgraph->level = graph->level+1; cgraph->finer = graph; graph->coarser = cgraph; /************************************************************* * Obtain the vtxdist of the coarser graph **************************************************************/ cvtxdist = cgraph->vtxdist = imalloc(npes+1, "Global_CreateCoarseGraph: cvtxdist"); cvtxdist[npes] = cnvtxs; /* Use last position in the cvtxdist as a temp buffer */ gkMPI_Allgather((void *)(cvtxdist+npes), 1, IDX_T, (void *)cvtxdist, 1, IDX_T, ctrl->comm); MAKECSR(i, npes, cvtxdist); cgraph->gnvtxs = cvtxdist[npes]; #ifdef DEBUG_CONTRACT PrintVector(ctrl, npes+1, 0, cvtxdist, "cvtxdist"); #endif /************************************************************* * Construct the cmap vector **************************************************************/ cfirstvtx = cvtxdist[mype]; clastvtx = cvtxdist[mype+1]; /* Create the cmap of what you know so far locally. */ for (cnvtxs=0, i=0; i<nvtxs; i++) { if (match[i] >= KEEP_BIT) { k = match[i] - KEEP_BIT; if (k>=firstvtx && k<firstvtx+i) continue; /* Both (i,k) are local and i has been matched via the (k,i) side */ cmap[i] = cfirstvtx + cnvtxs++; if (k != firstvtx+i && (k>=firstvtx && k<lastvtx)) { /* I'm matched locally */ cmap[k-firstvtx] = cmap[i]; match[k-firstvtx] += KEEP_BIT; /* Add the KEEP_BIT to simplify coding */ } } } PASSERT(ctrl, cnvtxs == clastvtx-cfirstvtx); CommInterfaceData(ctrl, graph, cmap, cmap+nvtxs); /* Update the cmap of the locally stored vertices that will go away. * The remote processor assigned cmap for them */ for (i=0; i<nvtxs; i++) { if (match[i] < KEEP_BIT) { /* Only vertices that go away satisfy this*/ cmap[i] = cmap[nvtxs+BSearch(graph->nrecv, recvind, match[i])]; } } CommInterfaceData(ctrl, graph, cmap, cmap+nvtxs); #ifndef NDEBUG for (i=0; i<nvtxs+graph->nrecv; i++) { if (cmap[i] == -1) errexit("cmap[%"PRIDX"] == -1\n", i); } #endif #ifdef DEBUG_CONTRACT PrintVector(ctrl, nvtxs, firstvtx, cmap, "Cmap"); #endif /************************************************************* * Determine how many adjcency lists you need to send/receive. **************************************************************/ /* first pass: determine sizes */ for (nsend=0, nrecv=0, i=0; i<nvtxs; i++) { if (match[i] < KEEP_BIT) /* This is going away */ nsend++; else { k = match[i]-KEEP_BIT; if (k<firstvtx || k>=lastvtx) /* This is comming from afar */ nrecv++; } } scand = ikvwspacemalloc(ctrl, nsend); rcand = graph->rcand = ikvmalloc(nrecv, "CreateCoarseGraph: rcand"); /* second pass: place them in the appropriate arrays */ nkeepsize = nsend = nrecv = 0; for (i=0; i<nvtxs; i++) { if (match[i] < KEEP_BIT) { /* This is going away */ scand[nsend].key = match[i]; scand[nsend].val = i; nsend++; } else { nkeepsize += (xadj[i+1]-xadj[i]); k = match[i]-KEEP_BIT; if (k<firstvtx || k>=lastvtx) { /* This is comming from afar */ rcand[nrecv].key = k; rcand[nrecv].val = cmap[i] - cfirstvtx; /* Set it for use during the partition projection */ PASSERT(ctrl, rcand[nrecv].val>=0 && rcand[nrecv].val<cnvtxs); nrecv++; } } } #ifdef DEBUG_CONTRACT PrintPairs(ctrl, nsend, scand, "scand"); PrintPairs(ctrl, nrecv, rcand, "rcand"); #endif /*************************************************************** * Determine how many lists and their sizes you will send and * received for each of the neighboring PEs ****************************************************************/ rlens = graph->rlens = imalloc(nnbrs+1, "CreateCoarseGraph: graph->rlens"); slens = graph->slens = imalloc(nnbrs+1, "CreateCoarseGraph: graph->slens"); rsizes = iset(nnbrs, 0, iwspacemalloc(ctrl, nnbrs)); ssizes = iset(nnbrs, 0, iwspacemalloc(ctrl, nnbrs)); /* Take care the sending data first */ ikvsortii(nsend, scand); slens[0] = 0; for (k=i=0; i<nnbrs; i++) { otherlastvtx = vtxdist[peind[i]+1]; for (; k<nsend && scand[k].key < otherlastvtx; k++) ssizes[i] += (xadj[scand[k].val+1]-xadj[scand[k].val]); slens[i+1] = k; } /* Take care the receiving data next. You cannot yet determine the rsizes[] */ ikvsortii(nrecv, rcand); rlens[0] = 0; for (k=i=0; i<nnbrs; i++) { otherlastvtx = vtxdist[peind[i]+1]; for (; k<nrecv && rcand[k].key < otherlastvtx; k++); rlens[i+1] = k; } #ifdef DEBUG_CONTRACT PrintVector(ctrl, nnbrs+1, 0, slens, "slens"); PrintVector(ctrl, nnbrs+1, 0, rlens, "rlens"); #endif /*************************************************************** * Exchange size information ****************************************************************/ /* Issue the receives first. */ for (i=0; i<nnbrs; i++) { if (rlens[i+1]-rlens[i] > 0) /* Issue a receive only if you are getting something */ gkMPI_Irecv((void *)(rsizes+i), 1, IDX_T, peind[i], 1, ctrl->comm, ctrl->rreq+i); } /* Take care the sending data next */ for (i=0; i<nnbrs; i++) { if (slens[i+1]-slens[i] > 0) /* Issue a send only if you are sending something */ gkMPI_Isend((void *)(ssizes+i), 1, IDX_T, peind[i], 1, ctrl->comm, ctrl->sreq+i); } /* OK, now get into the loop waiting for the operations to finish */ for (i=0; i<nnbrs; i++) { if (rlens[i+1]-rlens[i] > 0) gkMPI_Wait(ctrl->rreq+i, &ctrl->status); } for (i=0; i<nnbrs; i++) { if (slens[i+1]-slens[i] > 0) gkMPI_Wait(ctrl->sreq+i, &ctrl->status); } #ifdef DEBUG_CONTRACT PrintVector(ctrl, nnbrs, 0, rsizes, "rsizes"); PrintVector(ctrl, nnbrs, 0, ssizes, "ssizes"); #endif /************************************************************* * Allocate memory for received/sent graphs and start sending * and receiving data. * rgraph and sgraph is a different data structure than CSR * to facilitate single message exchange. **************************************************************/ nrecvsize = isum(nnbrs, rsizes, 1); nsendsize = isum(nnbrs, ssizes, 1); rgraph = iwspacemalloc(ctrl, (4+ncon)*nrecv+2*nrecvsize); WCOREPUSH; /* for freeing sgraph right away */ sgraph = iwspacemalloc(ctrl, (4+ncon)*nsend+2*nsendsize); /* Deal with the received portion first */ for (l=i=0; i<nnbrs; i++) { /* Issue a receive only if you are getting something */ if (rlens[i+1]-rlens[i] > 0) { gkMPI_Irecv((void *)(rgraph+l), (4+ncon)*(rlens[i+1]-rlens[i])+2*rsizes[i], IDX_T, peind[i], 1, ctrl->comm, ctrl->rreq+i); l += (4+ncon)*(rlens[i+1]-rlens[i])+2*rsizes[i]; } } /* Deal with the sent portion now */ for (ll=l=i=0; i<nnbrs; i++) { if (slens[i+1]-slens[i] > 0) { /* Issue a send only if you are sending something */ for (k=slens[i]; k<slens[i+1]; k++) { ii = scand[k].val; sgraph[ll++] = firstvtx+ii; sgraph[ll++] = xadj[ii+1]-xadj[ii]; for (h=0; h<ncon; h++) sgraph[ll++] = vwgt[ii*ncon+h]; sgraph[ll++] = (ctrl->partType == STATIC_PARTITION || ctrl->partType == ORDER_PARTITION ? -1 : vsize[ii]); sgraph[ll++] = (ctrl->partType == STATIC_PARTITION || ctrl->partType == ORDER_PARTITION ? -1 : home[ii]); for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { sgraph[ll++] = cmap[adjncy[jj]]; sgraph[ll++] = adjwgt[jj]; } } PASSERT(ctrl, ll-l == (4+ncon)*(slens[i+1]-slens[i])+2*ssizes[i]); /*myprintf(ctrl, "Sending to pe:%"PRIDX", %"PRIDX" lists of size %"PRIDX"\n", peind[i], slens[i+1]-slens[i], ssizes[i]); */ gkMPI_Isend((void *)(sgraph+l), ll-l, IDX_T, peind[i], 1, ctrl->comm, ctrl->sreq+i); l = ll; } } /* OK, now get into the loop waiting for the operations to finish */ for (i=0; i<nnbrs; i++) { if (rlens[i+1]-rlens[i] > 0) gkMPI_Wait(ctrl->rreq+i, &ctrl->status); } for (i=0; i<nnbrs; i++) { if (slens[i+1]-slens[i] > 0) gkMPI_Wait(ctrl->sreq+i, &ctrl->status); } #ifdef DEBUG_CONTRACT rprintf(ctrl, "Graphs were sent!\n"); PrintTransferedGraphs(ctrl, nnbrs, peind, slens, rlens, sgraph, rgraph); #endif WCOREPOP; /* free sgraph */ /************************************************************* * Setup the mapping from indices returned by BSearch to * those that are actually stored **************************************************************/ perm = iset(graph->nrecv, -1, iwspacemalloc(ctrl, graph->nrecv)); for (j=i=0; i<nrecv; i++) { perm[BSearch(graph->nrecv, recvind, rgraph[j])] = j+1; j += (4+ncon)+2*rgraph[j+1]; } /************************************************************* * Finally, create the coarser graph **************************************************************/ /* Allocate memory for the coarser graph, and fire up coarsening */ cxadj = cgraph->xadj = imalloc(cnvtxs+1, "CreateCoarserGraph: cxadj"); cvwgt = cgraph->vwgt = imalloc(cnvtxs*ncon, "CreateCoarserGraph: cvwgt"); cnvwgt = cgraph->nvwgt = rmalloc(cnvtxs*ncon, "CreateCoarserGraph: cnvwgt"); if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) { cvsize = cgraph->vsize = imalloc(cnvtxs, "CreateCoarserGraph: cvsize"); chome = cgraph->home = imalloc(cnvtxs, "CreateCoarserGraph: chome"); } if (where != NULL) cwhere = cgraph->where = imalloc(cnvtxs, "CreateCoarserGraph: cwhere"); /* these are just upper bound estimates for now */ cadjncy = iwspacemalloc(ctrl, nkeepsize+nrecvsize); cadjwgt = iwspacemalloc(ctrl, nkeepsize+nrecvsize); iset(LHTSIZE, -1, htable); cxadj[0] = cnvtxs = cnedges = 0; for (i=0; i<nvtxs; i++) { if (match[i] >= KEEP_BIT) { v = firstvtx+i; u = match[i]-KEEP_BIT; if (u>=firstvtx && u<lastvtx && v > u) continue; /* I have already collapsed it as (u,v) */ /* Collapse the v vertex first, which you know is local */ for (h=0; h<ncon; h++) cvwgt[cnvtxs*ncon+h] = vwgt[i*ncon+h]; if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) { cvsize[cnvtxs] = vsize[i]; chome[cnvtxs] = home[i]; } if (where != NULL) cwhere[cnvtxs] = where[i]; nedges = 0; /* Collapse the v (i) vertex first */ for (j=xadj[i]; j<xadj[i+1]; j++) { k = cmap[adjncy[j]]; if (k < 0) printf("k=%d\n", (int)k); if (k != cfirstvtx+cnvtxs) { /* If this is not an internal edge */ l = k&MASK; if (htable[l] == -1) { /* Seeing this for first time */ htable[l] = k; htableidx[l] = cnedges+nedges; cadjncy[cnedges+nedges] = k; cadjwgt[cnedges+nedges++] = adjwgt[j]; } else if (htable[l] == k) { cadjwgt[htableidx[l]] += adjwgt[j]; } else { /* Now you have to go and do a search. Expensive case */ for (l=0; l<nedges; l++) { if (cadjncy[cnedges+l] == k) break; } if (l < nedges) { cadjwgt[cnedges+l] += adjwgt[j]; } else { cadjncy[cnedges+nedges] = k; cadjwgt[cnedges+nedges++] = adjwgt[j]; } } } } /* Collapse the u vertex next */ if (v != u) { if (u>=firstvtx && u<lastvtx) { /* Local vertex */ u -= firstvtx; for (h=0; h<ncon; h++) cvwgt[cnvtxs*ncon+h] += vwgt[u*ncon+h]; if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) cvsize[cnvtxs] += vsize[u]; for (j=xadj[u]; j<xadj[u+1]; j++) { k = cmap[adjncy[j]]; if (k != cfirstvtx+cnvtxs) { /* If this is not an internal edge */ l = k&MASK; if (htable[l] == -1) { /* Seeing this for first time */ htable[l] = k; htableidx[l] = cnedges+nedges; cadjncy[cnedges+nedges] = k; cadjwgt[cnedges+nedges] = adjwgt[j]; nedges++; } else if (htable[l] == k) { cadjwgt[htableidx[l]] += adjwgt[j]; } else { /* Now you have to go and do a search. Expensive case */ for (l=0; l<nedges; l++) { if (cadjncy[cnedges+l] == k) break; } if (l < nedges) { cadjwgt[cnedges+l] += adjwgt[j]; } else { cadjncy[cnedges+nedges] = k; cadjwgt[cnedges+nedges] = adjwgt[j]; nedges++; } } } } } else { /* Remote vertex */ u = perm[BSearch(graph->nrecv, recvind, u)]; for (h=0; h<ncon; h++) /* Remember that the +1 stores the vertex weight */ cvwgt[cnvtxs*ncon+h] += rgraph[(u+1)+h]; if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) { cvsize[cnvtxs] += rgraph[u+1+ncon]; chome[cnvtxs] = rgraph[u+2+ncon]; } for (j=0; j<rgraph[u]; j++) { k = rgraph[u+3+ncon+2*j]; if (k != cfirstvtx+cnvtxs) { /* If this is not an internal edge */ l = k&MASK; if (htable[l] == -1) { /* Seeing this for first time */ htable[l] = k; htableidx[l] = cnedges+nedges; cadjncy[cnedges+nedges] = k; cadjwgt[cnedges+nedges] = rgraph[u+3+ncon+2*j+1]; nedges++; } else if (htable[l] == k) { cadjwgt[htableidx[l]] += rgraph[u+3+ncon+2*j+1]; } else { /* Now you have to go and do a search. Expensive case */ for (l=0; l<nedges; l++) { if (cadjncy[cnedges+l] == k) break; } if (l < nedges) { cadjwgt[cnedges+l] += rgraph[u+3+ncon+2*j+1]; } else { cadjncy[cnedges+nedges] = k; cadjwgt[cnedges+nedges] = rgraph[u+3+ncon+2*j+1]; nedges++; } } } } } } cnedges += nedges; for (j=cxadj[cnvtxs]; j<cnedges; j++) htable[cadjncy[j]&MASK] = -1; /* reset the htable */ cxadj[++cnvtxs] = cnedges; } } cgraph->nedges = cnedges; /* ADD: In order to keep from having to change this too much */ /* ADD: I kept vwgt array and recomputed nvwgt for each coarser graph */ for (j=0; j<cnvtxs; j++) { for (h=0; h<ncon; h++) cgraph->nvwgt[j*ncon+h] = ctrl->invtvwgts[h]*cvwgt[j*ncon+h]; } cgraph->adjncy = imalloc(cnedges, "CreateCoarserGraph: cadjncy"); cgraph->adjwgt = imalloc(cnedges, "CreateCoarserGraph: cadjwgt"); icopy(cnedges, cadjncy, cgraph->adjncy); icopy(cnedges, cadjwgt, cgraph->adjwgt); WCOREPOP; /* Note that graph->where works fine even if it is NULL */ gk_free((void **)&graph->where, LTERM); }