00001
00011 #include "metislib.h"
00012
00013
00014
00031
00032 idx_t FindPartitionInducedComponents(graph_t *graph, idx_t *where,
00033 idx_t *cptr, idx_t *cind)
00034 {
00035 idx_t i, ii, j, jj, k, me=0, nvtxs, first, last, nleft, ncmps;
00036 idx_t *xadj, *adjncy;
00037 idx_t *touched, *perm, *todo;
00038 idx_t mustfree_ccsr=0, mustfree_where=0;
00039
00040 nvtxs = graph->nvtxs;
00041 xadj = graph->xadj;
00042 adjncy = graph->adjncy;
00043
00044
00045 if (cptr == NULL) {
00046 cptr = imalloc(nvtxs+1, "FindPartitionInducedComponents: cptr");
00047 cind = imalloc(nvtxs, "FindPartitionInducedComponents: cind");
00048 mustfree_ccsr = 1;
00049 }
00050
00051
00052 if (where == NULL) {
00053 where = ismalloc(nvtxs, 0, "FindPartitionInducedComponents: where");
00054 mustfree_where = 1;
00055 }
00056
00057
00058 perm = iincset(nvtxs, 0, imalloc(nvtxs, "FindPartitionInducedComponents: perm"));
00059 todo = iincset(nvtxs, 0, imalloc(nvtxs, "FindPartitionInducedComponents: todo"));
00060 touched = ismalloc(nvtxs, 0, "FindPartitionInducedComponents: touched");
00061
00062
00063
00064 ncmps = -1;
00065 first = last = 0;
00066 nleft = nvtxs;
00067 while (nleft > 0) {
00068 if (first == last) {
00069 cptr[++ncmps] = first;
00070 ASSERT(touched[todo[0]] == 0);
00071 i = todo[0];
00072 cind[last++] = i;
00073 touched[i] = 1;
00074 me = where[i];
00075 }
00076
00077 i = cind[first++];
00078 k = perm[i];
00079 j = todo[k] = todo[--nleft];
00080 perm[j] = k;
00081
00082 for (j=xadj[i]; j<xadj[i+1]; j++) {
00083 k = adjncy[j];
00084 if (where[k] == me && !touched[k]) {
00085 cind[last++] = k;
00086 touched[k] = 1;
00087 }
00088 }
00089 }
00090 cptr[++ncmps] = first;
00091
00092 if (mustfree_ccsr)
00093 gk_free((void **)&cptr, &cind, LTERM);
00094 if (mustfree_where)
00095 gk_free((void **)&where, LTERM);
00096
00097 gk_free((void **)&perm, &todo, &touched, LTERM);
00098
00099 return ncmps;
00100 }
00101
00102
00103
00114
00115 void ComputeBFSOrdering(ctrl_t *ctrl, graph_t *graph, idx_t *bfsperm)
00116 {
00117 idx_t i, j, k, nvtxs, first, last;
00118 idx_t *xadj, *adjncy, *perm;
00119
00120 WCOREPUSH;
00121
00122 nvtxs = graph->nvtxs;
00123 xadj = graph->xadj;
00124 adjncy = graph->adjncy;
00125
00126
00127 perm = iincset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
00128
00129 iincset(nvtxs, 0, bfsperm);
00130
00131
00132
00133 first = last = 0;
00134 while (first < nvtxs) {
00135 if (first == last) {
00136 k = bfsperm[last];
00137 ASSERT(perm[k] != -1);
00138 perm[k] = -1;
00139 last++;
00140 }
00141
00142 i = bfsperm[first++];
00143 for (j=xadj[i]; j<xadj[i+1]; j++) {
00144 k = adjncy[j];
00145
00146 if (perm[k] != -1) {
00147
00148
00149
00150 bfsperm[perm[k]] = bfsperm[last];
00151 perm[bfsperm[last]] = perm[k];
00152
00153 bfsperm[last++] = k;
00154 perm[k] = -1;
00155 }
00156 }
00157 }
00158
00159 WCOREPOP;
00160 }
00161
00162
00163
00166
00167 idx_t IsConnected(graph_t *graph, idx_t report)
00168 {
00169 idx_t ncmps;
00170
00171 ncmps = FindPartitionInducedComponents(graph, NULL, NULL, NULL);
00172
00173 if (ncmps != 1 && report)
00174 printf("The graph is not connected. It has %"PRIDX" connected components.\n", ncmps);
00175
00176 return (ncmps == 1);
00177 }
00178
00179
00180
00183
00184 idx_t IsConnectedSubdomain(ctrl_t *ctrl, graph_t *graph, idx_t pid, idx_t report)
00185 {
00186 idx_t i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
00187 idx_t *xadj, *adjncy, *where, *touched, *queue;
00188 idx_t *cptr;
00189
00190 nvtxs = graph->nvtxs;
00191 xadj = graph->xadj;
00192 adjncy = graph->adjncy;
00193 where = graph->where;
00194
00195 touched = ismalloc(nvtxs, 0, "IsConnected: touched");
00196 queue = imalloc(nvtxs, "IsConnected: queue");
00197 cptr = imalloc(nvtxs+1, "IsConnected: cptr");
00198
00199 nleft = 0;
00200 for (i=0; i<nvtxs; i++) {
00201 if (where[i] == pid)
00202 nleft++;
00203 }
00204
00205 for (i=0; i<nvtxs; i++) {
00206 if (where[i] == pid)
00207 break;
00208 }
00209
00210 touched[i] = 1;
00211 queue[0] = i;
00212 first = 0; last = 1;
00213
00214 cptr[0] = 0;
00215 ncmps = 0;
00216 while (first != nleft) {
00217 if (first == last) {
00218 cptr[++ncmps] = first;
00219 for (i=0; i<nvtxs; i++) {
00220 if (where[i] == pid && !touched[i])
00221 break;
00222 }
00223 queue[last++] = i;
00224 touched[i] = 1;
00225 }
00226
00227 i = queue[first++];
00228 for (j=xadj[i]; j<xadj[i+1]; j++) {
00229 k = adjncy[j];
00230 if (where[k] == pid && !touched[k]) {
00231 queue[last++] = k;
00232 touched[k] = 1;
00233 }
00234 }
00235 }
00236 cptr[++ncmps] = first;
00237
00238 if (ncmps > 1 && report) {
00239 printf("The graph has %"PRIDX" connected components in partition %"PRIDX":\t", ncmps, pid);
00240 for (i=0; i<ncmps; i++) {
00241 wgt = 0;
00242 for (j=cptr[i]; j<cptr[i+1]; j++)
00243 wgt += graph->vwgt[queue[j]];
00244 printf("[%5"PRIDX" %5"PRIDX"] ", cptr[i+1]-cptr[i], wgt);
00245
00246
00247
00248
00249 }
00250 printf("\n");
00251 }
00252
00253 gk_free((void **)&touched, &queue, &cptr, LTERM);
00254
00255 return (ncmps == 1 ? 1 : 0);
00256 }
00257
00258
00259
00266
00267 idx_t FindSepInducedComponents(ctrl_t *ctrl, graph_t *graph, idx_t *cptr,
00268 idx_t *cind)
00269 {
00270 idx_t i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
00271 idx_t *xadj, *adjncy, *where, *touched, *queue;
00272
00273 nvtxs = graph->nvtxs;
00274 xadj = graph->xadj;
00275 adjncy = graph->adjncy;
00276 where = graph->where;
00277
00278 touched = ismalloc(nvtxs, 0, "IsConnected: queue");
00279
00280 for (i=0; i<graph->nbnd; i++)
00281 touched[graph->bndind[i]] = 1;
00282
00283 queue = cind;
00284
00285 nleft = 0;
00286 for (i=0; i<nvtxs; i++) {
00287 if (where[i] != 2)
00288 nleft++;
00289 }
00290
00291 for (i=0; i<nvtxs; i++) {
00292 if (where[i] != 2)
00293 break;
00294 }
00295
00296 touched[i] = 1;
00297 queue[0] = i;
00298 first = 0;
00299 last = 1;
00300 cptr[0] = 0;
00301 ncmps = 0;
00302
00303 while (first != nleft) {
00304 if (first == last) {
00305 cptr[++ncmps] = first;
00306 for (i=0; i<nvtxs; i++) {
00307 if (!touched[i])
00308 break;
00309 }
00310 queue[last++] = i;
00311 touched[i] = 1;
00312 }
00313
00314 i = queue[first++];
00315 for (j=xadj[i]; j<xadj[i+1]; j++) {
00316 k = adjncy[j];
00317 if (!touched[k]) {
00318 queue[last++] = k;
00319 touched[k] = 1;
00320 }
00321 }
00322 }
00323 cptr[++ncmps] = first;
00324
00325 gk_free((void **)&touched, LTERM);
00326
00327 return ncmps;
00328 }
00329
00330
00331
00335
00336 void EliminateComponents(ctrl_t *ctrl, graph_t *graph)
00337 {
00338 idx_t i, ii, j, jj, k, me, nparts, nvtxs, ncon, ncmps, other,
00339 ncand, target;
00340 idx_t *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts;
00341 idx_t *cptr, *cind, *cpvec, *pcptr, *pcind, *cwhere;
00342 idx_t cid, bestcid, *cwgt, *bestcwgt;
00343 idx_t ntodo, oldntodo, *todo;
00344 rkv_t *cand;
00345 real_t *tpwgts;
00346 idx_t *vmarker=NULL, *pmarker=NULL, *modind=NULL;
00347
00348 WCOREPUSH;
00349
00350 nvtxs = graph->nvtxs;
00351 ncon = graph->ncon;
00352 xadj = graph->xadj;
00353 adjncy = graph->adjncy;
00354 vwgt = graph->vwgt;
00355 adjwgt = (ctrl->objtype == METIS_OBJTYPE_VOL ? NULL : graph->adjwgt);
00356
00357 where = graph->where;
00358 pwgts = graph->pwgts;
00359
00360 nparts = ctrl->nparts;
00361 tpwgts = ctrl->tpwgts;
00362
00363 cptr = iwspacemalloc(ctrl, nvtxs+1);
00364 cind = iwspacemalloc(ctrl, nvtxs);
00365
00366 ncmps = FindPartitionInducedComponents(graph, where, cptr, cind);
00367
00368 IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO,
00369 printf("I found %"PRIDX" components, for this %"PRIDX"-way partition\n",
00370 ncmps, nparts));
00371
00372
00373 if (ncmps > nparts) {
00374 cwgt = iwspacemalloc(ctrl, ncon);
00375 bestcwgt = iwspacemalloc(ctrl, ncon);
00376 cpvec = iwspacemalloc(ctrl, nparts);
00377 pcptr = iset(nparts+1, 0, iwspacemalloc(ctrl, nparts+1));
00378 pcind = iwspacemalloc(ctrl, ncmps);
00379 cwhere = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));
00380 todo = iwspacemalloc(ctrl, ncmps);
00381 cand = (rkv_t *)wspacemalloc(ctrl, nparts*sizeof(rkv_t));
00382
00383 if (ctrl->objtype == METIS_OBJTYPE_VOL) {
00384
00385 modind = iwspacemalloc(ctrl, nvtxs);
00386 vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
00387 pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts));
00388 }
00389
00390
00391
00392 for (i=0; i<ncmps; i++)
00393 pcptr[where[cind[cptr[i]]]]++;
00394 MAKECSR(i, nparts, pcptr);
00395 for (i=0; i<ncmps; i++)
00396 pcind[pcptr[where[cind[cptr[i]]]]++] = i;
00397 SHIFTCSR(i, nparts, pcptr);
00398
00399
00400 for (ntodo=0, i=0; i<nparts; i++) {
00401 if (pcptr[i+1]-pcptr[i] == 1)
00402 bestcid = pcind[pcptr[i]];
00403 else {
00404 for (bestcid=-1, j=pcptr[i]; j<pcptr[i+1]; j++) {
00405 cid = pcind[j];
00406 iset(ncon, 0, cwgt);
00407 for (ii=cptr[cid]; ii<cptr[cid+1]; ii++)
00408 iaxpy(ncon, 1, vwgt+cind[ii]*ncon, 1, cwgt, 1);
00409 if (bestcid == -1 || isum(ncon, bestcwgt, 1) < isum(ncon, cwgt, 1)) {
00410 bestcid = cid;
00411 icopy(ncon, cwgt, bestcwgt);
00412 }
00413 }
00414
00415 for (j=pcptr[i]; j<pcptr[i+1]; j++) {
00416 if (pcind[j] != bestcid)
00417 todo[ntodo++] = pcind[j];
00418 }
00419 }
00420
00421 for (j=cptr[bestcid]; j<cptr[bestcid+1]; j++) {
00422 ASSERT(where[cind[j]] == i);
00423 cwhere[cind[j]] = i;
00424 }
00425 }
00426
00427
00428 while (ntodo > 0) {
00429 oldntodo = ntodo;
00430 for (i=0; i<ntodo; i++) {
00431 cid = todo[i];
00432 me = where[cind[cptr[cid]]];
00433
00434
00435 iset(ncon, 0, cwgt);
00436 for (j=cptr[cid]; j<cptr[cid+1]; j++)
00437 iaxpy(ncon, 1, vwgt+cind[j]*ncon, 1, cwgt, 1);
00438
00439 IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO,
00440 printf("Trying to move %"PRIDX" [%"PRIDX"] from %"PRIDX"\n",
00441 cid, isum(ncon, cwgt, 1), me));
00442
00443
00444 iset(nparts, 0, cpvec);
00445 for (j=cptr[cid]; j<cptr[cid+1]; j++) {
00446 ii = cind[j];
00447 for (jj=xadj[ii]; jj<xadj[ii+1]; jj++)
00448 if (cwhere[adjncy[jj]] != -1)
00449 cpvec[cwhere[adjncy[jj]]] += (adjwgt ? adjwgt[jj] : 1);
00450 }
00451
00452
00453 for (ncand=0, j=0; j<nparts; j++) {
00454 if (cpvec[j] > 0) {
00455 cand[ncand].key = cpvec[j];
00456 cand[ncand++].val = j;
00457 }
00458 }
00459 if (ncand == 0)
00460 continue;
00461
00462 rkvsortd(ncand, cand);
00463
00464
00465
00466
00467
00468 if (ncon == 1) {
00469 for (j=1; j<ncand; j++) {
00470 if (cand[j].key < .5*cand[0].key)
00471 break;
00472 }
00473 ncand = j;
00474 }
00475
00476
00477 target = cand[0].val;
00478 for (j=1; j<ncand; j++) {
00479 if (BetterBalanceKWay(ncon, cwgt, ctrl->ubfactors,
00480 1, pwgts+target*ncon, ctrl->pijbm+target*ncon,
00481 1, pwgts+cand[j].val*ncon, ctrl->pijbm+cand[j].val*ncon))
00482 target = cand[j].val;
00483 }
00484
00485 IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO,
00486 printf("\tMoving it to %"PRIDX" [%"PRIDX"] [%"PRIDX"]\n", target, cpvec[target], ncand));
00487
00488
00489
00490 if (target != me) {
00491 switch (ctrl->objtype) {
00492 case METIS_OBJTYPE_CUT:
00493 MoveGroupContigForCut(ctrl, graph, target, cid, cptr, cind);
00494 break;
00495
00496 case METIS_OBJTYPE_VOL:
00497 MoveGroupContigForVol(ctrl, graph, target, cid, cptr, cind,
00498 vmarker, pmarker, modind);
00499 break;
00500
00501 default:
00502 gk_errexit(SIGERR, "Unknown objtype %d\n", ctrl->objtype);
00503 }
00504 }
00505
00506
00507 for (j=cptr[cid]; j<cptr[cid+1]; j++)
00508 cwhere[cind[j]] = target;
00509
00510 todo[i] = todo[--ntodo];
00511 }
00512 if (oldntodo == ntodo) {
00513 IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, printf("Stopped at ntodo: %"PRIDX"\n", ntodo));
00514 break;
00515 }
00516 }
00517
00518 for (i=0; i<nvtxs; i++)
00519 ASSERT(where[i] == cwhere[i]);
00520
00521 }
00522
00523 WCOREPOP;
00524 }
00525
00526
00527
00530
00531 void MoveGroupContigForCut(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t gid,
00532 idx_t *ptr, idx_t *ind)
00533 {
00534 idx_t i, ii, iii, j, jj, k, l, nvtxs, nbnd, from, me;
00535 idx_t *xadj, *adjncy, *adjwgt, *where, *bndptr, *bndind;
00536 ckrinfo_t *myrinfo;
00537 cnbr_t *mynbrs;
00538
00539 nvtxs = graph->nvtxs;
00540 xadj = graph->xadj;
00541 adjncy = graph->adjncy;
00542 adjwgt = graph->adjwgt;
00543
00544 where = graph->where;
00545 bndptr = graph->bndptr;
00546 bndind = graph->bndind;
00547
00548 nbnd = graph->nbnd;
00549
00550 for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) {
00551 i = ind[iii];
00552 from = where[i];
00553
00554 myrinfo = graph->ckrinfo+i;
00555 if (myrinfo->inbr == -1) {
00556 myrinfo->inbr = cnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);
00557 myrinfo->nnbrs = 0;
00558 }
00559 mynbrs = ctrl->cnbrpool + myrinfo->inbr;
00560
00561
00562 for (k=0; k<myrinfo->nnbrs; k++) {
00563 if (mynbrs[k].pid == to)
00564 break;
00565 }
00566 if (k == myrinfo->nnbrs) {
00567 mynbrs[k].pid = to;
00568 mynbrs[k].ed = 0;
00569 myrinfo->nnbrs++;
00570 }
00571
00572 graph->mincut -= mynbrs[k].ed-myrinfo->id;
00573
00574
00575 iaxpy(graph->ncon, 1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon, 1);
00576 iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
00577 UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where, nbnd,
00578 bndptr, bndind, BNDTYPE_REFINE);
00579
00580
00581 for (j=xadj[i]; j<xadj[i+1]; j++) {
00582 ii = adjncy[j];
00583 me = where[ii];
00584 myrinfo = graph->ckrinfo+ii;
00585
00586 UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me,
00587 from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, BNDTYPE_REFINE);
00588 }
00589
00590 ASSERT(CheckRInfo(ctrl, graph->ckrinfo+i));
00591 }
00592
00593 graph->nbnd = nbnd;
00594 }
00595
00596
00597
00600
00601 void MoveGroupContigForVol(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t gid,
00602 idx_t *ptr, idx_t *ind, idx_t *vmarker, idx_t *pmarker,
00603 idx_t *modind)
00604 {
00605 idx_t i, ii, iii, j, jj, k, l, nvtxs, from, me, other, xgain;
00606 idx_t *xadj, *vsize, *adjncy, *where;
00607 vkrinfo_t *myrinfo, *orinfo;
00608 vnbr_t *mynbrs, *onbrs;
00609
00610 nvtxs = graph->nvtxs;
00611 xadj = graph->xadj;
00612 vsize = graph->vsize;
00613 adjncy = graph->adjncy;
00614 where = graph->where;
00615
00616 for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) {
00617 i = ind[iii];
00618 from = where[i];
00619
00620 myrinfo = graph->vkrinfo+i;
00621 if (myrinfo->inbr == -1) {
00622 myrinfo->inbr = vnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);
00623 myrinfo->nnbrs = 0;
00624 }
00625 mynbrs = ctrl->vnbrpool + myrinfo->inbr;
00626
00627 xgain = (myrinfo->nid == 0 && myrinfo->ned > 0 ? vsize[i] : 0);
00628
00629
00630 for (k=0; k<myrinfo->nnbrs; k++) {
00631 if (mynbrs[k].pid == to)
00632 break;
00633 }
00634 if (k == myrinfo->nnbrs) {
00635 if (myrinfo->nid > 0)
00636 xgain -= vsize[i];
00637
00638
00639 for (j=xadj[i]; j<xadj[i+1]; j++) {
00640 ii = adjncy[j];
00641 other = where[ii];
00642 orinfo = graph->vkrinfo+ii;
00643 onbrs = ctrl->vnbrpool + orinfo->inbr;
00644 ASSERT(other != to)
00645
00646 if (from == other) {
00647
00648 for (l=0; l<orinfo->nnbrs; l++) {
00649 if (onbrs[l].pid == to)
00650 break;
00651 }
00652 if (l == orinfo->nnbrs)
00653 xgain -= vsize[ii];
00654 }
00655 else {
00656
00657 for (l=0; l<orinfo->nnbrs; l++) {
00658 if (onbrs[l].pid == to)
00659 break;
00660 }
00661 if (l == orinfo->nnbrs)
00662 xgain -= vsize[ii];
00663
00664
00665 for (l=0; l<orinfo->nnbrs; l++) {
00666 if (onbrs[l].pid == from && onbrs[l].ned == 1) {
00667 xgain += vsize[ii];
00668 break;
00669 }
00670 }
00671 }
00672 }
00673 graph->minvol -= xgain;
00674 graph->mincut -= -myrinfo->nid;
00675 }
00676 else {
00677 graph->minvol -= (xgain + mynbrs[k].gv);
00678 graph->mincut -= mynbrs[k].ned-myrinfo->nid;
00679 }
00680
00681
00682
00683 where[i] = to;
00684 iaxpy(graph->ncon, 1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon, 1);
00685 iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
00686
00687
00688 KWayVolUpdate(ctrl, graph, i, from, to, NULL, NULL, NULL, NULL,
00689 NULL, BNDTYPE_REFINE, vmarker, pmarker, modind);
00690
00691
00692 }
00693
00694 ASSERT(ComputeCut(graph, where) == graph->mincut);
00695 ASSERTP(ComputeVolume(graph, where) == graph->minvol,
00696 ("%"PRIDX" %"PRIDX"\n", ComputeVolume(graph, where), graph->minvol));
00697
00698 }
00699