Beispiel #1
0
void FM_Mc2WayCutRefine(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts, idx_t niter)
{
    idx_t i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass,
          me, limit, tmp, cnum;
    idx_t *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *id, *ed,
          *bndptr, *bndind;
    idx_t *moved, *swaps, *perm, *qnum;
    idx_t higain, mincut, initcut, newcut, mincutorder;
    real_t *invtvwgt, *ubfactors, *minbalv, *newbalv;
    real_t origbal, minbal, newbal, rgain, ffactor;
    rpq_t **queues;

    WCOREPUSH;

    nvtxs    = graph->nvtxs;
    ncon     = graph->ncon;
    xadj     = graph->xadj;
    vwgt     = graph->vwgt;
    adjncy   = graph->adjncy;
    adjwgt   = graph->adjwgt;
    invtvwgt = graph->invtvwgt;
    where    = graph->where;
    id       = graph->id;
    ed       = graph->ed;
    pwgts    = graph->pwgts;
    bndptr   = graph->bndptr;
    bndind   = graph->bndind;

    moved     = iwspacemalloc(ctrl, nvtxs);
    swaps     = iwspacemalloc(ctrl, nvtxs);
    perm      = iwspacemalloc(ctrl, nvtxs);
    qnum      = iwspacemalloc(ctrl, nvtxs);
    ubfactors = rwspacemalloc(ctrl, ncon);
    newbalv   = rwspacemalloc(ctrl, ncon);
    minbalv   = rwspacemalloc(ctrl, ncon);

    limit = gk_min(gk_max(0.01*nvtxs, 25), 150);


    /* Determine a fudge factor to allow the refinement routines to get out
       of tight balancing constraints. */
    ffactor = .5/gk_max(20, nvtxs);

    /* Initialize the queues */
    queues = (rpq_t **)wspacemalloc(ctrl, 2*ncon*sizeof(rpq_t *));
    for (i=0; i<2*ncon; i++)
        queues[i] = rpqCreate(nvtxs);
    for (i=0; i<nvtxs; i++)
        qnum[i] = iargmax_nrm(ncon, vwgt+i*ncon, invtvwgt);

    /* Determine the unbalance tolerance for each constraint. The tolerance is
       equal to the maximum of the original load imbalance and the user-supplied
       allowed tolerance. The rationale behind this approach is to allow the
       refinement routine to improve the cut, without having to worry about fixing
       load imbalance problems. The load imbalance is addressed by the balancing
       routines. */
    origbal = ComputeLoadImbalanceDiffVec(graph, 2, ctrl->pijbm, ctrl->ubfactors, ubfactors);
    for (i=0; i<ncon; i++)
        ubfactors[i] = (ubfactors[i] > 0 ? ctrl->ubfactors[i]+ubfactors[i] : ctrl->ubfactors[i]);


    IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
          Print2WayRefineStats(ctrl, graph, ntpwgts, origbal, -2));

    iset(nvtxs, -1, moved);
    for (pass=0; pass<niter; pass++) { /* Do a number of passes */
        for (i=0; i<2*ncon; i++)
            rpqReset(queues[i]);

        mincutorder = -1;
        newcut = mincut = initcut = graph->mincut;

        minbal = ComputeLoadImbalanceDiffVec(graph, 2, ctrl->pijbm, ubfactors, minbalv);

        ASSERT(ComputeCut(graph, where) == graph->mincut);
        ASSERT(CheckBnd(graph));

        /* Insert boundary nodes in the priority queues */
        nbnd = graph->nbnd;
        irandArrayPermute(nbnd, perm, nbnd/5, 1);
        for (ii=0; ii<nbnd; ii++) {
            i = bndind[perm[ii]];
            ASSERT(ed[i] > 0 || id[i] == 0);
            ASSERT(bndptr[i] != -1);
            //rgain = 1.0*(ed[i]-id[i])/sqrt(vwgt[i*ncon+qnum[i]]+1);
            //rgain = (ed[i]-id[i] > 0 ? 1.0*(ed[i]-id[i])/sqrt(vwgt[i*ncon+qnum[i]]+1) : ed[i]-id[i]);
            rgain = ed[i]-id[i];
            rpqInsert(queues[2*qnum[i]+where[i]], i, rgain);
        }

        for (nswaps=0; nswaps<nvtxs; nswaps++) {
            SelectQueue(graph, ctrl->pijbm, ubfactors, queues, &from, &cnum);

            to = (from+1)%2;

            if (from == -1 || (higain = rpqGetTop(queues[2*cnum+from])) == -1)
                break;
            ASSERT(bndptr[higain] != -1);

            newcut -= (ed[higain]-id[higain]);

            iaxpy(ncon,  1, vwgt+higain*ncon, 1, pwgts+to*ncon,   1);
            iaxpy(ncon, -1, vwgt+higain*ncon, 1, pwgts+from*ncon, 1);
            newbal = ComputeLoadImbalanceDiffVec(graph, 2, ctrl->pijbm, ubfactors, newbalv);

            if ((newcut < mincut && newbal <= ffactor) ||
                    (newcut == mincut && (newbal < minbal ||
                                          (newbal == minbal && BetterBalance2Way(ncon, minbalv, newbalv))))) {
                mincut      = newcut;
                minbal      = newbal;
                mincutorder = nswaps;
                rcopy(ncon, newbalv, minbalv);
            }
            else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
                newcut += (ed[higain]-id[higain]);
                iaxpy(ncon,  1, vwgt+higain*ncon, 1, pwgts+from*ncon, 1);
                iaxpy(ncon, -1, vwgt+higain*ncon, 1, pwgts+to*ncon,   1);
                break;
            }

            where[higain] = to;
            moved[higain] = nswaps;
            swaps[nswaps] = higain;

            if (ctrl->dbglvl&METIS_DBG_MOVEINFO) {
                printf("Moved%6"PRIDX" from %"PRIDX"(%"PRIDX") Gain:%5"PRIDX", "
                       "Cut:%5"PRIDX", NPwgts:", higain, from, cnum, ed[higain]-id[higain], newcut);
                for (l=0; l<ncon; l++)
                    printf("(%.3"PRREAL" %.3"PRREAL")", pwgts[l]*invtvwgt[l], pwgts[ncon+l]*invtvwgt[l]);
                printf(" %+.3"PRREAL" LB: %.3"PRREAL"(%+.3"PRREAL")\n",
                       minbal, ComputeLoadImbalance(graph, 2, ctrl->pijbm), newbal);
            }


            /**************************************************************
            * Update the id[i]/ed[i] values of the affected nodes
            ***************************************************************/
            SWAP(id[higain], ed[higain], tmp);
            if (ed[higain] == 0 && xadj[higain] < xadj[higain+1])
                BNDDelete(nbnd, bndind,  bndptr, higain);

            for (j=xadj[higain]; j<xadj[higain+1]; j++) {
                k = adjncy[j];

                kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
                INC_DEC(id[k], ed[k], kwgt);

                /* Update its boundary information and queue position */
                if (bndptr[k] != -1) { /* If k was a boundary vertex */
                    if (ed[k] == 0) { /* Not a boundary vertex any more */
                        BNDDelete(nbnd, bndind, bndptr, k);
                        if (moved[k] == -1)  /* Remove it if in the queues */
                            rpqDelete(queues[2*qnum[k]+where[k]], k);
                    }
                    else { /* If it has not been moved, update its position in the queue */
                        if (moved[k] == -1) {
                            //rgain = 1.0*(ed[k]-id[k])/sqrt(vwgt[k*ncon+qnum[k]]+1);
                            //rgain = (ed[k]-id[k] > 0 ?
                            //              1.0*(ed[k]-id[k])/sqrt(vwgt[k*ncon+qnum[k]]+1) : ed[k]-id[k]);
                            rgain = ed[k]-id[k];
                            rpqUpdate(queues[2*qnum[k]+where[k]], k, rgain);
                        }
                    }
                }
                else {
                    if (ed[k] > 0) {  /* It will now become a boundary vertex */
                        BNDInsert(nbnd, bndind, bndptr, k);
                        if (moved[k] == -1) {
                            //rgain = 1.0*(ed[k]-id[k])/sqrt(vwgt[k*ncon+qnum[k]]+1);
                            //rgain = (ed[k]-id[k] > 0 ?
                            //              1.0*(ed[k]-id[k])/sqrt(vwgt[k*ncon+qnum[k]]+1) : ed[k]-id[k]);
                            rgain = ed[k]-id[k];
                            rpqInsert(queues[2*qnum[k]+where[k]], k, rgain);
                        }
                    }
                }
            }

        }


        /****************************************************************
        * Roll back computations
        *****************************************************************/
        for (i=0; i<nswaps; i++)
            moved[swaps[i]] = -1;  /* reset moved array */
        for (nswaps--; nswaps>mincutorder; nswaps--) {
            higain = swaps[nswaps];

            to = where[higain] = (where[higain]+1)%2;
            SWAP(id[higain], ed[higain], tmp);
            if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
                BNDDelete(nbnd, bndind,  bndptr, higain);
            else if (ed[higain] > 0 && bndptr[higain] == -1)
                BNDInsert(nbnd, bndind,  bndptr, higain);

            iaxpy(ncon,  1, vwgt+higain*ncon, 1, pwgts+to*ncon,         1);
            iaxpy(ncon, -1, vwgt+higain*ncon, 1, pwgts+((to+1)%2)*ncon, 1);
            for (j=xadj[higain]; j<xadj[higain+1]; j++) {
                k = adjncy[j];

                kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
                INC_DEC(id[k], ed[k], kwgt);

                if (bndptr[k] != -1 && ed[k] == 0)
                    BNDDelete(nbnd, bndind, bndptr, k);
                if (bndptr[k] == -1 && ed[k] > 0)
                    BNDInsert(nbnd, bndind, bndptr, k);
            }
        }

        graph->mincut = mincut;
        graph->nbnd   = nbnd;

        IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
              Print2WayRefineStats(ctrl, graph, ntpwgts, minbal, mincutorder));

        if (mincutorder <= 0 || mincut == initcut)
            break;
    }

    for (i=0; i<2*ncon; i++)
        rpqDestroy(queues[i]);

    WCOREPOP;
}
Beispiel #2
0
idx_t *iwspacemalloc(ctrl_t *ctrl, size_t n)
{
  return (idx_t *)wspacemalloc(ctrl, n*sizeof(idx_t));
}
Beispiel #3
0
rkv_t *rkvwspacemalloc(ctrl_t *ctrl, size_t n)
{
  return (rkv_t *)wspacemalloc(ctrl, n*sizeof(rkv_t));
}
Beispiel #4
0
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;
}
Beispiel #5
0
ikv_t *ikvwspacemalloc(ctrl_t *ctrl, idx_t n) {
    return (ikv_t *) wspacemalloc(ctrl, n * sizeof(ikv_t));
}
Beispiel #6
0
real_t *rwspacemalloc(ctrl_t *ctrl, idx_t n) {
    return (real_t *) wspacemalloc(ctrl, n * sizeof(real_t));
}