idx_t IsConnected(graph_t *graph, idx_t report) { idx_t ncmps; ncmps = FindPartitionInducedComponents(graph, NULL, NULL, NULL); if (ncmps != 1 && report) { printf("The graph is not connected. It has %"PRIDX" connected components.\n", ncmps); } return (ncmps == 1); }
void RefineKWay(ctrl_t *ctrl, graph_t *orggraph, graph_t *graph) { idx_t i, nlevels, contig=ctrl->contig; graph_t *ptr; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->UncoarsenTmr)); /* Determine how many levels are there */ for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++); /* Compute the parameters of the coarsest graph */ ComputeKWayPartitionParams(ctrl, graph); /* Try to minimize the sub-domain connectivity */ if (ctrl->minconn) EliminateSubDomainEdges(ctrl, graph); /* Deal with contiguity constraints at the beginning */ if (contig && FindPartitionInducedComponents(graph, graph->where, NULL, NULL) > ctrl->nparts) { EliminateComponents(ctrl, graph); ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE); Greedy_KWayOptimize(ctrl, graph, 5, 0, OMODE_BALANCE); ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE); Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 0, OMODE_REFINE); ctrl->contig = 0; } /* Refine each successively finer graph */ for (i=0; ;i++) { if (ctrl->minconn && i == nlevels/2) EliminateSubDomainEdges(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->RefTmr)); if (2*i >= nlevels && !IsBalanced(ctrl, graph, .02)) { ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE); Greedy_KWayOptimize(ctrl, graph, 1, 0, OMODE_BALANCE); ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE); } Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 5.0, OMODE_REFINE); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->RefTmr)); /* Deal with contiguity constraints in the middle */ if (contig && i == nlevels/2) { if (FindPartitionInducedComponents(graph, graph->where, NULL, NULL) > ctrl->nparts) { EliminateComponents(ctrl, graph); if (!IsBalanced(ctrl, graph, .02)) { ctrl->contig = 1; ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE); Greedy_KWayOptimize(ctrl, graph, 5, 0, OMODE_BALANCE); ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE); Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 0, OMODE_REFINE); ctrl->contig = 0; } } } if (graph == orggraph) break; graph = graph->finer; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ProjectTmr)); ASSERT(graph->vwgt != NULL); ProjectKWayPartition(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr)); } /* Deal with contiguity requirement at the end */ ctrl->contig = contig; if (contig && FindPartitionInducedComponents(graph, graph->where, NULL, NULL) > ctrl->nparts) EliminateComponents(ctrl, graph); if (!IsBalanced(ctrl, graph, 0.0)) { ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE); Greedy_KWayOptimize(ctrl, graph, 10, 0, OMODE_BALANCE); ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE); Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 0, OMODE_REFINE); } if (ctrl->contig) ASSERT(FindPartitionInducedComponents(graph, graph->where, NULL, NULL) == ctrl->nparts); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->UncoarsenTmr)); }
void EliminateComponents(ctrl_t *ctrl, graph_t *graph) { idx_t i, ii, j, jj, k, me, nparts, nvtxs, ncon, ncmps, other, ncand, target; idx_t *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts; idx_t *cptr, *cind, *cpvec, *pcptr, *pcind, *cwhere; idx_t cid, bestcid, *cwgt, *bestcwgt; idx_t ntodo, oldntodo, *todo; rkv_t *cand; real_t *tpwgts; idx_t *vmarker = NULL, *pmarker = NULL, *modind = NULL; /* volume specific work arrays */ WCOREPUSH; nvtxs = graph->nvtxs; ncon = graph->ncon; xadj = graph->xadj; adjncy = graph->adjncy; vwgt = graph->vwgt; adjwgt = (ctrl->objtype == METIS_OBJTYPE_VOL ? NULL : graph->adjwgt); where = graph->where; pwgts = graph->pwgts; nparts = ctrl->nparts; tpwgts = ctrl->tpwgts; cptr = iwspacemalloc(ctrl, nvtxs + 1); cind = iwspacemalloc(ctrl, nvtxs); ncmps = FindPartitionInducedComponents(graph, where, cptr, cind); IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, printf("I found %"PRIDX" components, for this %"PRIDX"-way partition\n", ncmps, nparts)); /* There are more components than partitions */ if (ncmps > nparts) { cwgt = iwspacemalloc(ctrl, ncon); bestcwgt = iwspacemalloc(ctrl, ncon); cpvec = iwspacemalloc(ctrl, nparts); pcptr = iset(nparts + 1, 0, iwspacemalloc(ctrl, nparts + 1)); pcind = iwspacemalloc(ctrl, ncmps); cwhere = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs)); todo = iwspacemalloc(ctrl, ncmps); cand = (rkv_t *) wspacemalloc(ctrl, nparts * sizeof(rkv_t)); if (ctrl->objtype == METIS_OBJTYPE_VOL) { /* Vol-refinement specific working arrays */ modind = iwspacemalloc(ctrl, nvtxs); vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs)); pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts)); } /* Get a CSR representation of the components-2-partitions mapping */ for (i = 0; i < ncmps; i++) { pcptr[where[cind[cptr[i]]]]++; } MAKECSR(i, nparts, pcptr); for (i = 0; i < ncmps; i++) { pcind[pcptr[where[cind[cptr[i]]]]++] = i; } SHIFTCSR(i, nparts, pcptr); /* Assign the heaviest component of each partition to its original partition */ for (ntodo = 0, i = 0; i < nparts; i++) { if (pcptr[i + 1] - pcptr[i] == 1) { bestcid = pcind[pcptr[i]]; } else { for (bestcid = -1, j = pcptr[i]; j < pcptr[i + 1]; j++) { cid = pcind[j]; iset(ncon, 0, cwgt); for (ii = cptr[cid]; ii < cptr[cid + 1]; ii++) { iaxpy(ncon, 1, vwgt + cind[ii] * ncon, 1, cwgt, 1); } if (bestcid == -1 || isum(ncon, bestcwgt, 1) < isum(ncon, cwgt, 1)) { bestcid = cid; icopy(ncon, cwgt, bestcwgt); } } /* Keep track of those that need to be dealt with */ for (j = pcptr[i]; j < pcptr[i + 1]; j++) { if (pcind[j] != bestcid) { todo[ntodo++] = pcind[j]; } } } for (j = cptr[bestcid]; j < cptr[bestcid + 1]; j++) { ASSERT(where[cind[j]] == i); cwhere[cind[j]] = i; } } while (ntodo > 0) { oldntodo = ntodo; for (i = 0; i < ntodo; i++) { cid = todo[i]; me = where[cind[cptr[cid]]]; /* Get the domain of this component */ /* Determine the weight of the block to be moved */ iset(ncon, 0, cwgt); for (j = cptr[cid]; j < cptr[cid + 1]; j++) { iaxpy(ncon, 1, vwgt + cind[j] * ncon, 1, cwgt, 1); } IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, printf("Trying to move %"PRIDX" [%"PRIDX"] from %"PRIDX"\n", cid, isum(ncon, cwgt, 1), me)); /* Determine the connectivity */ iset(nparts, 0, cpvec); for (j = cptr[cid]; j < cptr[cid + 1]; j++) { ii = cind[j]; for (jj = xadj[ii]; jj < xadj[ii + 1]; jj++) { if (cwhere[adjncy[jj]] != -1) { cpvec[cwhere[adjncy[jj]]] += (adjwgt ? adjwgt[jj] : 1); } } } /* Put the neighbors into a cand[] array for sorting */ for (ncand = 0, j = 0; j < nparts; j++) { if (cpvec[j] > 0) { cand[ncand].key = cpvec[j]; cand[ncand++].val = j; } } if (ncand == 0) { continue; } rkvsortd(ncand, cand); /* Limit the moves to only the top candidates, which are defined as those with connectivity at least 50% of the best. This applies only when ncon=1, as for multi-constraint, balancing will be hard. */ if (ncon == 1) { for (j = 1; j < ncand; j++) { if (cand[j].key < .5 * cand[0].key) { break; } } ncand = j; } /* Now among those, select the one with the best balance */ target = cand[0].val; for (j = 1; j < ncand; j++) { if (BetterBalanceKWay(ncon, cwgt, ctrl->ubfactors, 1, pwgts + target * ncon, ctrl->pijbm + target * ncon, 1, pwgts + cand[j].val * ncon, ctrl->pijbm + cand[j].val * ncon)) { target = cand[j].val; } } IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, printf("\tMoving it to %"PRIDX" [%"PRIDX"] [%"PRIDX"]\n", target, cpvec[target], ncand)); /* Note that as a result of a previous movement, a connected component may now will like to stay to its original partition */ if (target != me) { switch (ctrl->objtype) { case METIS_OBJTYPE_CUT:MoveGroupContigForCut(ctrl, graph, target, cid, cptr, cind); break; case METIS_OBJTYPE_VOL: MoveGroupContigForVol(ctrl, graph, target, cid, cptr, cind, vmarker, pmarker, modind); break; default:gk_errexit(SIGERR, "Unknown objtype %d\n", ctrl->objtype); } } /* Update the cwhere vector */ for (j = cptr[cid]; j < cptr[cid + 1]; j++) { cwhere[cind[j]] = target; } todo[i] = todo[--ntodo]; } if (oldntodo == ntodo) { IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, printf("Stopped at ntodo: %"PRIDX"\n", ntodo)); break; } } for (i = 0; i < nvtxs; i++) { ASSERT(where[i] == cwhere[i]); } } WCOREPOP; }