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