00001
00011 #include "metislib.h"
00012
00013
00014
00017
00018 void ComputeSubDomainGraph(ctrl_t *ctrl, graph_t *graph)
00019 {
00020 idx_t i, ii, j, pid, other, nparts, nvtxs, nnbrs;
00021 idx_t *xadj, *adjncy, *adjwgt, *where;
00022 idx_t *pptr, *pind;
00023 idx_t nads=0, *vadids, *vadwgts;
00024
00025 WCOREPUSH;
00026
00027 nvtxs = graph->nvtxs;
00028 xadj = graph->xadj;
00029 adjncy = graph->adjncy;
00030 adjwgt = graph->adjwgt;
00031 where = graph->where;
00032
00033 nparts = ctrl->nparts;
00034
00035 vadids = ctrl->pvec1;
00036 vadwgts = iset(nparts, 0, ctrl->pvec2);
00037
00038 pptr = iwspacemalloc(ctrl, nparts+1);
00039 pind = iwspacemalloc(ctrl, nvtxs);
00040 iarray2csr(nvtxs, nparts, where, pptr, pind);
00041
00042 for (pid=0; pid<nparts; pid++) {
00043 switch (ctrl->objtype) {
00044 case METIS_OBJTYPE_CUT:
00045 {
00046 ckrinfo_t *rinfo;
00047 cnbr_t *nbrs;
00048
00049 rinfo = graph->ckrinfo;
00050 for (nads=0, ii=pptr[pid]; ii<pptr[pid+1]; ii++) {
00051 i = pind[ii];
00052 ASSERT(pid == where[i]);
00053
00054 if (rinfo[i].ed > 0) {
00055 nnbrs = rinfo[i].nnbrs;
00056 nbrs = ctrl->cnbrpool + rinfo[i].inbr;
00057
00058 for (j=0; j<nnbrs; j++) {
00059 other = nbrs[j].pid;
00060 if (vadwgts[other] == 0)
00061 vadids[nads++] = other;
00062 vadwgts[other] += nbrs[j].ed;
00063 }
00064 }
00065 }
00066 }
00067 break;
00068
00069 case METIS_OBJTYPE_VOL:
00070 {
00071 vkrinfo_t *rinfo;
00072 vnbr_t *nbrs;
00073
00074 rinfo = graph->vkrinfo;
00075 for (nads=0, ii=pptr[pid]; ii<pptr[pid+1]; ii++) {
00076 i = pind[ii];
00077 ASSERT(pid == where[i]);
00078
00079 if (rinfo[i].ned > 0) {
00080 nnbrs = rinfo[i].nnbrs;
00081 nbrs = ctrl->vnbrpool + rinfo[i].inbr;
00082
00083 for (j=0; j<nnbrs; j++) {
00084 other = nbrs[j].pid;
00085 if (vadwgts[other] == 0)
00086 vadids[nads++] = other;
00087 vadwgts[other] += nbrs[j].ned;
00088 }
00089 }
00090 }
00091 }
00092 break;
00093
00094 default:
00095 gk_errexit(SIGERR, "Unknown objtype: %d\n", ctrl->objtype);
00096 }
00097
00098
00099 if (ctrl->maxnads[pid] < nads) {
00100 ctrl->maxnads[pid] = 2*nads;
00101 ctrl->adids[pid] = irealloc(ctrl->adids[pid], ctrl->maxnads[pid],
00102 "ComputeSubDomainGraph: adids[pid]");
00103 ctrl->adwgts[pid] = irealloc(ctrl->adwgts[pid], ctrl->maxnads[pid],
00104 "ComputeSubDomainGraph: adids[pid]");
00105 }
00106
00107 ctrl->nads[pid] = nads;
00108 for (j=0; j<nads; j++) {
00109 ctrl->adids[pid][j] = vadids[j];
00110 ctrl->adwgts[pid][j] = vadwgts[vadids[j]];
00111
00112 vadwgts[vadids[j]] = 0;
00113 }
00114 }
00115
00116 WCOREPOP;
00117 }
00118
00119
00120
00133
00134 void UpdateEdgeSubDomainGraph(ctrl_t *ctrl, idx_t u, idx_t v, idx_t ewgt,
00135 idx_t *r_maxndoms)
00136 {
00137 idx_t i, j, nads;
00138
00139 if (ewgt == 0)
00140 return;
00141
00142 for (i=0; i<2; i++) {
00143 nads = ctrl->nads[u];
00144
00145 for (j=0; j<nads; j++) {
00146 if (ctrl->adids[u][j] == v) {
00147 ctrl->adwgts[u][j] += ewgt;
00148 break;
00149 }
00150 }
00151
00152 if (j == nads) {
00153
00154 ASSERT(ewgt > 0);
00155 if (ctrl->maxnads[u] == nads) {
00156 ctrl->maxnads[u] = 2*(nads+1);
00157 ctrl->adids[u] = irealloc(ctrl->adids[u], ctrl->maxnads[u],
00158 "IncreaseEdgeSubDomainGraph: adids[pid]");
00159 ctrl->adwgts[u] = irealloc(ctrl->adwgts[u], ctrl->maxnads[u],
00160 "IncreaseEdgeSubDomainGraph: adids[pid]");
00161 }
00162 ctrl->adids[u][nads] = v;
00163 ctrl->adwgts[u][nads] = ewgt;
00164 nads++;
00165 if (r_maxndoms != NULL && nads > *r_maxndoms) {
00166 printf("You just increased the maxndoms: %"PRIDX" %"PRIDX"\n",
00167 nads, *r_maxndoms);
00168 *r_maxndoms = nads;
00169 }
00170 }
00171 else {
00172
00173 ASSERT(ctrl->adwgts[u][j] >= 0);
00174 if (ctrl->adwgts[u][j] == 0) {
00175 ctrl->adids[u][j] = ctrl->adids[u][nads-1];
00176 ctrl->adwgts[u][j] = ctrl->adwgts[u][nads-1];
00177 nads--;
00178 if (r_maxndoms != NULL && nads+1 == *r_maxndoms)
00179 *r_maxndoms = ctrl->nads[iargmax(ctrl->nparts, ctrl->nads)];
00180 }
00181 }
00182 ctrl->nads[u] = nads;
00183
00184 SWAP(u, v, j);
00185 }
00186 }
00187
00188
00189
00191
00192 void EliminateSubDomainEdges(ctrl_t *ctrl, graph_t *graph)
00193 {
00194 idx_t i, ii, j, k, ncon, nparts, scheme, pid_from, pid_to, me, other, nvtxs,
00195 total, max, avg, totalout, nind=0, ncand=0, ncand2, target, target2,
00196 nadd, bestnadd=0;
00197 idx_t min, move, *cpwgt;
00198 idx_t *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt,
00199 *mypmat, *otherpmat, *kpmat, *ind;
00200 idx_t *nads, **adids, **adwgts;
00201 ikv_t *cand, *cand2;
00202 ipq_t queue;
00203 real_t *tpwgts, badfactor=1.4;
00204 idx_t *pptr, *pind;
00205 idx_t *vmarker=NULL, *pmarker=NULL, *modind=NULL;
00206
00207 WCOREPUSH;
00208
00209 nvtxs = graph->nvtxs;
00210 ncon = graph->ncon;
00211 xadj = graph->xadj;
00212 adjncy = graph->adjncy;
00213 vwgt = graph->vwgt;
00214 adjwgt = (ctrl->objtype == METIS_OBJTYPE_VOL ? NULL : graph->adjwgt);
00215
00216 where = graph->where;
00217 pwgts = graph->pwgts;
00218
00219 nparts = ctrl->nparts;
00220 tpwgts = ctrl->tpwgts;
00221
00222 cpwgt = iwspacemalloc(ctrl, ncon);
00223 maxpwgt = iwspacemalloc(ctrl, nparts*ncon);
00224 ind = iwspacemalloc(ctrl, nvtxs);
00225 otherpmat = iset(nparts, 0, iwspacemalloc(ctrl, nparts));
00226
00227 cand = ikvwspacemalloc(ctrl, nparts);
00228 cand2 = ikvwspacemalloc(ctrl, nparts);
00229
00230 pptr = iwspacemalloc(ctrl, nparts+1);
00231 pind = iwspacemalloc(ctrl, nvtxs);
00232 iarray2csr(nvtxs, nparts, where, pptr, pind);
00233
00234 if (ctrl->objtype == METIS_OBJTYPE_VOL) {
00235
00236 modind = iwspacemalloc(ctrl, nvtxs);
00237 vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
00238 pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts));
00239 }
00240
00241
00242
00243 ComputeSubDomainGraph(ctrl, graph);
00244
00245 nads = ctrl->nads;
00246 adids = ctrl->adids;
00247 adwgts = ctrl->adwgts;
00248
00249 mypmat = iset(nparts, 0, ctrl->pvec1);
00250 kpmat = iset(nparts, 0, ctrl->pvec2);
00251
00252
00253 for (i=0; i<nparts; i++) {
00254 for (j=0; j<ncon; j++)
00255 maxpwgt[i*ncon+j] =
00256 (ncon == 1 ? 1.25 : 1.025)*tpwgts[i]*graph->tvwgt[j]*ctrl->ubfactors[j];
00257 }
00258
00259 ipqInit(&queue, nparts);
00260
00261
00262 while (1) {
00263 total = isum(nparts, nads, 1);
00264 avg = total/nparts;
00265 max = nads[iargmax(nparts, nads)];
00266
00267 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
00268 printf("Adjacent Subdomain Stats: Total: %3"PRIDX", "
00269 "Max: %3"PRIDX"[%zu], Avg: %3"PRIDX"\n",
00270 total, max, iargmax(nparts, nads), avg));
00271
00272 if (max < badfactor*avg)
00273 break;
00274
00275
00276 ipqReset(&queue);
00277 for (i=0; i<nparts; i++) {
00278 if (nads[i] >= avg + (max-avg)/2)
00279 ipqInsert(&queue, i, nads[i]);
00280 }
00281
00282 move = 0;
00283 while ((me = ipqGetTop(&queue)) != -1) {
00284 totalout = isum(nads[me], adwgts[me], 1);
00285
00286 for (ncand2=0, i=0; i<nads[me]; i++) {
00287 mypmat[adids[me][i]] = adwgts[me][i];
00288
00289
00290 if (2*nads[me]*adwgts[me][i] < totalout) {
00291 cand2[ncand2].val = adids[me][i];
00292 cand2[ncand2++].key = adwgts[me][i];
00293 }
00294 }
00295
00296 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
00297 printf("Me: %"PRIDX", Degree: %4"PRIDX", TotalOut: %"PRIDX",\n",
00298 me, nads[me], totalout));
00299
00300
00301 ikvsorti(ncand2, cand2);
00302
00303
00304
00305
00306
00307
00308
00309
00310 target = target2 = -1;
00311 for (scheme=0; scheme<2; scheme++) {
00312 for (min=0; min<ncand2; min++) {
00313 other = cand2[min].val;
00314
00315
00316
00317
00318 if (scheme == 0) {
00319 pid_from = other;
00320 pid_to = me;
00321 }
00322 else {
00323 pid_from = me;
00324 pid_to = other;
00325 }
00326
00327
00328 for (nind=0, ii=pptr[pid_from]; ii<pptr[pid_from+1]; ii++) {
00329 i = pind[ii];
00330 ASSERT(where[i] == pid_from);
00331 for (j=xadj[i]; j<xadj[i+1]; j++) {
00332 if (where[adjncy[j]] == pid_to) {
00333 ind[nind++] = i;
00334 break;
00335 }
00336 }
00337 }
00338
00339
00340
00341 iset(ncon, 0, cpwgt);
00342 for (ncand=0, ii=0; ii<nind; ii++) {
00343 i = ind[ii];
00344 iaxpy(ncon, 1, vwgt+i*ncon, 1, cpwgt, 1);
00345
00346 for (j=xadj[i]; j<xadj[i+1]; j++) {
00347 if ((k = where[adjncy[j]]) == pid_from)
00348 continue;
00349 if (otherpmat[k] == 0)
00350 cand[ncand++].val = k;
00351 otherpmat[k] += (adjwgt ? adjwgt[j] : 1);
00352 }
00353 }
00354
00355 for (i=0; i<ncand; i++) {
00356 cand[i].key = otherpmat[cand[i].val];
00357 ASSERT(cand[i].key > 0);
00358 }
00359
00360 ikvsortd(ncand, cand);
00361
00362 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
00363 printf("\tMinOut: %4"PRIDX", to: %3"PRIDX", TtlWgt: %5"PRIDX"[#:%"PRIDX"]\n",
00364 mypmat[other], other, isum(ncon, cpwgt, 1), nind));
00365
00366
00367
00368
00369 for (i=0; i<ncand; i++) {
00370 k = cand[i].val;
00371
00372 if (mypmat[k] > 0) {
00373
00374 if (!ivecaxpylez(ncon, 1, cpwgt, pwgts+k*ncon, maxpwgt+k*ncon))
00375 continue;
00376
00377
00378 for (j=0; j<nads[k]; j++)
00379 kpmat[adids[k][j]] = adwgts[k][j];
00380
00381
00382
00383
00384 for (j=0; j<nparts; j++) {
00385 if (otherpmat[j] > 0 && kpmat[j] == 0 && nads[j]+1 >= nads[me])
00386 break;
00387 }
00388
00389
00390
00391 if (j == nparts) {
00392 for (nadd=0, j=0; j<nparts; j++) {
00393 if (otherpmat[j] > 0 && kpmat[j] == 0)
00394 nadd++;
00395 }
00396
00397 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
00398 printf("\t\tto=%"PRIDX", nadd=%"PRIDX", %"PRIDX"\n", k, nadd, nads[k]));
00399
00400 if (nads[k]+nadd < nads[me]) {
00401 if (target2 == -1 || nads[target2]+bestnadd > nads[k]+nadd ||
00402 (nads[target2]+bestnadd == nads[k]+nadd && bestnadd > nadd)) {
00403 target2 = k;
00404 bestnadd = nadd;
00405 }
00406 }
00407
00408 if (nadd == 0)
00409 target = k;
00410 }
00411
00412
00413 for (j=0; j<nads[k]; j++)
00414 kpmat[adids[k][j]] = 0;
00415 }
00416
00417 if (target != -1)
00418 break;
00419 }
00420
00421
00422 for (i=0; i<ncand; i++)
00423 otherpmat[cand[i].val] = 0;
00424
00425 if (target == -1 && target2 != -1)
00426 target = target2;
00427
00428 if (target != -1) {
00429 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
00430 printf("\t\tScheme: %"PRIDX". Moving to %"PRIDX"\n", scheme, target));
00431 move = 1;
00432 break;
00433 }
00434 }
00435
00436 if (target != -1)
00437 break;
00438 }
00439
00440
00441 for (i=0; i<nads[me]; i++)
00442 mypmat[adids[me][i]] = 0;
00443
00444
00445
00446 if (target != -1) {
00447 switch (ctrl->objtype) {
00448 case METIS_OBJTYPE_CUT:
00449 MoveGroupMinConnForCut(ctrl, graph, target, nind, ind);
00450 break;
00451 case METIS_OBJTYPE_VOL:
00452 MoveGroupMinConnForVol(ctrl, graph, target, nind, ind, vmarker,
00453 pmarker, modind);
00454 break;
00455 default:
00456 gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype);
00457 }
00458
00459
00460 iarray2csr(nvtxs, nparts, where, pptr, pind);
00461 }
00462 }
00463
00464 if (move == 0)
00465 break;
00466 }
00467
00468 ipqFree(&queue);
00469
00470 WCOREPOP;
00471 }
00472
00473
00474
00476
00477 void MoveGroupMinConnForCut(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t nind,
00478 idx_t *ind)
00479 {
00480 idx_t i, ii, j, jj, k, l, nvtxs, nbnd, from, me;
00481 idx_t *xadj, *adjncy, *adjwgt, *where, *bndptr, *bndind;
00482 ckrinfo_t *myrinfo;
00483 cnbr_t *mynbrs;
00484
00485 nvtxs = graph->nvtxs;
00486 xadj = graph->xadj;
00487 adjncy = graph->adjncy;
00488 adjwgt = graph->adjwgt;
00489
00490 where = graph->where;
00491 bndptr = graph->bndptr;
00492 bndind = graph->bndind;
00493
00494 nbnd = graph->nbnd;
00495
00496 while (--nind>=0) {
00497 i = ind[nind];
00498 from = where[i];
00499
00500 myrinfo = graph->ckrinfo+i;
00501 if (myrinfo->inbr == -1) {
00502 myrinfo->inbr = cnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);
00503 myrinfo->nnbrs = 0;
00504 }
00505 mynbrs = ctrl->cnbrpool + myrinfo->inbr;
00506
00507
00508 for (k=0; k<myrinfo->nnbrs; k++) {
00509 if (mynbrs[k].pid == to)
00510 break;
00511 }
00512 if (k == myrinfo->nnbrs) {
00513 ASSERT(k < xadj[i+1]-xadj[i]);
00514 mynbrs[k].pid = to;
00515 mynbrs[k].ed = 0;
00516 myrinfo->nnbrs++;
00517 }
00518
00519
00520 iaxpy(graph->ncon, 1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon, 1);
00521 iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
00522
00523
00524 graph->mincut -= mynbrs[k].ed-myrinfo->id;
00525
00526
00527 UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->id-mynbrs[k].ed, NULL);
00528
00529
00530 UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where, nbnd,
00531 bndptr, bndind, BNDTYPE_REFINE);
00532
00533
00534 for (j=xadj[i]; j<xadj[i+1]; j++) {
00535 ii = adjncy[j];
00536 me = where[ii];
00537 myrinfo = graph->ckrinfo+ii;
00538
00539 UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me,
00540 from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, BNDTYPE_REFINE);
00541
00542
00543
00544 if (me != from && me != to) {
00545 UpdateEdgeSubDomainGraph(ctrl, from, me, -adjwgt[j], NULL);
00546 UpdateEdgeSubDomainGraph(ctrl, to, me, adjwgt[j], NULL);
00547 }
00548 }
00549 }
00550
00551 ASSERT(ComputeCut(graph, where) == graph->mincut);
00552
00553 graph->nbnd = nbnd;
00554
00555 }
00556
00557
00558
00560
00561 void MoveGroupMinConnForVol(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t nind,
00562 idx_t *ind, idx_t *vmarker, idx_t *pmarker, idx_t *modind)
00563 {
00564 idx_t i, ii, j, jj, k, l, nvtxs, from, me, other, xgain, ewgt;
00565 idx_t *xadj, *vsize, *adjncy, *where;
00566 vkrinfo_t *myrinfo, *orinfo;
00567 vnbr_t *mynbrs, *onbrs;
00568
00569 nvtxs = graph->nvtxs;
00570 xadj = graph->xadj;
00571 vsize = graph->vsize;
00572 adjncy = graph->adjncy;
00573 where = graph->where;
00574
00575 while (--nind>=0) {
00576 i = ind[nind];
00577 from = where[i];
00578
00579 myrinfo = graph->vkrinfo+i;
00580 if (myrinfo->inbr == -1) {
00581 myrinfo->inbr = vnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);
00582 myrinfo->nnbrs = 0;
00583 }
00584 mynbrs = ctrl->vnbrpool + myrinfo->inbr;
00585
00586 xgain = (myrinfo->nid == 0 && myrinfo->ned > 0 ? vsize[i] : 0);
00587
00588
00589
00590
00591
00592 for (k=0; k<myrinfo->nnbrs; k++) {
00593 if (mynbrs[k].pid == to)
00594 break;
00595 }
00596
00597 if (k == myrinfo->nnbrs) {
00598
00599
00600 if (myrinfo->nid > 0)
00601 xgain -= vsize[i];
00602
00603
00604 for (j=xadj[i]; j<xadj[i+1]; j++) {
00605 ii = adjncy[j];
00606 other = where[ii];
00607 orinfo = graph->vkrinfo+ii;
00608 onbrs = ctrl->vnbrpool + orinfo->inbr;
00609 ASSERT(other != to)
00610
00611
00612
00613 if (from == other) {
00614
00615 for (l=0; l<orinfo->nnbrs; l++) {
00616 if (onbrs[l].pid == to)
00617 break;
00618 }
00619 if (l == orinfo->nnbrs)
00620 xgain -= vsize[ii];
00621 }
00622 else {
00623
00624 for (l=0; l<orinfo->nnbrs; l++) {
00625 if (onbrs[l].pid == to)
00626 break;
00627 }
00628 if (l == orinfo->nnbrs)
00629 xgain -= vsize[ii];
00630
00631
00632 for (l=0; l<orinfo->nnbrs; l++) {
00633 if (onbrs[l].pid == from && onbrs[l].ned == 1) {
00634 xgain += vsize[ii];
00635 break;
00636 }
00637 }
00638 }
00639 }
00640 graph->minvol -= xgain;
00641 graph->mincut -= -myrinfo->nid;
00642 ewgt = myrinfo->nid;
00643 }
00644 else {
00645 graph->minvol -= (xgain + mynbrs[k].gv);
00646 graph->mincut -= mynbrs[k].ned-myrinfo->nid;
00647 ewgt = myrinfo->nid-mynbrs[k].ned;
00648 }
00649
00650
00651 where[i] = to;
00652 iaxpy(graph->ncon, 1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon, 1);
00653 iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
00654
00655
00656 UpdateEdgeSubDomainGraph(ctrl, from, to, ewgt, NULL);
00657
00658
00659 for (j=xadj[i]; j<xadj[i+1]; j++) {
00660 me = where[adjncy[j]];
00661 if (me != from && me != to) {
00662 UpdateEdgeSubDomainGraph(ctrl, from, me, -1, NULL);
00663 UpdateEdgeSubDomainGraph(ctrl, to, me, 1, NULL);
00664 }
00665 }
00666
00667
00668 KWayVolUpdate(ctrl, graph, i, from, to, NULL, NULL, NULL, NULL,
00669 NULL, BNDTYPE_REFINE, vmarker, pmarker, modind);
00670
00671
00672 }
00673 ASSERT(ComputeCut(graph, where) == graph->mincut);
00674 ASSERTP(ComputeVolume(graph, where) == graph->minvol,
00675 ("%"PRIDX" %"PRIDX"\n", ComputeVolume(graph, where), graph->minvol));
00676
00677 }
00678
00679
00680
00682
00683 void PrintSubDomainGraph(graph_t *graph, idx_t nparts, idx_t *where)
00684 {
00685 idx_t i, j, k, me, nvtxs, total, max;
00686 idx_t *xadj, *adjncy, *adjwgt, *pmat;
00687
00688 nvtxs = graph->nvtxs;
00689 xadj = graph->xadj;
00690 adjncy = graph->adjncy;
00691 adjwgt = graph->adjwgt;
00692
00693 pmat = ismalloc(nparts*nparts, 0, "ComputeSubDomainGraph: pmat");
00694
00695 for (i=0; i<nvtxs; i++) {
00696 me = where[i];
00697 for (j=xadj[i]; j<xadj[i+1]; j++) {
00698 k = adjncy[j];
00699 if (where[k] != me)
00700 pmat[me*nparts+where[k]] += adjwgt[j];
00701 }
00702 }
00703
00704
00705 total = max = 0;
00706 for (i=0; i<nparts; i++) {
00707 for (k=0, j=0; j<nparts; j++) {
00708 if (pmat[i*nparts+j] > 0)
00709 k++;
00710 }
00711 total += k;
00712
00713 if (k > max)
00714 max = k;
00715
00716
00717
00718
00719
00720
00721
00722
00723 }
00724 printf("Total adjacent subdomains: %"PRIDX", Max: %"PRIDX"\n", total, max);
00725
00726 gk_free((void **)&pmat, LTERM);
00727 }
00728
00729