/* * Copyright 1997, Regents of the University of Minnesota * * kfmetis.c * * This file contains the top level routines for computing a k-way partitioning * that also balances the fill-in. * * Started 8/12/02 * George * */ #include /************************************************************************* * This function is the entry point for KFMETIS **************************************************************************/ void METIS_PartFillGraph(idxtype *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, idxtype *wgtflag, idxtype *numflag, idxtype *nparts, idxtype *options, idxtype *edgecut, idxtype *part) { idxtype i, j; GraphType graph; CtrlType ctrl; /* Compute an initial k-way partitioning of the graph */ METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part); /*----------------------------------------------------------------------- * Internalize the graph and allocate memory for the workspace *-----------------------------------------------------------------------*/ if (*numflag == 1) Change2CNumbering(*nvtxs, xadj, adjncy); SetUpGraph(&graph, OP_KMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag); if (options[0] == 0) { /* Use the default parameters */ ctrl.CType = KMETIS_CTYPE; ctrl.IType = KMETIS_ITYPE; ctrl.RType = KMETIS_RTYPE; ctrl.dbglvl = KMETIS_DBGLVL; } else { ctrl.CType = options[OPTION_CTYPE]; ctrl.IType = options[OPTION_ITYPE]; ctrl.RType = options[OPTION_RTYPE]; ctrl.dbglvl = options[OPTION_DBGLVL]; } ctrl.optype = OP_KMETIS; ctrl.CoarsenTo = amax((*nvtxs)/(40*gk_log2(*nparts)), 20*(*nparts)); ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt, 1) : (*nvtxs))/ctrl.CoarsenTo); InitRandom(-1); AllocateWorkSpace(&ctrl, &graph, *nparts); /*----------------------------------------------------------------------- * Balance the fill-in *-----------------------------------------------------------------------*/ BalanceFillIn(&ctrl, &graph, *nparts, part); *edgecut = ComputeCut(&graph, part); /*----------------------------------------------------------------------- * Post-process the results *-----------------------------------------------------------------------*/ FreeWorkSpace(&ctrl, &graph); if (*numflag == 1) Change2FNumbering(*nvtxs, xadj, adjncy, part); } /************************************************************************** * This function is the top-level routine of the fill-balancing code ***************************************************************************/ void BalanceFillIn(CtrlType *ctrl, GraphType *graph, idxtype nparts, idxtype *part) { idxtype i, j, k, nvtxs, options[10]; idxtype *fills, *subfills, *ssize, *spart, *vmap, *ppart, *vimap; idxtype oldavg, oldmax, oldcut, oldmaxcut, newavg, newmax, newcut, newmaxcut; idxtype *tssize; float diff, alpha; GraphType *pgraph; nvtxs = graph->nvtxs; fills = idxsmalloc(nparts, 0, "BalanceFillIn: fills"); subfills = idxsmalloc(2*nparts, 0, "BalanceFillIn: subfills"); ssize = idxsmalloc(nparts, 0, "BalanceFillIn: ssize"); tssize = idxsmalloc(nparts, 0, "BalanceFillIn: tssize"); spart = idxmalloc(nvtxs, "BalanceFillIn: spart"); ppart = idxmalloc(nvtxs, "BalanceFillIn: ppart"); vmap = idxmalloc(nvtxs, "BalanceFillIn: vmap"); vimap = idxmalloc(nvtxs, "BalanceFillIn: vimap"); /* Go and compute a top-level vertex separator for each partition */ for (i=0; invtxs), pgraph->xadj, pgraph->adjncy, pgraph->vwgt, pgraph->adjwgt, options, &ssize[i], ppart); /* Copy the separator and partition information to the global graph's spart vector */ for (j=0; jnvtxs; j++) spart[vimap[j]] = ppart[j]; FreeGraph(pgraph, 1); } /* Go and compute the fill-ins of each partition */ for (i=0; invtxs, "ComputePartitionFillIn: vmap"); vimap = idxmalloc(graph->nvtxs, "ComputePartitionFillIn: vimap"); pgraph = ExtractPartitionGraph(graph, part, pid, vmap, vimap); pnvtxs = pgraph->nvtxs; iperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: iperm"); ppart = idxmalloc(pnvtxs, "ComputePartitionFillIn: ppart"); lvmap = idxmalloc(pnvtxs, "ComputePartitionFillIn: lvmap"); lvimap = idxmalloc(pnvtxs, "ComputePartitionFillIn: lvimap"); rvmap = idxmalloc(pnvtxs, "ComputePartitionFillIn: rvmap"); rvimap = idxmalloc(pnvtxs, "ComputePartitionFillIn: rvimap"); lperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: liperm"); liperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: liperm"); rperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: riperm"); riperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: riperm"); /* project down the separator-partition */ for (i=0; ixadj[i]; jxadj[i+1]; j++) { if (ppart[i] != ppart[pgraph->adjncy[j]]) { if (!(ppart[i] == 2 || ppart[pgraph->adjncy[j]] == 2)) mprintf("Error: %D %D %D\n", i, ppart[i], ppart[pgraph->adjncy[j]]); } } } lgraph = ExtractPartitionGraph(pgraph, ppart, 0, lvmap, lvimap); rgraph = ExtractPartitionGraph(pgraph, ppart, 1, rvmap, rvimap); options[0] = 1; options[1] = 3; options[2] = 1; options[3] = 1; options[4] = 0; options[5] = 0; options[6] = 0; options[7] = 4; METIS_NodeND(&lgraph->nvtxs, lgraph->xadj, lgraph->adjncy, &numflag, options, lperm, liperm); METIS_NodeND(&rgraph->nvtxs, rgraph->xadj, rgraph->adjncy, &numflag, options, rperm, riperm); /* Put the ordering together */ for (i=0; invtxs; i++) iperm[lvimap[i]] = liperm[i]; for (i=0; invtxs; i++) iperm[rvimap[i]] = lgraph->nvtxs + riperm[i]; for (j=lgraph->nvtxs+rgraph->nvtxs, i=0; invtxs-rgraph->nvtxs, lgraph->nvtxs, rgraph->nvtxs, r_subfill[0], r_subfill[1], *r_fill); FreeGraph(pgraph, 1); FreeGraph(lgraph, 1); FreeGraph(rgraph, 1); gk_free((void **)&vmap, &vimap, &iperm, &ppart, &lvmap, &lvimap, &rvmap, &rvimap, &lperm, &liperm, &rperm, &riperm, LTERM); } /************************************************************************* * This function extracts the graph of a partition and returns it. **************************************************************************/ GraphType *ExtractPartitionGraph(GraphType *graph, idxtype *part, idxtype pid, idxtype *vmap, idxtype *vimap) { idxtype i, j, k, nvtxs, pnvtxs, pnedges; idxtype *xadj, *adjncy, *vwgt, *adjwgt; idxtype *pxadj, *padjncy, *pvwgt, *padjwgt; GraphType *pgraph; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; vwgt = graph->vwgt; adjwgt = graph->adjwgt; /* Determine the size of the partition graph */ for (pnvtxs=pnedges=0, i=0; invtxs = pnvtxs; pgraph->nedges = pnedges; pxadj = pgraph->xadj = idxmalloc(pnvtxs+1, "ExtractPartitionGraph: xadj"); pvwgt = pgraph->vwgt = idxmalloc(pnvtxs, "ExtractPartitionGraph: vwgt"); padjncy = pgraph->adjncy = idxmalloc(pnedges, "ExtractPartitionGraph: adjncy"); padjwgt = pgraph->adjwgt = idxmalloc(pnedges, "ExtractPartitionGraph: adjwgt"); pgraph->adjwgtsum = idxmalloc(pnvtxs, "ExtractPartitionGraph: adjwgtsum"); pgraph->cmap = idxmalloc(pnvtxs, "ExtractPartitionGraph: cmap"); /* Go and extract the partition graph */ pxadj[0] = pnvtxs = pnedges = 0; for (i=0; invtxs; xadj = graph->xadj; vwgt = graph->vwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; pwgts = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pwgts"); spwgts[0] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: spwgts"); spwgts[1] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: spwgts"); spwgts[2] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: spwgts"); pdegrees[0] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pdegrees"); pdegrees[1] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pdegrees"); pdegrees[2] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pdegrees"); pdegrees[3] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pdegrees"); pmarker = idxsmalloc(nparts, -1, "RefineTopLevelSeparators: pmarker "); pids = idxmalloc(nparts, "RefineTopLevelSeparators: pids "); perm = idxmalloc(nvtxs, "RefineTopLevelSeparators: perm"); alphas[0] = gk_fmalloc(nparts, "RefineTopLevelSeparators: alphas[0]"); alphas[1] = gk_fmalloc(nparts, "RefineTopLevelSeparators: alphas[1]"); alphas[2] = gk_fmalloc(nparts, "RefineTopLevelSeparators: alphas[2]"); mincut = ComputeCut(graph, part); /* Compute partition and separator sizes */ for (i=0; i maxpwgt) continue; if (fills[pids[j]] > amax(fills[from], avgfill)) { nskip[0]++; if (tssizes[from] < ssizes[from]) nskip[2]++; continue; } if (pdegrees[0][j] > 0 && spwgts[0][pids[j]] > maxspwgt) continue; if (pdegrees[1][j] > 0 && spwgts[1][pids[j]] > maxspwgt) continue; if (pdegrees[0][j]*pdegrees[1][j] == 0) { /* will not increase target separator */ to = (to == -1 || pdegrees[3][to] < pdegrees[3][j] ? j : to); } } if (to == -1 && tssizes[from] < ssizes[from]) nskip[1]++; /* See if some of the moves should be skipped */ if (to != -1 && pdegrees[3][to] < id && tssizes[from] > ssizes[from]) to = -1; if (to != -1 && pdegrees[3][to] < id && RandomInRange(3) == 0) { nskip[3]++; to = -1; } if (to != -1 && id - pdegrees[3][to] > avgdegree*(0.9+0.07*pass)) { nskip[4]++; to = -1; } } else { /* I'm not on the separator */ for (to=-1, j=0; j maxpwgt) continue; if (tssizes[pids[j]] < ssizes[pids[j]]) continue; if (pdegrees[0][j] > 0 && spwgts[0][pids[j]] > maxspwgt) continue; if (pdegrees[1][j] > 0 && spwgts[1][pids[j]] > maxspwgt) continue; if (pdegrees[0][j]*pdegrees[1][j] == 0) { /* will not increase target separator */ to = (to == -1 || pdegrees[3][to] < pdegrees[3][j] ? j : to); } } if (to != -1) { if (pdegrees[3][to] < id) to = -1; else if (pdegrees[3][to] == id && fills[from] < fills[pids[to]] /*pwgts[from] < pwgts[pids[to]]*/) to = -1; } } if (to != -1) { /* mprintf("%2D. Moving %6D %3D -> %3D, %2D -> %2D, Gain: %+4D, SepFrom: %4D, SepTo: %3D, Cut: %5D, %4D %4D\n", pass, i, from, pids[to], spart[i], (pdegrees[0][to] > pdegrees[1][to] ? 0 : 1), pdegrees[3][to] - id, ssizes[from], ssizes[pids[to]], mincut, pwgts[from], pwgts[pids[to]]); */ /* Update the approximations of fill of 'from' */ if (spart[i] == 2) fills[from] -= (pow(ssizes[from], alphas[2][from]) - pow(ssizes[from]-vwgt[i], alphas[2][from])); else fills[from] -= (pow(spwgts[spart[i]][from], alphas[spart[i]][from]) - pow(spwgts[spart[i]][from]-vwgt[i], alphas[spart[i]][from])); if (spart[i] == 2) ssizes[from] -= vwgt[i]; pwgts[from] -= vwgt[i]; spwgts[spart[i]][from] -= vwgt[i]; part[i] = pids[to]; spart[i] = (pdegrees[0][to] > pdegrees[1][to] ? 0 : 1); /* Update the approximations of fill of 'to' */ fills[to] += (pow(spwgts[spart[i]][to]+vwgt[i], alphas[spart[i]][to]) - pow(spwgts[spart[i]][to], alphas[spart[i]][to])); pwgts[pids[to]] += vwgt[i]; spwgts[spart[i]][pids[to]] += vwgt[i]; mincut = mincut - (pdegrees[3][to] - id); nmoves++; } /* reset pmarker */ for (j=xadj[i]; j