Creation of OpenFOAM-dev repository 15/04/2008

This commit is contained in:
OpenFOAM-admin
2008-04-15 18:56:58 +01:00
commit 3170c7c0c9
9896 changed files with 4016171 additions and 0 deletions

View File

@ -0,0 +1,55 @@
coarsen.o
fm.o
initpart.o
match.o
ccgraph.o
pmetis.o
pqueue.o
refine.o
util.o
timing.o
debug.o
bucketsort.o
graph.o
stat.o
kmetis.o
kwayrefine.o
kwayfm.o
balance.o
ometis.o
srefine.o
sfm.o
separator.o
mincover.o
mmd.o
mesh.o
meshpart.o
frename.o
fortran.o
myqsort.o
compress.o
parmetis.o
estmem.o
mpmetis.o
mcoarsen.o
mmatch.o
minitpart.o
mbalance.o
mutil.o
mkmetis.o
mkwayrefine.o
mkwayfmh.o
mrefine2.o
minitpart2.o
mbalance2.o
mfm2.o
kvmetis.o
kwayvolrefine.o
kwayvolfm.o
subdomains.o
mfm.o
memory.o
mrefine.o
checkgraph.o
LIB = $(FOAM_MPI_LIBBIN)/libmetis-parmetis

View File

@ -0,0 +1,4 @@
include $(RULES)/mplib$(WM_MPLIB)
EXE_INC = $(PFLAGS) $(PINC)
LIB_LIBS = $(PLIBS)

View File

@ -0,0 +1,45 @@
include ../Makefile.in
CFLAGS = $(COPTIONS) $(OPTFLAGS) -I. $(INCDIR)
OBJS = coarsen.o fm.o initpart.o match.o ccgraph.o \
pmetis.o pqueue.o refine.o util.o timing.o debug.o \
bucketsort.o graph.o stat.o kmetis.o kwayrefine.o \
kwayfm.o balance.o ometis.o srefine.o sfm.o separator.o \
mincover.o mmd.o mesh.o meshpart.o frename.o fortran.o \
myqsort.o compress.o parmetis.o estmem.o \
mpmetis.o mcoarsen.o mmatch.o minitpart.o mbalance.o \
mutil.o mkmetis.o mkwayrefine.o mkwayfmh.o \
mrefine2.o minitpart2.o mbalance2.o mfm2.o \
kvmetis.o kwayvolrefine.o kwayvolfm.o subdomains.o \
mfm.o memory.o mrefine.o checkgraph.o
.c.o:
$(CC) $(CFLAGS) -c $*.c
../libmetis.a: $(OBJS)
$(AR) $@ $(OBJS)
$(RANLIB) $@
clean:
rm -f *.o
realclean:
rm -f *.o ; rm -f ../libmetis.a
checkin:
@for file in *.[c,h]; \
do \
ci -u -m'Maintance' $$file;\
done
checkin2:
@for file in *.[c,h]; \
do \
ci $$file;\
rcs -U $$file;\
co $$file;\
done

View File

@ -0,0 +1,127 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* checkgraph.c
*
* This file contains routines related to I/O
*
* Started 8/28/94
* George
*
* $Id: NEW_checkgraph.c,v 1.1 2003/07/16 15:55:13 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function checks if a graph is valid
**************************************************************************/
int CheckGraph(GraphType *graph)
{
int i, j, k, l;
int nvtxs, ncon, err=0;
int minedge, maxedge, minewgt, maxewgt;
float minvwgt[MAXNCON], maxvwgt[MAXNCON];
idxtype *xadj, *adjncy, *adjwgt, *htable;
float *nvwgt, ntvwgts[MAXNCON];
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
htable = idxsmalloc(nvtxs, 0, "htable");
if (ncon > 1) {
for (j=0; j<ncon; j++) {
minvwgt[j] = maxvwgt[j] = nvwgt[j];
ntvwgts[j] = 0.0;
}
}
minedge = maxedge = adjncy[0];
minewgt = maxewgt = adjwgt[0];
for (i=0; i<nvtxs; i++) {
if (ncon > 1) {
for (j=0; j<ncon; j++) {
ntvwgts[j] += nvwgt[i*ncon+j];
minvwgt[j] = (nvwgt[i*ncon+j] < minvwgt[j]) ? nvwgt[i*ncon+j] : minvwgt[j];
maxvwgt[j] = (nvwgt[i*ncon+j] > maxvwgt[j]) ? nvwgt[i*ncon+j] : maxvwgt[j];
}
}
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
minedge = (k < minedge) ? k : minedge;
maxedge = (k > maxedge) ? k : maxedge;
minewgt = (adjwgt[j] < minewgt) ? adjwgt[j] : minewgt;
maxewgt = (adjwgt[j] > maxewgt) ? adjwgt[j] : maxewgt;
if (i == k) {
printf("Vertex %d contains a self-loop (i.e., diagonal entry in the matrix)!\n", i);
err++;
}
else {
for (l=xadj[k]; l<xadj[k+1]; l++) {
if (adjncy[l] == i) {
if (adjwgt != NULL && adjwgt[l] != adjwgt[j]) {
printf("Edges (%d %d) and (%d %d) do not have the same weight! %d %d\n", i,k,k,i, adjwgt[l], adjwgt[j]);
err++;
}
break;
}
}
if (l == xadj[k+1]) {
printf("Missing edge: (%d %d)!\n", k, i);
err++;
}
}
if (htable[k] == 0) {
htable[k]++;
}
else {
printf("Edge %d from vertex %d is repeated %d times\n", k, i, htable[k]++);
err++;
}
}
for (j=xadj[i]; j<xadj[i+1]; j++) {
htable[adjncy[j]] = 0;
}
}
if (ncon > 1) {
for (j=0; j<ncon; j++) {
if (fabs(ntvwgts[j] - 1.0) > 0.0001) {
printf("Normalized vwgts don't sum to one. Weight %d = %.8f.\n", j, ntvwgts[j]);
err++;
}
}
}
/*
printf("errs: %d, adjncy: [%d %d], adjwgt: [%d %d]\n",
err, minedge, maxedge, minewgt, maxewgt);
if (ncon > 1) {
for (j=0; j<ncon; j++)
printf("[%.5f %.5f] ", minvwgt[j], maxvwgt[j]);
printf("\n");
}
*/
if (err > 0) {
printf("A total of %d errors exist in the input file. Correct them, and run again!\n", err);
}
GKfree(&htable, LTERM);
return (err == 0 ? 1 : 0);
}

View File

@ -0,0 +1,208 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* memory.c
*
* This file contains routines that deal with memory allocation
*
* Started 2/24/96
* George
*
* $Id: NEW_memory.c,v 1.1 2003/07/16 15:55:13 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function allocates memory for the workspace
**************************************************************************/
void AllocateWorkSpace(CtrlType *ctrl, GraphType *graph, int nparts)
{
ctrl->wspace.pmat = NULL;
if (ctrl->optype == OP_KMETIS) {
ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateWorkSpace: edegrees");
ctrl->wspace.vedegrees = NULL;
ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees;
ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat");
/* Memory requirements for different phases
Coarsening
Matching: 4*nvtxs vectors
Contraction: 2*nvtxs vectors (from the above 4), 1*nparts, 1*Nedges
Total = MAX(4*nvtxs, 2*nvtxs+nparts+nedges)
Refinement
Random Refinement/Balance: 5*nparts + 1*nvtxs + 2*nedges
Greedy Refinement/Balance: 5*nparts + 2*nvtxs + 2*nedges + 1*PQueue(==Nvtxs)
Total = 5*nparts + 3*nvtxs + 2*nedges
Total = 5*nparts + 3*nvtxs + 2*nedges
*/
ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */
5*(nparts+1) + /* Partition weights etc */
graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */
20 /* padding for 64 bit machines */
;
}
else if (ctrl->optype == OP_KVMETIS) {
ctrl->wspace.edegrees = NULL;
ctrl->wspace.vedegrees = (VEDegreeType *)GKmalloc(graph->nedges*sizeof(VEDegreeType), "AllocateWorkSpace: vedegrees");
ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.vedegrees;
ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat");
/* Memory requirements for different phases are identical to KMETIS */
ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */
3*(nparts+1) + /* Partition weights etc */
graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */
20 /* padding for 64 bit machines */
;
}
else {
ctrl->wspace.edegrees = (EDegreeType *)idxmalloc(graph->nedges, "AllocateWorkSpace: edegrees");
ctrl->wspace.vedegrees = NULL;
ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees;
ctrl->wspace.maxcore = 5*(graph->nvtxs+1) + /* Refinement vectors */
4*(nparts+1) + /* Partition weights etc */
2*graph->ncon*graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* 2-way refinement */
2*graph->ncon*(NEG_GAINSPAN+PLUS_GAINSPAN+1)*(sizeof(ListNodeType *)/sizeof(idxtype)) + /* 2-way refinement */
20 /* padding for 64 bit machines */
;
}
ctrl->wspace.maxcore += HTLENGTH;
ctrl->wspace.core = idxmalloc(ctrl->wspace.maxcore, "AllocateWorkSpace: maxcore");
ctrl->wspace.ccore = 0;
}
/*************************************************************************
* This function allocates memory for the workspace
**************************************************************************/
void FreeWorkSpace(CtrlType *ctrl, GraphType *graph)
{
GKfree(&ctrl->wspace.edegrees, &ctrl->wspace.vedegrees, &ctrl->wspace.core, &ctrl->wspace.pmat, LTERM);
}
/*************************************************************************
* This function returns how may words are left in the workspace
**************************************************************************/
int WspaceAvail(CtrlType *ctrl)
{
return ctrl->wspace.maxcore - ctrl->wspace.ccore;
}
/*************************************************************************
* This function allocate space from the core
**************************************************************************/
idxtype *idxwspacemalloc(CtrlType *ctrl, int n)
{
n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
ctrl->wspace.ccore += n;
ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore);
return ctrl->wspace.core + ctrl->wspace.ccore - n;
}
/*************************************************************************
* This function frees space from the core
**************************************************************************/
void idxwspacefree(CtrlType *ctrl, int n)
{
n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
ctrl->wspace.ccore -= n;
ASSERT(ctrl->wspace.ccore >= 0);
}
/*************************************************************************
* This function allocate space from the core
**************************************************************************/
float *fwspacemalloc(CtrlType *ctrl, int n)
{
n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
ctrl->wspace.ccore += n;
ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore);
return (float *) (ctrl->wspace.core + ctrl->wspace.ccore - n);
}
/*************************************************************************
* This function frees space from the core
**************************************************************************/
void fwspacefree(CtrlType *ctrl, int n)
{
n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
ctrl->wspace.ccore -= n;
ASSERT(ctrl->wspace.ccore >= 0);
}
/*************************************************************************
* This function creates a CoarseGraphType data structure and initializes
* the various fields
**************************************************************************/
GraphType *CreateGraph(void)
{
GraphType *graph;
graph = (GraphType *)GKmalloc(sizeof(GraphType), "CreateCoarseGraph: graph");
InitGraph(graph);
return graph;
}
/*************************************************************************
* This function creates a CoarseGraphType data structure and initializes
* the various fields
**************************************************************************/
void InitGraph(GraphType *graph)
{
graph->gdata = graph->rdata = NULL;
graph->nvtxs = graph->nedges = -1;
graph->mincut = graph->minvol = -1;
graph->xadj = graph->vwgt = graph->adjncy = graph->adjwgt = NULL;
graph->adjwgtsum = NULL;
graph->label = NULL;
graph->cmap = NULL;
graph->where = graph->pwgts = NULL;
graph->id = graph->ed = NULL;
graph->bndptr = graph->bndind = NULL;
graph->rinfo = NULL;
graph->vrinfo = NULL;
graph->nrinfo = NULL;
graph->ncon = -1;
graph->nvwgt = NULL;
graph->npwgts = NULL;
graph->vsize = NULL;
graph->coarser = graph->finer = NULL;
}
/*************************************************************************
* This function deallocates any memory stored in a graph
**************************************************************************/
void FreeGraph(GraphType *graph)
{
GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->npwgts, LTERM);
free(graph);
}

View File

@ -0,0 +1,341 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mfm.c
*
* This file contains code that implements the edge-based FM refinement
*
* Started 7/23/97
* George
*
* $Id: NEW_mfm.c,v 1.1 2003/07/16 15:55:13 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function performs an edge-based FM refinement
**************************************************************************/
void MocFM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, float *tpwgts, int npasses)
{
int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum;
idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
idxtype *moved, *swaps, *perm, *qnum;
float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal;
PQueueType parts[MAXNCON][2];
int higain, oldgain, mincut, initcut, newcut, mincutorder;
float rtpwgts[2];
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
npwgts = graph->npwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
moved = idxwspacemalloc(ctrl, nvtxs);
swaps = idxwspacemalloc(ctrl, nvtxs);
perm = idxwspacemalloc(ctrl, nvtxs);
qnum = idxwspacemalloc(ctrl, nvtxs);
limit = amin(amax(0.01*nvtxs, 25), 150);
/* Initialize the queues */
for (i=0; i<ncon; i++) {
PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
}
for (i=0; i<nvtxs; i++)
qnum[i] = samax(ncon, nvwgt+i*ncon);
origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
rtpwgts[0] = origbal*tpwgts[0];
rtpwgts[1] = origbal*tpwgts[1];
if (ctrl->dbglvl&DBG_REFINE) {
printf("Parts: [");
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal);
}
idxset(nvtxs, -1, moved);
for (pass=0; pass<npasses; pass++) { /* Do a number of passes */
for (i=0; i<ncon; i++) {
PQueueReset(&parts[i][0]);
PQueueReset(&parts[i][1]);
}
mincutorder = -1;
newcut = mincut = initcut = graph->mincut;
for (i=0; i<ncon; i++)
mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
minbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
/* Insert boundary nodes in the priority queues */
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (ii=0; ii<nbnd; ii++) {
i = bndind[perm[ii]];
ASSERT(ed[i] > 0 || id[i] == 0);
ASSERT(bndptr[i] != -1);
PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]);
}
for (nswaps=0; nswaps<nvtxs; nswaps++) {
SelectQueue(ncon, npwgts, rtpwgts, &from, &cnum, parts);
to = (from+1)%2;
if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1)
break;
ASSERT(bndptr[higain] != -1);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
newcut -= (ed[higain]-id[higain]);
newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
if ((newcut < mincut && newbal-origbal <= .00001) ||
(newcut == mincut && (newbal < minbal ||
(newbal == minbal && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) {
mincut = newcut;
minbal = newbal;
mincutorder = nswaps;
for (i=0; i<ncon; i++)
mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
}
else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
newcut += (ed[higain]-id[higain]);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
break;
}
where[higain] = to;
moved[higain] = nswaps;
swaps[nswaps] = higain;
if (ctrl->dbglvl&DBG_MOVEINFO) {
printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf(", %.3f LB: %.3f\n", minbal, 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];
oldgain = ed[k]-id[k];
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 */
PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain);
}
else { /* If it has not been moved, update its position in the queue */
if (moved[k] == -1)
PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]);
}
}
else {
if (ed[k] > 0) { /* It will now become a boundary vertex */
BNDInsert(nbnd, bndind, bndptr, k);
if (moved[k] == -1)
PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]);
}
}
}
}
/****************************************************************
* 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);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((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);
}
}
if (ctrl->dbglvl&DBG_REFINE) {
printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
}
graph->mincut = mincut;
graph->nbnd = nbnd;
if (mincutorder == -1 || mincut == initcut)
break;
}
for (i=0; i<ncon; i++) {
PQueueFree(ctrl, &parts[i][0]);
PQueueFree(ctrl, &parts[i][1]);
}
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function selects the partition number and the queue from which
* we will move vertices out
**************************************************************************/
void SelectQueue(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, PQueueType queues[MAXNCON][2])
{
int i, part, maxgain=0;
float max, maxdiff=0.0;
*from = -1;
*cnum = -1;
/* First determine the side and the queue, irrespective of the presence of nodes */
for (part=0; part<2; part++) {
for (i=0; i<ncon; i++) {
if (npwgts[part*ncon+i]-tpwgts[part] >= maxdiff) {
maxdiff = npwgts[part*ncon+i]-tpwgts[part];
*from = part;
*cnum = i;
}
}
}
/* printf("Selected %d(%d) -> %d\n", *from, *cnum, PQueueGetSize(&queues[*cnum][*from])); */
if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) {
/* The desired queue is empty, select a node from that side anyway */
for (i=0; i<ncon; i++) {
if (PQueueGetSize(&queues[i][*from]) > 0) {
max = npwgts[(*from)*ncon + i];
*cnum = i;
break;
}
}
for (i++; i<ncon; i++) {
if (npwgts[(*from)*ncon + i] > max && PQueueGetSize(&queues[i][*from]) > 0) {
max = npwgts[(*from)*ncon + i];
*cnum = i;
}
}
}
/* Check to see if you can focus on the cut */
if (maxdiff <= 0.0 || *from == -1) {
maxgain = -100000;
for (part=0; part<2; part++) {
for (i=0; i<ncon; i++) {
if (PQueueGetSize(&queues[i][part]) > 0 && PQueueGetKey(&queues[i][part]) > maxgain) {
maxgain = PQueueGetKey(&queues[i][part]);
*from = part;
*cnum = i;
}
}
}
}
}
/*************************************************************************
* This function checks if the balance achieved is better than the diff
* For now, it uses a 2-norm measure
**************************************************************************/
int BetterBalance(int ncon, float *npwgts, float *tpwgts, float *diff)
{
int i;
float ndiff[MAXNCON];
for (i=0; i<ncon; i++)
ndiff[i] = fabs(tpwgts[0]-npwgts[i]);
return snorm2(ncon, ndiff) < snorm2(ncon, diff);
}
/*************************************************************************
* This function computes the load imbalance over all the constrains
**************************************************************************/
float Compute2WayHLoadImbalance(int ncon, float *npwgts, float *tpwgts)
{
int i;
float max=0.0, temp;
for (i=0; i<ncon; i++) {
/* temp = amax(npwgts[i]/tpwgts[0], npwgts[ncon+i]/tpwgts[1]); */
temp = fabs(tpwgts[0]-npwgts[i])/tpwgts[0];
max = (max < temp ? temp : max);
}
return 1.0+max;
}
/*************************************************************************
* This function computes the load imbalance over all the constrains
* For now assume that we just want balanced partitionings
**************************************************************************/
void Compute2WayHLoadImbalanceVec(int ncon, float *npwgts, float *tpwgts, float *lbvec)
{
int i;
for (i=0; i<ncon; i++)
lbvec[i] = 1.0 + fabs(tpwgts[0]-npwgts[i])/tpwgts[0];
}

View File

@ -0,0 +1,219 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* refine.c
*
* This file contains the driving routines for multilevel refinement
*
* Started 7/24/97
* George
*
* $Id: NEW_mrefine.c,v 1.1 2003/07/16 15:55:14 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of refinement
**************************************************************************/
void MocRefine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, float ubfactor)
{
int i;
float tubvec[MAXNCON];
for (i=0; i<graph->ncon; i++)
tubvec[i] = 1.0;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
/* Compute the parameters of the coarsest graph */
MocCompute2WayPartitionParams(ctrl, graph);
for (;;) {
ASSERT(CheckBnd(graph));
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
switch (ctrl->RType) {
case RTYPE_FM:
MocBalance2Way(ctrl, graph, tpwgts, 1.03);
MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8);
break;
case 2:
MocBalance2Way(ctrl, graph, tpwgts, 1.03);
MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, tubvec, 8);
break;
default:
errexit("Unknown refinement type: %d\n", ctrl->RType);
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
if (graph == orggraph)
break;
graph = graph->finer;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
MocProject2WayPartition(ctrl, graph);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
}
MocBalance2Way(ctrl, graph, tpwgts, 1.01);
MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
}
/*************************************************************************
* This function allocates memory for 2-way edge refinement
**************************************************************************/
void MocAllocate2WayPartitionMemory(CtrlType *ctrl, GraphType *graph)
{
int nvtxs, ncon;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
graph->rdata = idxmalloc(5*nvtxs, "Allocate2WayPartitionMemory: rdata");
graph->where = graph->rdata;
graph->id = graph->rdata + nvtxs;
graph->ed = graph->rdata + 2*nvtxs;
graph->bndptr = graph->rdata + 3*nvtxs;
graph->bndind = graph->rdata + 4*nvtxs;
graph->npwgts = fmalloc(2*ncon, "npwgts");
}
/*************************************************************************
* This function computes the initial id/ed
**************************************************************************/
void MocCompute2WayPartitionParams(CtrlType *ctrl, GraphType *graph)
{
int i, j, k, l, nvtxs, ncon, nbnd, mincut;
idxtype *xadj, *adjncy, *adjwgt;
float *nvwgt, *npwgts;
idxtype *id, *ed, *where;
idxtype *bndptr, *bndind;
int me, other;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
npwgts = sset(2*ncon, 0.0, graph->npwgts);
id = idxset(nvtxs, 0, graph->id);
ed = idxset(nvtxs, 0, graph->ed);
bndptr = idxset(nvtxs, -1, graph->bndptr);
bndind = graph->bndind;
/*------------------------------------------------------------
/ Compute now the id/ed degrees
/------------------------------------------------------------*/
nbnd = mincut = 0;
for (i=0; i<nvtxs; i++) {
ASSERT(where[i] >= 0 && where[i] <= 1);
me = where[i];
saxpy(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1);
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (me == where[adjncy[j]])
id[i] += adjwgt[j];
else
ed[i] += adjwgt[j];
}
if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
mincut += ed[i];
bndptr[i] = nbnd;
bndind[nbnd++] = i;
}
}
graph->mincut = mincut/2;
graph->nbnd = nbnd;
}
/*************************************************************************
* This function projects a partition, and at the same time computes the
* parameters for refinement.
**************************************************************************/
void MocProject2WayPartition(CtrlType *ctrl, GraphType *graph)
{
int i, j, k, nvtxs, nbnd, me;
idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
idxtype *cmap, *where, *id, *ed, *bndptr, *bndind;
idxtype *cwhere, *cid, *ced, *cbndptr;
GraphType *cgraph;
cgraph = graph->coarser;
cwhere = cgraph->where;
cid = cgraph->id;
ced = cgraph->ed;
cbndptr = cgraph->bndptr;
nvtxs = graph->nvtxs;
cmap = graph->cmap;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
MocAllocate2WayPartitionMemory(ctrl, graph);
where = graph->where;
id = idxset(nvtxs, 0, graph->id);
ed = idxset(nvtxs, 0, graph->ed);
bndptr = idxset(nvtxs, -1, graph->bndptr);
bndind = graph->bndind;
/* Go through and project partition and compute id/ed for the nodes */
for (i=0; i<nvtxs; i++) {
k = cmap[i];
where[i] = cwhere[k];
cmap[i] = cbndptr[k];
}
for (nbnd=0, i=0; i<nvtxs; i++) {
me = where[i];
id[i] = adjwgtsum[i];
if (xadj[i] == xadj[i+1]) {
bndptr[i] = nbnd;
bndind[nbnd++] = i;
}
else {
if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (me != where[adjncy[j]])
ed[i] += adjwgt[j];
}
id[i] -= ed[i];
if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
bndptr[i] = nbnd;
bndind[nbnd++] = i;
}
}
}
}
graph->mincut = cgraph->mincut;
graph->nbnd = nbnd;
scopy(2*graph->ncon, cgraph->npwgts, graph->npwgts);
FreeGraph(graph->coarser);
graph->coarser = NULL;
}

View File

@ -0,0 +1,155 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* parmetis.c
*
* This file contains the top level routines for the multilevel recursive
* bisection algorithm PMETIS.
*
* Started 7/24/97
* George
*
* $Id: NEW_parmetis.c,v 1.1 2003/07/16 15:55:14 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point for PWMETIS that accepts exact weights
* for the target partitions
**************************************************************************/
void METIS_mCPartGraphRecursive2(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
float *tpwgts, int *options, int *edgecut, idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
float *mytpwgts;
idxtype wgt[2048], minwgt, maxwgt, sumwgt;
float avgwgt;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag);
graph.npwgts = NULL;
mytpwgts = fmalloc(*nparts, "mytpwgts");
scopy(*nparts, tpwgts, mytpwgts);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = McPMETIS_CTYPE;
ctrl.IType = McPMETIS_ITYPE;
ctrl.RType = McPMETIS_RTYPE;
ctrl.dbglvl = McPMETIS_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_PMETIS;
ctrl.CoarsenTo = 100;
ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
InitRandom(options[7]);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
ASSERT(CheckGraph(&graph));
*edgecut = MCMlevelRecursiveBisection2(&ctrl, &graph, *nparts, mytpwgts, part, 1.000, 0);
/*
printf("nvtxs: %d, nparts: %d, ncon: %d\n", graph.nvtxs, *nparts, *ncon);
for (i=0; i<(*nparts)*(*ncon); i++)
wgt[i] = 0;
for (i=0; i<graph.nvtxs; i++)
for (j=0; j<*ncon; j++)
wgt[part[i]*(*ncon)+j] += vwgt[i*(*ncon)+j];
for (j=0; j<*ncon; j++) {
minwgt = maxwgt = sumwgt = 0;
for (i=0; i<(*nparts); i++) {
minwgt = (wgt[i*(*ncon)+j] < wgt[minwgt*(*ncon)+j]) ? i : minwgt;
maxwgt = (wgt[i*(*ncon)+j] > wgt[maxwgt*(*ncon)+j]) ? i : maxwgt;
sumwgt += wgt[i*(*ncon)+j];
}
avgwgt = (float)sumwgt / (float)*nparts;
printf("min: %5d, max: %5d, avg: %5.2f, balance: %6.3f\n", wgt[minwgt*(*ncon)+j], wgt[maxwgt*(*ncon)+j], avgwgt, (float)wgt[maxwgt*(*ncon)+j] / avgwgt);
}
printf("\n");
*/
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
GKfree((void *)&mytpwgts, LTERM);
if (*numflag == 1)
Change2FNumbering(*nvtxs, xadj, adjncy, part);
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
int MCMlevelRecursiveBisection2(CtrlType *ctrl, GraphType *graph, int nparts,
float *tpwgts, idxtype *part, float ubfactor, int fpart)
{
int i, nvtxs, cut;
float wsum, tpwgts2[2];
idxtype *label, *where;
GraphType lgraph, rgraph;
nvtxs = graph->nvtxs;
if (nvtxs == 0) {
/* printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n"); */
return 0;
}
/* Determine the weights of the partitions */
tpwgts2[0] = ssum(nparts/2, tpwgts);
tpwgts2[1] = 1.0-tpwgts2[0];
MCMlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor);
cut = graph->mincut;
label = graph->label;
where = graph->where;
for (i=0; i<nvtxs; i++)
part[label[i]] = where[i] + fpart;
if (nparts > 2)
SplitGraphPart(ctrl, graph, &lgraph, &rgraph);
/* Free the memory of the top level graph */
GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->label, &graph->npwgts, LTERM);
/* Scale the fractions in the tpwgts according to the true weight */
wsum = ssum(nparts/2, tpwgts);
sscale(nparts/2, 1.0/wsum, tpwgts);
sscale(nparts-nparts/2, 1.0/(1.0-wsum), tpwgts+nparts/2);
/* Do the recursive call */
if (nparts > 3) {
cut += MCMlevelRecursiveBisection2(ctrl, &lgraph, nparts/2, tpwgts, part, ubfactor, fpart);
cut += MCMlevelRecursiveBisection2(ctrl, &rgraph, nparts-nparts/2, tpwgts+nparts/2, part, ubfactor, fpart+nparts/2);
}
else if (nparts == 3) {
cut += MCMlevelRecursiveBisection2(ctrl, &rgraph, nparts-nparts/2, tpwgts+nparts/2, part, ubfactor, fpart+nparts/2);
GKfree(&lgraph.gdata, &lgraph.nvwgt, &lgraph.label, LTERM);
}
return cut;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* stat.c
*
* This file computes various statistics
*
* Started 7/25/97
* George
*
* $Id: NEW_stats.c,v 1.1 2003/07/16 15:55:15 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function computes the balance of the partitioning
**************************************************************************/
void Moc_ComputePartitionBalance(GraphType *graph, int nparts, idxtype *where, float *ubvec)
{
int i, j, nvtxs, ncon;
float *kpwgts, *nvwgt;
float balance;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
nvwgt = graph->nvwgt;
kpwgts = fmalloc(nparts, "ComputePartitionInfo: kpwgts");
for (j=0; j<ncon; j++) {
sset(nparts, 0.0, kpwgts);
for (i=0; i<graph->nvtxs; i++)
kpwgts[where[i]] += nvwgt[i*ncon+j];
ubvec[j] = (float)nparts*kpwgts[samax(nparts, kpwgts)]/ssum(nparts, kpwgts);
}
free(kpwgts);
}

View File

@ -0,0 +1,278 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* balance.c
*
* This file contains code that is used to forcefully balance either
* bisections or k-sections
*
* Started 7/29/97
* George
*
* $Id: balance.c,v 1.1 2003/07/16 15:54:58 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of the bisection balancing algorithms.
**************************************************************************/
void Balance2Way(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
{
int i, j, nvtxs, from, imax, gain, mindiff;
idxtype *id, *ed;
/* Return right away if the balance is OK */
mindiff = abs(tpwgts[0]-graph->pwgts[0]);
if (mindiff < 3*(graph->pwgts[0]+graph->pwgts[1])/graph->nvtxs)
return;
if (graph->pwgts[0] > tpwgts[0] && graph->pwgts[0] < (int)(ubfactor*tpwgts[0]))
return;
if (graph->pwgts[1] > tpwgts[1] && graph->pwgts[1] < (int)(ubfactor*tpwgts[1]))
return;
if (graph->nbnd > 0)
Bnd2WayBalance(ctrl, graph, tpwgts);
else
General2WayBalance(ctrl, graph, tpwgts);
}
/*************************************************************************
* This function balances two partitions by moving boundary nodes
* from the domain that is overweight to the one that is underweight.
**************************************************************************/
void Bnd2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts)
{
int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, tmp;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts;
idxtype *moved, *perm;
PQueueType parts;
int higain, oldgain, mincut, mindiff;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
pwgts = graph->pwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
moved = idxwspacemalloc(ctrl, nvtxs);
perm = idxwspacemalloc(ctrl, nvtxs);
/* Determine from which domain you will be moving data */
mindiff = abs(tpwgts[0]-pwgts[0]);
from = (pwgts[0] < tpwgts[0] ? 1 : 0);
to = (from+1)%2;
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d [B]\n",
pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)];
PQueueInit(ctrl, &parts, nvtxs, tmp);
idxset(nvtxs, -1, moved);
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
/* Insert the boundary nodes of the proper partition whose size is OK in the priority queue */
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (ii=0; ii<nbnd; ii++) {
i = perm[ii];
ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0);
ASSERT(bndptr[bndind[i]] != -1);
if (where[bndind[i]] == from && vwgt[bndind[i]] <= mindiff)
PQueueInsert(&parts, bndind[i], ed[bndind[i]]-id[bndind[i]]);
}
mincut = graph->mincut;
for (nswaps=0; nswaps<nvtxs; nswaps++) {
if ((higain = PQueueGetMax(&parts)) == -1)
break;
ASSERT(bndptr[higain] != -1);
if (pwgts[to]+vwgt[higain] > tpwgts[to])
break;
mincut -= (ed[higain]-id[higain]);
INC_DEC(pwgts[to], pwgts[from], vwgt[higain]);
where[higain] = to;
moved[higain] = nswaps;
IFSET(ctrl->dbglvl, DBG_MOVEINFO,
printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], mincut, pwgts[0], pwgts[1]));
/**************************************************************
* 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];
oldgain = ed[k]-id[k];
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 && where[k] == from && vwgt[k] <= mindiff) /* Remove it if in the queues */
PQueueDelete(&parts, k, oldgain);
}
else { /* If it has not been moved, update its position in the queue */
if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff)
PQueueUpdate(&parts, k, oldgain, ed[k]-id[k]);
}
}
else {
if (ed[k] > 0) { /* It will now become a boundary vertex */
BNDInsert(nbnd, bndind, bndptr, k);
if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff)
PQueueInsert(&parts, k, ed[k]-id[k]);
}
}
}
}
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("\tMinimum cut: %6d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, pwgts[0], pwgts[1], nbnd));
graph->mincut = mincut;
graph->nbnd = nbnd;
PQueueFree(ctrl, &parts);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function balances two partitions by moving the highest gain
* (including negative gain) vertices to the other domain.
* It is used only when tha unbalance is due to non contigous
* subdomains. That is, the are no boundary vertices.
* It moves vertices from the domain that is overweight to the one that
* is underweight.
**************************************************************************/
void General2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts)
{
int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, tmp;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts;
idxtype *moved, *perm;
PQueueType parts;
int higain, oldgain, mincut, mindiff;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
pwgts = graph->pwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
moved = idxwspacemalloc(ctrl, nvtxs);
perm = idxwspacemalloc(ctrl, nvtxs);
/* Determine from which domain you will be moving data */
mindiff = abs(tpwgts[0]-pwgts[0]);
from = (pwgts[0] < tpwgts[0] ? 1 : 0);
to = (from+1)%2;
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d [B]\n",
pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)];
PQueueInit(ctrl, &parts, nvtxs, tmp);
idxset(nvtxs, -1, moved);
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
/* Insert the nodes of the proper partition whose size is OK in the priority queue */
RandomPermute(nvtxs, perm, 1);
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (where[i] == from && vwgt[i] <= mindiff)
PQueueInsert(&parts, i, ed[i]-id[i]);
}
mincut = graph->mincut;
nbnd = graph->nbnd;
for (nswaps=0; nswaps<nvtxs; nswaps++) {
if ((higain = PQueueGetMax(&parts)) == -1)
break;
if (pwgts[to]+vwgt[higain] > tpwgts[to])
break;
mincut -= (ed[higain]-id[higain]);
INC_DEC(pwgts[to], pwgts[from], vwgt[higain]);
where[higain] = to;
moved[higain] = nswaps;
IFSET(ctrl->dbglvl, DBG_MOVEINFO,
printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], mincut, pwgts[0], pwgts[1]));
/**************************************************************
* Update the id[i]/ed[i] values of the affected nodes
***************************************************************/
SWAP(id[higain], ed[higain], tmp);
if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
BNDDelete(nbnd, bndind, bndptr, higain);
if (ed[higain] > 0 && bndptr[higain] == -1)
BNDInsert(nbnd, bndind, bndptr, higain);
for (j=xadj[higain]; j<xadj[higain+1]; j++) {
k = adjncy[j];
oldgain = ed[k]-id[k];
kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
INC_DEC(id[k], ed[k], kwgt);
/* Update the queue position */
if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff)
PQueueUpdate(&parts, k, oldgain, ed[k]-id[k]);
/* Update its boundary information */
if (ed[k] == 0 && bndptr[k] != -1)
BNDDelete(nbnd, bndind, bndptr, k);
else if (ed[k] > 0 && bndptr[k] == -1)
BNDInsert(nbnd, bndind, bndptr, k);
}
}
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("\tMinimum cut: %6d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, pwgts[0], pwgts[1], nbnd));
graph->mincut = mincut;
graph->nbnd = nbnd;
PQueueFree(ctrl, &parts);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* bucketsort.c
*
* This file contains code that implement a variety of counting sorting
* algorithms
*
* Started 7/25/97
* George
*
* $Id: bucketsort.c,v 1.1 2003/07/16 15:55:00 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function uses simple counting sort to return a permutation array
* corresponding to the sorted order. The keys are assumed to start from
* 0 and they are positive. This sorting is used during matching.
**************************************************************************/
void BucketSortKeysInc(int n, int max, idxtype *keys, idxtype *tperm, idxtype *perm)
{
int i, ii;
idxtype *counts;
counts = idxsmalloc(max+2, 0, "BucketSortKeysInc: counts");
for (i=0; i<n; i++)
counts[keys[i]]++;
MAKECSR(i, max+1, counts);
for (ii=0; ii<n; ii++) {
i = tperm[ii];
perm[counts[keys[i]]++] = i;
}
free(counts);
}

View File

@ -0,0 +1,599 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* ccgraph.c
*
* This file contains the functions that create the coarse graph
*
* Started 8/11/97
* George
*
* $Id: ccgraph.c,v 1.1 2003/07/16 15:55:00 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function creates the coarser graph
**************************************************************************/
void CreateCoarseGraph(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm)
{
int i, j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, mask, dovsize;
idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *adjwgtsum, *auxadj;
idxtype *cmap, *htable;
idxtype *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt, *cadjwgtsum;
float *nvwgt, *cnvwgt;
GraphType *cgraph;
dovsize = (ctrl->optype == OP_KVMETIS ? 1 : 0);
mask = HTLENGTH;
if (cnvtxs < 8*mask || graph->nedges/graph->nvtxs > 15) {
CreateCoarseGraphNoMask(ctrl, graph, cnvtxs, match, perm);
return;
}
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr));
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
vwgt = graph->vwgt;
vsize = graph->vsize;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
cmap = graph->cmap;
/* Initialize the coarser graph */
cgraph = SetUpCoarseGraph(graph, cnvtxs, dovsize);
cxadj = cgraph->xadj;
cvwgt = cgraph->vwgt;
cvsize = cgraph->vsize;
cnvwgt = cgraph->nvwgt;
cadjwgtsum = cgraph->adjwgtsum;
cadjncy = cgraph->adjncy;
cadjwgt = cgraph->adjwgt;
iend = xadj[nvtxs];
auxadj = ctrl->wspace.auxcore;
memcpy(auxadj, adjncy, iend*sizeof(idxtype));
for (i=0; i<iend; i++)
auxadj[i] = cmap[auxadj[i]];
htable = idxset(mask+1, -1, idxwspacemalloc(ctrl, mask+1));
cxadj[0] = cnvtxs = cnedges = 0;
for (i=0; i<nvtxs; i++) {
v = perm[i];
if (cmap[v] != cnvtxs)
continue;
u = match[v];
if (ncon == 1)
cvwgt[cnvtxs] = vwgt[v];
else
scopy(ncon, nvwgt+v*ncon, cnvwgt+cnvtxs*ncon);
if (dovsize)
cvsize[cnvtxs] = vsize[v];
cadjwgtsum[cnvtxs] = adjwgtsum[v];
nedges = 0;
istart = xadj[v];
iend = xadj[v+1];
for (j=istart; j<iend; j++) {
k = auxadj[j];
kk = k&mask;
if ((m = htable[kk]) == -1) {
cadjncy[nedges] = k;
cadjwgt[nedges] = adjwgt[j];
htable[kk] = nedges++;
}
else if (cadjncy[m] == k) {
cadjwgt[m] += adjwgt[j];
}
else {
for (jj=0; jj<nedges; jj++) {
if (cadjncy[jj] == k) {
cadjwgt[jj] += adjwgt[j];
break;
}
}
if (jj == nedges) {
cadjncy[nedges] = k;
cadjwgt[nedges++] = adjwgt[j];
}
}
}
if (v != u) {
if (ncon == 1)
cvwgt[cnvtxs] += vwgt[u];
else
saxpy(ncon, 1.0, nvwgt+u*ncon, 1, cnvwgt+cnvtxs*ncon, 1);
if (dovsize)
cvsize[cnvtxs] += vsize[u];
cadjwgtsum[cnvtxs] += adjwgtsum[u];
istart = xadj[u];
iend = xadj[u+1];
for (j=istart; j<iend; j++) {
k = auxadj[j];
kk = k&mask;
if ((m = htable[kk]) == -1) {
cadjncy[nedges] = k;
cadjwgt[nedges] = adjwgt[j];
htable[kk] = nedges++;
}
else if (cadjncy[m] == k) {
cadjwgt[m] += adjwgt[j];
}
else {
for (jj=0; jj<nedges; jj++) {
if (cadjncy[jj] == k) {
cadjwgt[jj] += adjwgt[j];
break;
}
}
if (jj == nedges) {
cadjncy[nedges] = k;
cadjwgt[nedges++] = adjwgt[j];
}
}
}
/* Remove the contracted adjacency weight */
jj = htable[cnvtxs&mask];
if (jj >= 0 && cadjncy[jj] != cnvtxs) {
for (jj=0; jj<nedges; jj++) {
if (cadjncy[jj] == cnvtxs)
break;
}
}
if (jj >= 0 && cadjncy[jj] == cnvtxs) { /* This 2nd check is needed for non-adjacent matchings */
cadjwgtsum[cnvtxs] -= cadjwgt[jj];
cadjncy[jj] = cadjncy[--nedges];
cadjwgt[jj] = cadjwgt[nedges];
}
}
ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d %d %d %d\n", cnvtxs, cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt), adjwgtsum[u], adjwgtsum[v]));
for (j=0; j<nedges; j++)
htable[cadjncy[j]&mask] = -1; /* Zero out the htable */
htable[cnvtxs&mask] = -1;
cnedges += nedges;
cxadj[++cnvtxs] = cnedges;
cadjncy += nedges;
cadjwgt += nedges;
}
cgraph->nedges = cnedges;
ReAdjustMemory(graph, cgraph, dovsize);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr));
idxwspacefree(ctrl, mask+1);
}
/*************************************************************************
* This function creates the coarser graph
**************************************************************************/
void CreateCoarseGraphNoMask(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm)
{
int i, j, k, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, dovsize;
idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *adjwgtsum, *auxadj;
idxtype *cmap, *htable;
idxtype *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt, *cadjwgtsum;
float *nvwgt, *cnvwgt;
GraphType *cgraph;
dovsize = (ctrl->optype == OP_KVMETIS ? 1 : 0);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr));
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
vwgt = graph->vwgt;
vsize = graph->vsize;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
cmap = graph->cmap;
/* Initialize the coarser graph */
cgraph = SetUpCoarseGraph(graph, cnvtxs, dovsize);
cxadj = cgraph->xadj;
cvwgt = cgraph->vwgt;
cvsize = cgraph->vsize;
cnvwgt = cgraph->nvwgt;
cadjwgtsum = cgraph->adjwgtsum;
cadjncy = cgraph->adjncy;
cadjwgt = cgraph->adjwgt;
htable = idxset(cnvtxs, -1, idxwspacemalloc(ctrl, cnvtxs));
iend = xadj[nvtxs];
auxadj = ctrl->wspace.auxcore;
memcpy(auxadj, adjncy, iend*sizeof(idxtype));
for (i=0; i<iend; i++)
auxadj[i] = cmap[auxadj[i]];
cxadj[0] = cnvtxs = cnedges = 0;
for (i=0; i<nvtxs; i++) {
v = perm[i];
if (cmap[v] != cnvtxs)
continue;
u = match[v];
if (ncon == 1)
cvwgt[cnvtxs] = vwgt[v];
else
scopy(ncon, nvwgt+v*ncon, cnvwgt+cnvtxs*ncon);
if (dovsize)
cvsize[cnvtxs] = vsize[v];
cadjwgtsum[cnvtxs] = adjwgtsum[v];
nedges = 0;
istart = xadj[v];
iend = xadj[v+1];
for (j=istart; j<iend; j++) {
k = auxadj[j];
if ((m = htable[k]) == -1) {
cadjncy[nedges] = k;
cadjwgt[nedges] = adjwgt[j];
htable[k] = nedges++;
}
else {
cadjwgt[m] += adjwgt[j];
}
}
if (v != u) {
if (ncon == 1)
cvwgt[cnvtxs] += vwgt[u];
else
saxpy(ncon, 1.0, nvwgt+u*ncon, 1, cnvwgt+cnvtxs*ncon, 1);
if (dovsize)
cvsize[cnvtxs] += vsize[u];
cadjwgtsum[cnvtxs] += adjwgtsum[u];
istart = xadj[u];
iend = xadj[u+1];
for (j=istart; j<iend; j++) {
k = auxadj[j];
if ((m = htable[k]) == -1) {
cadjncy[nedges] = k;
cadjwgt[nedges] = adjwgt[j];
htable[k] = nedges++;
}
else {
cadjwgt[m] += adjwgt[j];
}
}
/* Remove the contracted adjacency weight */
if ((j = htable[cnvtxs]) != -1) {
ASSERT(cadjncy[j] == cnvtxs);
cadjwgtsum[cnvtxs] -= cadjwgt[j];
cadjncy[j] = cadjncy[--nedges];
cadjwgt[j] = cadjwgt[nedges];
htable[cnvtxs] = -1;
}
}
ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d\n", cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt)));
for (j=0; j<nedges; j++)
htable[cadjncy[j]] = -1; /* Zero out the htable */
cnedges += nedges;
cxadj[++cnvtxs] = cnedges;
cadjncy += nedges;
cadjwgt += nedges;
}
cgraph->nedges = cnedges;
ReAdjustMemory(graph, cgraph, dovsize);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr));
idxwspacefree(ctrl, cnvtxs);
}
/*************************************************************************
* This function creates the coarser graph
**************************************************************************/
void CreateCoarseGraph_NVW(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm)
{
int i, j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, mask;
idxtype *xadj, *adjncy, *adjwgtsum, *auxadj;
idxtype *cmap, *htable;
idxtype *cxadj, *cvwgt, *cadjncy, *cadjwgt, *cadjwgtsum;
float *nvwgt, *cnvwgt;
GraphType *cgraph;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr));
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgtsum = graph->adjwgtsum;
cmap = graph->cmap;
/* Initialize the coarser graph */
cgraph = SetUpCoarseGraph(graph, cnvtxs, 0);
cxadj = cgraph->xadj;
cvwgt = cgraph->vwgt;
cnvwgt = cgraph->nvwgt;
cadjwgtsum = cgraph->adjwgtsum;
cadjncy = cgraph->adjncy;
cadjwgt = cgraph->adjwgt;
iend = xadj[nvtxs];
auxadj = ctrl->wspace.auxcore;
memcpy(auxadj, adjncy, iend*sizeof(idxtype));
for (i=0; i<iend; i++)
auxadj[i] = cmap[auxadj[i]];
mask = HTLENGTH;
htable = idxset(mask+1, -1, idxwspacemalloc(ctrl, mask+1));
cxadj[0] = cnvtxs = cnedges = 0;
for (i=0; i<nvtxs; i++) {
v = perm[i];
if (cmap[v] != cnvtxs)
continue;
u = match[v];
cvwgt[cnvtxs] = 1;
cadjwgtsum[cnvtxs] = adjwgtsum[v];
nedges = 0;
istart = xadj[v];
iend = xadj[v+1];
for (j=istart; j<iend; j++) {
k = auxadj[j];
kk = k&mask;
if ((m = htable[kk]) == -1) {
cadjncy[nedges] = k;
cadjwgt[nedges] = 1;
htable[kk] = nedges++;
}
else if (cadjncy[m] == k) {
cadjwgt[m]++;
}
else {
for (jj=0; jj<nedges; jj++) {
if (cadjncy[jj] == k) {
cadjwgt[jj]++;
break;
}
}
if (jj == nedges) {
cadjncy[nedges] = k;
cadjwgt[nedges++] = 1;
}
}
}
if (v != u) {
cvwgt[cnvtxs]++;
cadjwgtsum[cnvtxs] += adjwgtsum[u];
istart = xadj[u];
iend = xadj[u+1];
for (j=istart; j<iend; j++) {
k = auxadj[j];
kk = k&mask;
if ((m = htable[kk]) == -1) {
cadjncy[nedges] = k;
cadjwgt[nedges] = 1;
htable[kk] = nedges++;
}
else if (cadjncy[m] == k) {
cadjwgt[m]++;
}
else {
for (jj=0; jj<nedges; jj++) {
if (cadjncy[jj] == k) {
cadjwgt[jj]++;
break;
}
}
if (jj == nedges) {
cadjncy[nedges] = k;
cadjwgt[nedges++] = 1;
}
}
}
/* Remove the contracted adjacency weight */
jj = htable[cnvtxs&mask];
if (jj >= 0 && cadjncy[jj] != cnvtxs) {
for (jj=0; jj<nedges; jj++) {
if (cadjncy[jj] == cnvtxs)
break;
}
}
if (jj >= 0 && cadjncy[jj] == cnvtxs) { /* This 2nd check is needed for non-adjacent matchings */
cadjwgtsum[cnvtxs] -= cadjwgt[jj];
cadjncy[jj] = cadjncy[--nedges];
cadjwgt[jj] = cadjwgt[nedges];
}
}
ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d %d %d %d\n", cnvtxs, cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt), adjwgtsum[u], adjwgtsum[v]));
for (j=0; j<nedges; j++)
htable[cadjncy[j]&mask] = -1; /* Zero out the htable */
htable[cnvtxs&mask] = -1;
cnedges += nedges;
cxadj[++cnvtxs] = cnedges;
cadjncy += nedges;
cadjwgt += nedges;
}
cgraph->nedges = cnedges;
ReAdjustMemory(graph, cgraph, 0);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr));
idxwspacefree(ctrl, mask+1);
}
/*************************************************************************
* Setup the various arrays for the coarse graph
**************************************************************************/
GraphType *SetUpCoarseGraph(GraphType *graph, int cnvtxs, int dovsize)
{
GraphType *cgraph;
cgraph = CreateGraph();
cgraph->nvtxs = cnvtxs;
cgraph->ncon = graph->ncon;
cgraph->finer = graph;
graph->coarser = cgraph;
/* Allocate memory for the coarser graph */
if (graph->ncon == 1) {
if (dovsize) {
cgraph->gdata = idxmalloc(5*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata");
cgraph->xadj = cgraph->gdata;
cgraph->vwgt = cgraph->gdata + cnvtxs+1;
cgraph->vsize = cgraph->gdata + 2*cnvtxs+1;
cgraph->adjwgtsum = cgraph->gdata + 3*cnvtxs+1;
cgraph->cmap = cgraph->gdata + 4*cnvtxs+1;
cgraph->adjncy = cgraph->gdata + 5*cnvtxs+1;
cgraph->adjwgt = cgraph->gdata + 5*cnvtxs+1 + graph->nedges;
}
else {
cgraph->gdata = idxmalloc(4*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata");
cgraph->xadj = cgraph->gdata;
cgraph->vwgt = cgraph->gdata + cnvtxs+1;
cgraph->adjwgtsum = cgraph->gdata + 2*cnvtxs+1;
cgraph->cmap = cgraph->gdata + 3*cnvtxs+1;
cgraph->adjncy = cgraph->gdata + 4*cnvtxs+1;
cgraph->adjwgt = cgraph->gdata + 4*cnvtxs+1 + graph->nedges;
}
}
else {
if (dovsize) {
cgraph->gdata = idxmalloc(4*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata");
cgraph->xadj = cgraph->gdata;
cgraph->vsize = cgraph->gdata + cnvtxs+1;
cgraph->adjwgtsum = cgraph->gdata + 2*cnvtxs+1;
cgraph->cmap = cgraph->gdata + 3*cnvtxs+1;
cgraph->adjncy = cgraph->gdata + 4*cnvtxs+1;
cgraph->adjwgt = cgraph->gdata + 4*cnvtxs+1 + graph->nedges;
}
else {
cgraph->gdata = idxmalloc(3*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata");
cgraph->xadj = cgraph->gdata;
cgraph->adjwgtsum = cgraph->gdata + cnvtxs+1;
cgraph->cmap = cgraph->gdata + 2*cnvtxs+1;
cgraph->adjncy = cgraph->gdata + 3*cnvtxs+1;
cgraph->adjwgt = cgraph->gdata + 3*cnvtxs+1 + graph->nedges;
}
cgraph->nvwgt = fmalloc(graph->ncon*cnvtxs, "SetUpCoarseGraph: nvwgt");
}
return cgraph;
}
/*************************************************************************
* This function re-adjusts the amount of memory that was allocated if
* it will lead to significant savings
**************************************************************************/
void ReAdjustMemory(GraphType *graph, GraphType *cgraph, int dovsize)
{
if (cgraph->nedges > 100000 && graph->nedges < 0.7*graph->nedges) {
idxcopy(cgraph->nedges, cgraph->adjwgt, cgraph->adjncy+cgraph->nedges);
if (graph->ncon == 1) {
if (dovsize) {
cgraph->gdata = realloc(cgraph->gdata, (5*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype));
/* Do this, in case everything was copied into new space */
cgraph->xadj = cgraph->gdata;
cgraph->vwgt = cgraph->gdata + cgraph->nvtxs+1;
cgraph->vsize = cgraph->gdata + 2*cgraph->nvtxs+1;
cgraph->adjwgtsum = cgraph->gdata + 3*cgraph->nvtxs+1;
cgraph->cmap = cgraph->gdata + 4*cgraph->nvtxs+1;
cgraph->adjncy = cgraph->gdata + 5*cgraph->nvtxs+1;
cgraph->adjwgt = cgraph->gdata + 5*cgraph->nvtxs+1 + cgraph->nedges;
}
else {
cgraph->gdata = realloc(cgraph->gdata, (4*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype));
/* Do this, in case everything was copied into new space */
cgraph->xadj = cgraph->gdata;
cgraph->vwgt = cgraph->gdata + cgraph->nvtxs+1;
cgraph->adjwgtsum = cgraph->gdata + 2*cgraph->nvtxs+1;
cgraph->cmap = cgraph->gdata + 3*cgraph->nvtxs+1;
cgraph->adjncy = cgraph->gdata + 4*cgraph->nvtxs+1;
cgraph->adjwgt = cgraph->gdata + 4*cgraph->nvtxs+1 + cgraph->nedges;
}
}
else {
if (dovsize) {
cgraph->gdata = realloc(cgraph->gdata, (4*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype));
/* Do this, in case everything was copied into new space */
cgraph->xadj = cgraph->gdata;
cgraph->vsize = cgraph->gdata + cgraph->nvtxs+1;
cgraph->adjwgtsum = cgraph->gdata + 2*cgraph->nvtxs+1;
cgraph->cmap = cgraph->gdata + 3*cgraph->nvtxs+1;
cgraph->adjncy = cgraph->gdata + 4*cgraph->nvtxs+1;
cgraph->adjwgt = cgraph->gdata + 4*cgraph->nvtxs+1 + cgraph->nedges;
}
else {
cgraph->gdata = realloc(cgraph->gdata, (3*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype));
/* Do this, in case everything was copied into new space */
cgraph->xadj = cgraph->gdata;
cgraph->adjwgtsum = cgraph->gdata + cgraph->nvtxs+1;
cgraph->cmap = cgraph->gdata + 2*cgraph->nvtxs+1;
cgraph->adjncy = cgraph->gdata + 3*cgraph->nvtxs+1;
cgraph->adjwgt = cgraph->gdata + 3*cgraph->nvtxs+1 + cgraph->nedges;
}
}
}
}

View File

@ -0,0 +1,127 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* checkgraph.c
*
* This file contains routines related to I/O
*
* Started 8/28/94
* George
*
* $Id: checkgraph.c,v 1.1 2003/07/24 18:39:06 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function checks if a graph is valid
**************************************************************************/
int CheckGraph(GraphType *graph)
{
int i, j, k, l;
int nvtxs, ncon, err=0;
int minedge, maxedge, minewgt, maxewgt;
float minvwgt[MAXNCON], maxvwgt[MAXNCON];
idxtype *xadj, *adjncy, *adjwgt, *htable;
float *nvwgt, ntvwgts[MAXNCON];
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
htable = idxsmalloc(nvtxs, 0, "htable");
if (ncon > 1) {
for (j=0; j<ncon; j++) {
minvwgt[j] = maxvwgt[j] = nvwgt[j];
ntvwgts[j] = 0.0;
}
}
minedge = maxedge = adjncy[0];
minewgt = maxewgt = adjwgt[0];
for (i=0; i<nvtxs; i++) {
if (ncon > 1) {
for (j=0; j<ncon; j++) {
ntvwgts[j] += nvwgt[i*ncon+j];
minvwgt[j] = (nvwgt[i*ncon+j] < minvwgt[j]) ? nvwgt[i*ncon+j] : minvwgt[j];
maxvwgt[j] = (nvwgt[i*ncon+j] > maxvwgt[j]) ? nvwgt[i*ncon+j] : maxvwgt[j];
}
}
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
minedge = (k < minedge) ? k : minedge;
maxedge = (k > maxedge) ? k : maxedge;
minewgt = (adjwgt[j] < minewgt) ? adjwgt[j] : minewgt;
maxewgt = (adjwgt[j] > maxewgt) ? adjwgt[j] : maxewgt;
if (i == k) {
printf("Vertex %d contains a self-loop (i.e., diagonal entry in the matrix)!\n", i);
err++;
}
else {
for (l=xadj[k]; l<xadj[k+1]; l++) {
if (adjncy[l] == i) {
if (adjwgt != NULL && adjwgt[l] != adjwgt[j]) {
printf("Edges (%d %d) and (%d %d) do not have the same weight! %d %d\n", i,k,k,i, adjwgt[l], adjwgt[j]);
err++;
}
break;
}
}
if (l == xadj[k+1]) {
printf("Missing edge: (%d %d)!\n", k, i);
err++;
}
}
if (htable[k] == 0) {
htable[k]++;
}
else {
printf("Edge %d from vertex %d is repeated %d times\n", k, i, htable[k]++);
err++;
}
}
for (j=xadj[i]; j<xadj[i+1]; j++) {
htable[adjncy[j]] = 0;
}
}
if (ncon > 1) {
for (j=0; j<ncon; j++) {
if (fabs(ntvwgts[j] - 1.0) > 0.0001) {
printf("Normalized vwgts don't sum to one. Weight %d = %.8f.\n", j, ntvwgts[j]);
err++;
}
}
}
/*
printf("errs: %d, adjncy: [%d %d], adjwgt: [%d %d]\n",
err, minedge, maxedge, minewgt, maxewgt);
if (ncon > 1) {
for (j=0; j<ncon; j++)
printf("[%.5f %.5f] ", minvwgt[j], maxvwgt[j]);
printf("\n");
}
*/
if (err > 0) {
printf("A total of %d errors exist in the input file. Correct them, and run again!\n", err);
}
GKfree(&htable, LTERM);
return (err == 0 ? 1 : 0);
}

View File

@ -0,0 +1,86 @@
/*
* coarsen.c
*
* This file contains the driving routines for the coarsening process
*
* Started 7/23/97
* George
*
* $Id: coarsen.c,v 1.2 2003/07/31 16:23:29 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function takes a graph and creates a sequence of coarser graphs
**************************************************************************/
GraphType *Coarsen2Way(CtrlType *ctrl, GraphType *graph)
{
int clevel;
GraphType *cgraph;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->CoarsenTmr));
cgraph = graph;
/* The following is ahack to allow the multiple bisections to go through with correct
coarsening */
if (ctrl->CType > 20) {
clevel = 1;
ctrl->CType -= 20;
}
else
clevel = 0;
do {
IFSET(ctrl->dbglvl, DBG_COARSEN, printf("%6d %7d [%d] [%d %d]\n",
cgraph->nvtxs, cgraph->nedges, ctrl->CoarsenTo, ctrl->maxvwgt,
(cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt) : cgraph->nvtxs)));
if (cgraph->adjwgt) {
switch (ctrl->CType) {
case MATCH_RM:
Match_RM(ctrl, cgraph);
break;
case MATCH_HEM:
if (clevel < 1 || cgraph->nedges == 0)
Match_RM(ctrl, cgraph);
else
Match_HEM(ctrl, cgraph);
break;
case MATCH_SHEM:
if (clevel < 1 || cgraph->nedges == 0)
Match_RM(ctrl, cgraph);
else
Match_SHEM(ctrl, cgraph);
break;
case MATCH_SHEMKWAY:
if (cgraph->nedges == 0)
Match_RM(ctrl, cgraph);
else
Match_SHEM(ctrl, cgraph);
break;
default:
errexit("Unknown CType: %d\n", ctrl->CType);
}
}
else {
Match_RM_NVW(ctrl, cgraph);
}
cgraph = cgraph->coarser;
clevel++;
} while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2);
IFSET(ctrl->dbglvl, DBG_COARSEN, printf("%6d %7d [%d] [%d %d]\n",
cgraph->nvtxs, cgraph->nedges, ctrl->CoarsenTo, ctrl->maxvwgt,
(cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt) : cgraph->nvtxs)));
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->CoarsenTmr));
return cgraph;
}

View File

@ -0,0 +1,256 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* compress.c
*
* This file contains code for compressing nodes with identical adjacency
* structure and for prunning dense columns
*
* Started 9/17/97
* George
*
* $Id: compress.c,v 1.1 2003/07/16 15:55:01 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function compresses a graph by merging identical vertices
* The compression should lead to at least 10% reduction.
**************************************************************************/
void CompressGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *cptr, idxtype *cind)
{
int i, ii, iii, j, jj, k, l, cnvtxs, cnedges;
idxtype *cxadj, *cadjncy, *cvwgt, *mark, *map;
KeyValueType *keys;
mark = idxsmalloc(nvtxs, -1, "CompressGraph: mark");
map = idxsmalloc(nvtxs, -1, "CompressGraph: map");
keys = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "CompressGraph: keys");
/* Compute a key for each adjacency list */
for (i=0; i<nvtxs; i++) {
k = 0;
for (j=xadj[i]; j<xadj[i+1]; j++)
k += adjncy[j];
keys[i].key = k+i; /* Add the diagonal entry as well */
keys[i].val = i;
}
ikeysort(nvtxs, keys);
l = cptr[0] = 0;
for (cnvtxs=i=0; i<nvtxs; i++) {
ii = keys[i].val;
if (map[ii] == -1) {
mark[ii] = i; /* Add the diagonal entry */
for (j=xadj[ii]; j<xadj[ii+1]; j++)
mark[adjncy[j]] = i;
cind[l++] = ii;
map[ii] = cnvtxs;
for (j=i+1; j<nvtxs; j++) {
iii = keys[j].val;
if (keys[i].key != keys[j].key || xadj[ii+1]-xadj[ii] != xadj[iii+1]-xadj[iii])
break; /* Break if keys or degrees are different */
if (map[iii] == -1) { /* Do a comparison if iii has not been mapped */
for (jj=xadj[iii]; jj<xadj[iii+1]; jj++) {
if (mark[adjncy[jj]] != i)
break;
}
if (jj == xadj[iii+1]) { /* Identical adjacency structure */
map[iii] = cnvtxs;
cind[l++] = iii;
}
}
}
cptr[++cnvtxs] = l;
}
}
/* printf("Original: %6d, Compressed: %6d\n", nvtxs, cnvtxs); */
InitGraph(graph);
if (cnvtxs >= COMPRESSION_FRACTION*nvtxs) {
graph->nvtxs = nvtxs;
graph->nedges = xadj[nvtxs];
graph->ncon = 1;
graph->xadj = xadj;
graph->adjncy = adjncy;
graph->gdata = idxmalloc(3*nvtxs+graph->nedges, "CompressGraph: gdata");
graph->vwgt = graph->gdata;
graph->adjwgtsum = graph->gdata+nvtxs;
graph->cmap = graph->gdata+2*nvtxs;
graph->adjwgt = graph->gdata+3*nvtxs;
idxset(nvtxs, 1, graph->vwgt);
idxset(graph->nedges, 1, graph->adjwgt);
for (i=0; i<nvtxs; i++)
graph->adjwgtsum[i] = xadj[i+1]-xadj[i];
graph->label = idxmalloc(nvtxs, "CompressGraph: label");
for (i=0; i<nvtxs; i++)
graph->label[i] = i;
}
else { /* Ok, form the compressed graph */
cnedges = 0;
for (i=0; i<cnvtxs; i++) {
ii = cind[cptr[i]];
cnedges += xadj[ii+1]-xadj[ii];
}
/* Allocate memory for the compressed graph*/
graph->gdata = idxmalloc(4*cnvtxs+1 + 2*cnedges, "CompressGraph: gdata");
cxadj = graph->xadj = graph->gdata;
cvwgt = graph->vwgt = graph->gdata + cnvtxs+1;
graph->adjwgtsum = graph->gdata + 2*cnvtxs+1;
graph->cmap = graph->gdata + 3*cnvtxs+1;
cadjncy = graph->adjncy = graph->gdata + 4*cnvtxs+1;
graph->adjwgt = graph->gdata + 4*cnvtxs+1 + cnedges;
/* Now go and compress the graph */
idxset(nvtxs, -1, mark);
l = cxadj[0] = 0;
for (i=0; i<cnvtxs; i++) {
cvwgt[i] = cptr[i+1]-cptr[i];
mark[i] = i; /* Remove any dioganal entries in the compressed graph */
for (j=cptr[i]; j<cptr[i+1]; j++) {
ii = cind[j];
for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
k = map[adjncy[jj]];
if (mark[k] != i)
cadjncy[l++] = k;
mark[k] = i;
}
}
cxadj[i+1] = l;
}
graph->nvtxs = cnvtxs;
graph->nedges = l;
graph->ncon = 1;
idxset(graph->nedges, 1, graph->adjwgt);
for (i=0; i<cnvtxs; i++)
graph->adjwgtsum[i] = cxadj[i+1]-cxadj[i];
graph->label = idxmalloc(cnvtxs, "CompressGraph: label");
for (i=0; i<cnvtxs; i++)
graph->label[i] = i;
}
GKfree(&keys, &map, &mark, LTERM);
}
/*************************************************************************
* This function prunes all the vertices in a graph with degree greater
* than factor*average
**************************************************************************/
void PruneGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *iperm, float factor)
{
int i, j, k, l, nlarge, pnvtxs, pnedges;
idxtype *pxadj, *padjncy, *padjwgt, *pvwgt;
idxtype *perm;
perm = idxmalloc(nvtxs, "PruneGraph: perm");
factor = factor*xadj[nvtxs]/nvtxs;
pnvtxs = pnedges = nlarge = 0;
for (i=0; i<nvtxs; i++) {
if (xadj[i+1]-xadj[i] < factor) {
perm[i] = pnvtxs;
iperm[pnvtxs++] = i;
pnedges += xadj[i+1]-xadj[i];
}
else {
perm[i] = nvtxs - ++nlarge;
iperm[nvtxs-nlarge] = i;
}
}
/* printf("Pruned %d vertices\n", nlarge); */
InitGraph(graph);
if (nlarge == 0) { /* No prunning */
graph->nvtxs = nvtxs;
graph->nedges = xadj[nvtxs];
graph->ncon = 1;
graph->xadj = xadj;
graph->adjncy = adjncy;
graph->gdata = idxmalloc(3*nvtxs+graph->nedges, "CompressGraph: gdata");
graph->vwgt = graph->gdata;
graph->adjwgtsum = graph->gdata+nvtxs;
graph->cmap = graph->gdata+2*nvtxs;
graph->adjwgt = graph->gdata+3*nvtxs;
idxset(nvtxs, 1, graph->vwgt);
idxset(graph->nedges, 1, graph->adjwgt);
for (i=0; i<nvtxs; i++)
graph->adjwgtsum[i] = xadj[i+1]-xadj[i];
graph->label = idxmalloc(nvtxs, "CompressGraph: label");
for (i=0; i<nvtxs; i++)
graph->label[i] = i;
}
else { /* Prune the graph */
/* Allocate memory for the compressed graph*/
graph->gdata = idxmalloc(4*pnvtxs+1 + 2*pnedges, "PruneGraph: gdata");
pxadj = graph->xadj = graph->gdata;
graph->vwgt = graph->gdata + pnvtxs+1;
graph->adjwgtsum = graph->gdata + 2*pnvtxs+1;
graph->cmap = graph->gdata + 3*pnvtxs+1;
padjncy = graph->adjncy = graph->gdata + 4*pnvtxs+1;
graph->adjwgt = graph->gdata + 4*pnvtxs+1 + pnedges;
pxadj[0] = pnedges = l = 0;
for (i=0; i<nvtxs; i++) {
if (xadj[i+1]-xadj[i] < factor) {
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = perm[adjncy[j]];
if (k < pnvtxs)
padjncy[pnedges++] = k;
}
pxadj[++l] = pnedges;
}
}
graph->nvtxs = pnvtxs;
graph->nedges = pnedges;
graph->ncon = 1;
idxset(pnvtxs, 1, graph->vwgt);
idxset(pnedges, 1, graph->adjwgt);
for (i=0; i<pnvtxs; i++)
graph->adjwgtsum[i] = pxadj[i+1]-pxadj[i];
graph->label = idxmalloc(pnvtxs, "CompressGraph: label");
for (i=0; i<pnvtxs; i++)
graph->label[i] = i;
}
free(perm);
}

View File

@ -0,0 +1,239 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* debug.c
*
* This file contains code that performs self debuging
*
* Started 7/24/97
* George
*
* $Id: debug.c,v 1.1 2003/07/16 15:55:01 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function computes the cut given the graph and a where vector
**************************************************************************/
int ComputeCut(GraphType *graph, idxtype *where)
{
int i, j, cut;
if (graph->adjwgt == NULL) {
for (cut=0, i=0; i<graph->nvtxs; i++) {
for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++)
if (where[i] != where[graph->adjncy[j]])
cut++;
}
}
else {
for (cut=0, i=0; i<graph->nvtxs; i++) {
for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++)
if (where[i] != where[graph->adjncy[j]])
cut += graph->adjwgt[j];
}
}
return cut/2;
}
/*************************************************************************
* This function checks whether or not the boundary information is correct
**************************************************************************/
int CheckBnd(GraphType *graph)
{
int i, j, nvtxs, nbnd;
idxtype *xadj, *adjncy, *where, *bndptr, *bndind;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
where = graph->where;
bndptr = graph->bndptr;
bndind = graph->bndind;
for (nbnd=0, i=0; i<nvtxs; i++) {
if (xadj[i+1]-xadj[i] == 0)
nbnd++; /* Islands are considered to be boundary vertices */
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (where[i] != where[adjncy[j]]) {
nbnd++;
ASSERT(bndptr[i] != -1);
ASSERT(bndind[bndptr[i]] == i);
break;
}
}
}
ASSERTP(nbnd == graph->nbnd, ("%d %d\n", nbnd, graph->nbnd));
return 1;
}
/*************************************************************************
* This function checks whether or not the boundary information is correct
**************************************************************************/
int CheckBnd2(GraphType *graph)
{
int i, j, nvtxs, nbnd, id, ed;
idxtype *xadj, *adjncy, *where, *bndptr, *bndind;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
where = graph->where;
bndptr = graph->bndptr;
bndind = graph->bndind;
for (nbnd=0, i=0; i<nvtxs; i++) {
id = ed = 0;
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (where[i] != where[adjncy[j]])
ed += graph->adjwgt[j];
else
id += graph->adjwgt[j];
}
if (ed - id >= 0 && xadj[i] < xadj[i+1]) {
nbnd++;
ASSERTP(bndptr[i] != -1, ("%d %d %d\n", i, id, ed));
ASSERT(bndind[bndptr[i]] == i);
}
}
ASSERTP(nbnd == graph->nbnd, ("%d %d\n", nbnd, graph->nbnd));
return 1;
}
/*************************************************************************
* This function checks whether or not the boundary information is correct
**************************************************************************/
int CheckNodeBnd(GraphType *graph, int onbnd)
{
int i, j, nvtxs, nbnd;
idxtype *xadj, *adjncy, *where, *bndptr, *bndind;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
where = graph->where;
bndptr = graph->bndptr;
bndind = graph->bndind;
for (nbnd=0, i=0; i<nvtxs; i++) {
if (where[i] == 2)
nbnd++;
}
ASSERTP(nbnd == onbnd, ("%d %d\n", nbnd, onbnd));
for (i=0; i<nvtxs; i++) {
if (where[i] != 2) {
ASSERTP(bndptr[i] == -1, ("%d %d\n", i, bndptr[i]));
}
else {
ASSERTP(bndptr[i] != -1, ("%d %d\n", i, bndptr[i]));
}
}
return 1;
}
/*************************************************************************
* This function checks whether or not the rinfo of a vertex is consistent
**************************************************************************/
int CheckRInfo(RInfoType *rinfo)
{
int i, j;
for (i=0; i<rinfo->ndegrees; i++) {
for (j=i+1; j<rinfo->ndegrees; j++)
ASSERTP(rinfo->edegrees[i].pid != rinfo->edegrees[j].pid, ("%d %d %d %d\n", i, j, rinfo->edegrees[i].pid, rinfo->edegrees[j].pid));
}
return 1;
}
/*************************************************************************
* This function checks the correctness of the NodeFM data structures
**************************************************************************/
int CheckNodePartitionParams(GraphType *graph)
{
int i, j, k, l, nvtxs, me, other;
idxtype *xadj, *adjncy, *adjwgt, *vwgt, *where;
idxtype edegrees[2], pwgts[3];
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
/*------------------------------------------------------------
/ Compute now the separator external degrees
/------------------------------------------------------------*/
pwgts[0] = pwgts[1] = pwgts[2] = 0;
for (i=0; i<nvtxs; i++) {
me = where[i];
pwgts[me] += vwgt[i];
if (me == 2) { /* If it is on the separator do some computations */
edegrees[0] = edegrees[1] = 0;
for (j=xadj[i]; j<xadj[i+1]; j++) {
other = where[adjncy[j]];
if (other != 2)
edegrees[other] += vwgt[adjncy[j]];
}
if (edegrees[0] != graph->nrinfo[i].edegrees[0] || edegrees[1] != graph->nrinfo[i].edegrees[1]) {
printf("Something wrong with edegrees: %d %d %d %d %d\n", i, edegrees[0], edegrees[1], graph->nrinfo[i].edegrees[0], graph->nrinfo[i].edegrees[1]);
return 0;
}
}
}
if (pwgts[0] != graph->pwgts[0] || pwgts[1] != graph->pwgts[1] || pwgts[2] != graph->pwgts[2])
printf("Something wrong with part-weights: %d %d %d %d %d %d\n", pwgts[0], pwgts[1], pwgts[2], graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]);
return 1;
}
/*************************************************************************
* This function checks if the separator is indeed a separator
**************************************************************************/
int IsSeparable(GraphType *graph)
{
int i, j, nvtxs, other;
idxtype *xadj, *adjncy, *where;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
where = graph->where;
for (i=0; i<nvtxs; i++) {
if (where[i] == 2)
continue;
other = (where[i]+1)%2;
for (j=xadj[i]; j<xadj[i+1]; j++) {
ASSERTP(where[adjncy[j]] != other, ("%d %d %d %d %d %d\n", i, where[i], adjncy[j], where[adjncy[j]], xadj[i+1]-xadj[i], xadj[adjncy[j]+1]-xadj[adjncy[j]]));
}
}
return 1;
}

View File

@ -0,0 +1,161 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* defs.h
*
* This file contains constant definitions
*
* Started 8/27/94
* George
*
* $Id: defs.h,v 1.1 2003/07/16 15:55:01 karypis Exp $
*
*/
#define METISTITLE " METIS 4.0 Copyright 1998, Regents of the University of Minnesota\n\n"
#define MAXLINE 1280000
#define LTERM (void **) 0 /* List terminator for GKfree() */
#define MAXNCON 16 /* The maximum number of constrains */
#define MAXNOBJ 16 /* The maximum number of objectives */
#define PLUS_GAINSPAN 500 /* Parameters for FM buckets */
#define NEG_GAINSPAN 500
#define HTLENGTH ((1<<11)-1)
/* Meaning of various options[] parameters */
#define OPTION_PTYPE 0
#define OPTION_CTYPE 1
#define OPTION_ITYPE 2
#define OPTION_RTYPE 3
#define OPTION_DBGLVL 4
#define OPTION_OFLAGS 5
#define OPTION_PFACTOR 6
#define OPTION_NSEPS 7
#define OFLAG_COMPRESS 1 /* Try to compress the graph */
#define OFLAG_CCMP 2 /* Find and order connected components */
/* Default options for PMETIS */
#define PMETIS_CTYPE MATCH_SHEM
#define PMETIS_ITYPE IPART_GGPKL
#define PMETIS_RTYPE RTYPE_FM
#define PMETIS_DBGLVL 0
/* Default options for KMETIS */
#define KMETIS_CTYPE MATCH_SHEM
#define KMETIS_ITYPE IPART_PMETIS
#define KMETIS_RTYPE RTYPE_KWAYRANDOM_MCONN
#define KMETIS_DBGLVL 0
/* Default options for OEMETIS */
#define OEMETIS_CTYPE MATCH_SHEM
#define OEMETIS_ITYPE IPART_GGPKL
#define OEMETIS_RTYPE RTYPE_FM
#define OEMETIS_DBGLVL 0
/* Default options for ONMETIS */
#define ONMETIS_CTYPE MATCH_SHEM
#define ONMETIS_ITYPE IPART_GGPKL
#define ONMETIS_RTYPE RTYPE_SEP1SIDED
#define ONMETIS_DBGLVL 0
#define ONMETIS_OFLAGS OFLAG_COMPRESS
#define ONMETIS_PFACTOR -1
#define ONMETIS_NSEPS 1
/* Default options for McPMETIS */
#define McPMETIS_CTYPE MATCH_SHEBM_ONENORM
#define McPMETIS_ITYPE IPART_RANDOM
#define McPMETIS_RTYPE RTYPE_FM
#define McPMETIS_DBGLVL 0
/* Default options for McKMETIS */
#define McKMETIS_CTYPE MATCH_SHEBM_ONENORM
#define McKMETIS_ITYPE IPART_McHPMETIS
#define McKMETIS_RTYPE RTYPE_KWAYRANDOM
#define McKMETIS_DBGLVL 0
/* Default options for KVMETIS */
#define KVMETIS_CTYPE MATCH_SHEM
#define KVMETIS_ITYPE IPART_PMETIS
#define KVMETIS_RTYPE RTYPE_KWAYRANDOM
#define KVMETIS_DBGLVL 0
/* Operations supported by stand-alone code */
#define OP_PMETIS 1
#define OP_KMETIS 2
#define OP_OEMETIS 3
#define OP_ONMETIS 4
#define OP_ONWMETIS 5
#define OP_KVMETIS 6
/* Matching Schemes */
#define MATCH_RM 1
#define MATCH_HEM 2
#define MATCH_SHEM 3
#define MATCH_SHEMKWAY 4
#define MATCH_SHEBM_ONENORM 5
#define MATCH_SHEBM_INFNORM 6
#define MATCH_SBHEM_ONENORM 7
#define MATCH_SBHEM_INFNORM 8
/* Initial partitioning schemes for PMETIS and ONMETIS */
#define IPART_GGPKL 1
#define IPART_GGPKLNODE 2
#define IPART_RANDOM 2
/* Refinement schemes for PMETIS */
#define RTYPE_FM 1
/* Initial partitioning schemes for KMETIS */
#define IPART_PMETIS 1
/* Refinement schemes for KMETIS */
#define RTYPE_KWAYRANDOM 1
#define RTYPE_KWAYGREEDY 2
#define RTYPE_KWAYRANDOM_MCONN 3
/* Refinement schemes for ONMETIS */
#define RTYPE_SEP2SIDED 1
#define RTYPE_SEP1SIDED 2
/* Initial Partitioning Schemes for McKMETIS */
#define IPART_McPMETIS 1 /* Simple McPMETIS */
#define IPART_McHPMETIS 2 /* horizontally relaxed McPMETIS */
#define UNMATCHED -1
#define HTABLE_EMPTY -1
#define NGR_PASSES 4 /* Number of greedy refinement passes */
#define NLGR_PASSES 5 /* Number of GR refinement during IPartition */
#define LARGENIPARTS 8 /* Number of random initial partitions */
#define SMALLNIPARTS 3 /* Number of random initial partitions */
#define COARSEN_FRACTION 0.75 /* Node reduction between succesive coarsening levels */
#define COARSEN_FRACTION2 0.90 /* Node reduction between succesive coarsening levels */
#define UNBALANCE_FRACTION 1.05
#define COMPRESSION_FRACTION 0.85
#define ORDER_UNBALANCE_FRACTION 1.10
#define MMDSWITCH 200
#define HORIZONTAL_IMBALANCE 1.05
/* Debug Levels */
#define DBG_TIME 1 /* Perform timing analysis */
#define DBG_OUTPUT 2
#define DBG_COARSEN 4 /* Show the coarsening progress */
#define DBG_REFINE 8 /* Show info on communication during folding */
#define DBG_IPART 16 /* Show info on initial partition */
#define DBG_MOVEINFO 32 /* Show info on communication during folding */
#define DBG_KWAYPINFO 64 /* Show info on communication during folding */
#define DBG_SEPINFO 128 /* Show info on communication during folding */

View File

@ -0,0 +1,157 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* estmem.c
*
* This file contains code for estimating the amount of memory required by
* the various routines in METIS
*
* Started 11/4/97
* George
*
* $Id: estmem.c,v 1.1 2003/07/16 15:55:02 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function computes how much memory will be required by the various
* routines in METIS
**************************************************************************/
void METIS_EstimateMemory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
{
int i, j, k, nedges, nlevels;
float vfraction, efraction, vmult, emult;
int coresize, gdata, rdata;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
nedges = xadj[*nvtxs];
InitRandom(-1);
EstimateCFraction(*nvtxs, xadj, adjncy, &vfraction, &efraction);
/* Estimate the amount of memory for coresize */
if (*optype == 2)
coresize = nedges;
else
coresize = 0;
coresize += nedges + 11*(*nvtxs) + 4*1024 + 2*(NEG_GAINSPAN+PLUS_GAINSPAN+1)*(sizeof(ListNodeType *)/sizeof(idxtype));
coresize += 2*(*nvtxs); /* add some more fore other vectors */
gdata = nedges; /* Assume that the user does not pass weights */
nlevels = (int)(log(100.0/(*nvtxs))/log(vfraction) + .5);
vmult = 0.5 + (1.0 - pow(vfraction, nlevels))/(1.0 - vfraction);
emult = 1.0 + (1.0 - pow(efraction, nlevels+1))/(1.0 - efraction);
gdata += vmult*4*(*nvtxs) + emult*2*nedges;
if ((vmult-1.0)*4*(*nvtxs) + (emult-1.0)*2*nedges < 5*(*nvtxs))
rdata = 0;
else
rdata = 5*(*nvtxs);
*nbytes = sizeof(idxtype)*(coresize+gdata+rdata+(*nvtxs));
if (*numflag == 1)
Change2FNumbering2(*nvtxs, xadj, adjncy);
}
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void EstimateCFraction(int nvtxs, idxtype *xadj, idxtype *adjncy, float *vfraction, float *efraction)
{
int i, ii, j, cnvtxs, cnedges, maxidx;
idxtype *match, *cmap, *perm;
cmap = idxmalloc(nvtxs, "cmap");
match = idxsmalloc(nvtxs, UNMATCHED, "match");
perm = idxmalloc(nvtxs, "perm");
RandomPermute(nvtxs, perm, 1);
cnvtxs = 0;
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
/* Find a random matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (match[adjncy[j]] == UNMATCHED) {
maxidx = adjncy[j];
break;
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
cnedges = ComputeCoarseGraphSize(nvtxs, xadj, adjncy, cnvtxs, cmap, match, perm);
*vfraction = (1.0*cnvtxs)/(1.0*nvtxs);
*efraction = (1.0*cnedges)/(1.0*xadj[nvtxs]);
GKfree(&cmap, &match, &perm, LTERM);
}
/*************************************************************************
* This function computes the size of the coarse graph
**************************************************************************/
int ComputeCoarseGraphSize(int nvtxs, idxtype *xadj, idxtype *adjncy, int cnvtxs, idxtype *cmap, idxtype *match, idxtype *perm)
{
int i, j, k, istart, iend, nedges, cnedges, v, u;
idxtype *htable;
htable = idxsmalloc(cnvtxs, -1, "htable");
cnvtxs = cnedges = 0;
for (i=0; i<nvtxs; i++) {
v = perm[i];
if (cmap[v] != cnvtxs)
continue;
htable[cnvtxs] = cnvtxs;
u = match[v];
istart = xadj[v];
iend = xadj[v+1];
for (j=istart; j<iend; j++) {
k = cmap[adjncy[j]];
if (htable[k] != cnvtxs) {
htable[k] = cnvtxs;
cnedges++;
}
}
if (v != u) {
istart = xadj[u];
iend = xadj[u+1];
for (j=istart; j<iend; j++) {
k = cmap[adjncy[j]];
if (htable[k] != cnvtxs) {
htable[k] = cnvtxs;
cnedges++;
}
}
}
cnvtxs++;
}
GKfree(&htable, LTERM);
return cnedges;
}

View File

@ -0,0 +1,194 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* fm.c
*
* This file contains code that implements the edge-based FM refinement
*
* Started 7/23/97
* George
*
* $Id: fm.c,v 1.1 2003/07/16 15:55:02 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function performs an edge-based FM refinement
**************************************************************************/
void FM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, int *tpwgts, int npasses)
{
int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, limit, tmp;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts;
idxtype *moved, *swaps, *perm;
PQueueType parts[2];
int higain, oldgain, mincut, mindiff, origdiff, initcut, newcut, mincutorder, avgvwgt;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
pwgts = graph->pwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
moved = idxwspacemalloc(ctrl, nvtxs);
swaps = idxwspacemalloc(ctrl, nvtxs);
perm = idxwspacemalloc(ctrl, nvtxs);
limit = amin(amax(0.01*nvtxs, 15), 100);
avgvwgt = amin((pwgts[0]+pwgts[1])/20, 2*(pwgts[0]+pwgts[1])/nvtxs);
tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)];
PQueueInit(ctrl, &parts[0], nvtxs, tmp);
PQueueInit(ctrl, &parts[1], nvtxs, tmp);
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d\n",
pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
origdiff = abs(tpwgts[0]-pwgts[0]);
idxset(nvtxs, -1, moved);
for (pass=0; pass<npasses; pass++) { /* Do a number of passes */
PQueueReset(&parts[0]);
PQueueReset(&parts[1]);
mincutorder = -1;
newcut = mincut = initcut = graph->mincut;
mindiff = abs(tpwgts[0]-pwgts[0]);
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
/* Insert boundary nodes in the priority queues */
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (ii=0; ii<nbnd; ii++) {
i = perm[ii];
ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0);
ASSERT(bndptr[bndind[i]] != -1);
PQueueInsert(&parts[where[bndind[i]]], bndind[i], ed[bndind[i]]-id[bndind[i]]);
}
for (nswaps=0; nswaps<nvtxs; nswaps++) {
from = (tpwgts[0]-pwgts[0] < tpwgts[1]-pwgts[1] ? 0 : 1);
to = (from+1)%2;
if ((higain = PQueueGetMax(&parts[from])) == -1)
break;
ASSERT(bndptr[higain] != -1);
newcut -= (ed[higain]-id[higain]);
INC_DEC(pwgts[to], pwgts[from], vwgt[higain]);
if ((newcut < mincut && abs(tpwgts[0]-pwgts[0]) <= origdiff+avgvwgt) ||
(newcut == mincut && abs(tpwgts[0]-pwgts[0]) < mindiff)) {
mincut = newcut;
mindiff = abs(tpwgts[0]-pwgts[0]);
mincutorder = nswaps;
}
else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
newcut += (ed[higain]-id[higain]);
INC_DEC(pwgts[from], pwgts[to], vwgt[higain]);
break;
}
where[higain] = to;
moved[higain] = nswaps;
swaps[nswaps] = higain;
IFSET(ctrl->dbglvl, DBG_MOVEINFO,
printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], newcut, pwgts[0], pwgts[1]));
/**************************************************************
* 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];
oldgain = ed[k]-id[k];
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 */
PQueueDelete(&parts[where[k]], k, oldgain);
}
else { /* If it has not been moved, update its position in the queue */
if (moved[k] == -1)
PQueueUpdate(&parts[where[k]], k, oldgain, ed[k]-id[k]);
}
}
else {
if (ed[k] > 0) { /* It will now become a boundary vertex */
BNDInsert(nbnd, bndind, bndptr, k);
if (moved[k] == -1)
PQueueInsert(&parts[where[k]], k, ed[k]-id[k]);
}
}
}
}
/****************************************************************
* 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);
INC_DEC(pwgts[to], pwgts[(to+1)%2], vwgt[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);
if (bndptr[k] != -1 && ed[k] == 0)
BNDDelete(nbnd, bndind, bndptr, k);
if (bndptr[k] == -1 && ed[k] > 0)
BNDInsert(nbnd, bndind, bndptr, k);
}
}
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("\tMinimum cut: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));
graph->mincut = mincut;
graph->nbnd = nbnd;
if (mincutorder == -1 || mincut == initcut)
break;
}
PQueueFree(ctrl, &parts[0]);
PQueueFree(ctrl, &parts[1]);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}

View File

@ -0,0 +1,141 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* fortran.c
*
* This file contains code for the fortran to C interface
*
* Started 8/19/97
* George
*
* $Id: fortran.c,v 1.1 2003/07/16 15:55:02 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function changes the numbering to start from 0 instead of 1
**************************************************************************/
void Change2CNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy)
{
int i, nedges;
for (i=0; i<=nvtxs; i++)
xadj[i]--;
nedges = xadj[nvtxs];
for (i=0; i<nedges; i++)
adjncy[i]--;
}
/*************************************************************************
* This function changes the numbering to start from 1 instead of 0
**************************************************************************/
void Change2FNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vector)
{
int i, nedges;
for (i=0; i<nvtxs; i++)
vector[i]++;
nedges = xadj[nvtxs];
for (i=0; i<nedges; i++)
adjncy[i]++;
for (i=0; i<=nvtxs; i++)
xadj[i]++;
}
/*************************************************************************
* This function changes the numbering to start from 1 instead of 0
**************************************************************************/
void Change2FNumbering2(int nvtxs, idxtype *xadj, idxtype *adjncy)
{
int i, nedges;
nedges = xadj[nvtxs];
for (i=0; i<nedges; i++)
adjncy[i]++;
for (i=0; i<=nvtxs; i++)
xadj[i]++;
}
/*************************************************************************
* This function changes the numbering to start from 1 instead of 0
**************************************************************************/
void Change2FNumberingOrder(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *v1, idxtype *v2)
{
int i, nedges;
for (i=0; i<nvtxs; i++) {
v1[i]++;
v2[i]++;
}
nedges = xadj[nvtxs];
for (i=0; i<nedges; i++)
adjncy[i]++;
for (i=0; i<=nvtxs; i++)
xadj[i]++;
}
/*************************************************************************
* This function changes the numbering to start from 0 instead of 1
**************************************************************************/
void ChangeMesh2CNumbering(int n, idxtype *mesh)
{
int i;
for (i=0; i<n; i++)
mesh[i]--;
}
/*************************************************************************
* This function changes the numbering to start from 1 instead of 0
**************************************************************************/
void ChangeMesh2FNumbering(int n, idxtype *mesh, int nvtxs, idxtype *xadj, idxtype *adjncy)
{
int i, nedges;
for (i=0; i<n; i++)
mesh[i]++;
nedges = xadj[nvtxs];
for (i=0; i<nedges; i++)
adjncy[i]++;
for (i=0; i<=nvtxs; i++)
xadj[i]++;
}
/*************************************************************************
* This function changes the numbering to start from 1 instead of 0
**************************************************************************/
void ChangeMesh2FNumbering2(int n, idxtype *mesh, int ne, int nn, idxtype *epart, idxtype *npart)
{
int i, nedges;
for (i=0; i<n; i++)
mesh[i]++;
for (i=0; i<ne; i++)
epart[i]++;
for (i=0; i<nn; i++)
npart[i]++;
}

View File

@ -0,0 +1,312 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* frename.c
*
* This file contains some renaming routines to deal with different Fortran compilers
*
* Started 9/15/97
* George
*
* $Id: frename.c,v 1.1 2003/07/16 15:55:03 karypis Exp $
*
*/
#include <metis.h>
void METIS_PARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void metis_partgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void metis_partgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void metis_partgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void METIS_WPARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
{
METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
}
void metis_wpartgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
{
METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
}
void metis_wpartgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
{
METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
}
void metis_wpartgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
{
METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
}
void METIS_PARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void metis_partgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void metis_partgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void metis_partgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void METIS_WPARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
{
METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
}
void metis_wpartgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
{
METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
}
void metis_wpartgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
{
METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
}
void metis_wpartgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
{
METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
}
void METIS_EDGEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
void metis_edgend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
void metis_edgend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
void metis_edgend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
void METIS_NODEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
void metis_nodend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
void metis_nodend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
void metis_nodend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
void METIS_NODEWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm);
}
void metis_nodewnd(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm);
}
void metis_nodewnd_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm);
}
void metis_nodewnd__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm);
}
void METIS_PARTMESHNODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
}
void metis_partmeshnodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
}
void metis_partmeshnodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
}
void metis_partmeshnodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
}
void METIS_PARTMESHDUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
}
void metis_partmeshdual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
}
void metis_partmeshdual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
}
void metis_partmeshdual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
}
void METIS_MESHTONODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
{
METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
}
void metis_meshtonodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
{
METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
}
void metis_meshtonodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
{
METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
}
void metis_meshtonodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
{
METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
}
void METIS_MESHTODUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
{
METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
}
void metis_meshtodual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
{
METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
}
void metis_meshtodual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
{
METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
}
void metis_meshtodual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
{
METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
}
void METIS_ESTIMATEMEMORY(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
{
METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes);
}
void metis_estimatememory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
{
METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes);
}
void metis_estimatememory_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
{
METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes);
}
void metis_estimatememory__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
{
METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes);
}
void METIS_MCPARTGRAPHRECURSIVE(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void metis_mcpartgraphrecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void metis_mcpartgraphrecursive_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void metis_mcpartgraphrecursive__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
{
METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
}
void METIS_MCPARTGRAPHKWAY(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
{
METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part);
}
void metis_mcpartgraphkway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
{
METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part);
}
void metis_mcpartgraphkway_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
{
METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part);
}
void metis_mcpartgraphkway__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
{
METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part);
}
void METIS_PARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
{
METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part);
}
void metis_partgraphvkaway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
{
METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part);
}
void metis_partgraphvkaway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
{
METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part);
}
void metis_partgraphvkaway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
{
METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part);
}
void METIS_WPARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
{
METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part);
}
void metis_wpartgraphvkaway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
{
METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part);
}
void metis_wpartgraphvkaway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
{
METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part);
}
void metis_wpartgraphvkaway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
{
METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part);
}

View File

@ -0,0 +1,616 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* graph.c
*
* This file contains functions that deal with setting up the graphs
* for METIS.
*
* Started 7/25/97
* George
*
* $Id: graph.c,v 1.2 2003/07/31 06:14:01 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function sets up the graph from the user input
**************************************************************************/
void SetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon,
idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int wgtflag)
{
int i, j, k, sum, gsize;
float *nvwgt;
idxtype tvwgt[MAXNCON];
if (OpType == OP_KMETIS && ncon == 1 && (wgtflag&2) == 0 && (wgtflag&1) == 0) {
SetUpGraphKway(graph, nvtxs, xadj, adjncy);
return;
}
InitGraph(graph);
graph->nvtxs = nvtxs;
graph->nedges = xadj[nvtxs];
graph->ncon = ncon;
graph->xadj = xadj;
graph->adjncy = adjncy;
if (ncon == 1) { /* We are in the non mC mode */
gsize = 0;
if ((wgtflag&2) == 0)
gsize += nvtxs;
if ((wgtflag&1) == 0)
gsize += graph->nedges;
gsize += 2*nvtxs;
graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata");
/* Create the vertex/edge weight vectors if they are not supplied */
gsize = 0;
if ((wgtflag&2) == 0) {
vwgt = graph->vwgt = idxset(nvtxs, 1, graph->gdata);
gsize += nvtxs;
}
else
graph->vwgt = vwgt;
if ((wgtflag&1) == 0) {
adjwgt = graph->adjwgt = idxset(graph->nedges, 1, graph->gdata+gsize);
gsize += graph->nedges;
}
else
graph->adjwgt = adjwgt;
/* Compute the initial values of the adjwgtsum */
graph->adjwgtsum = graph->gdata + gsize;
gsize += nvtxs;
for (i=0; i<nvtxs; i++) {
sum = 0;
for (j=xadj[i]; j<xadj[i+1]; j++)
sum += adjwgt[j];
graph->adjwgtsum[i] = sum;
}
graph->cmap = graph->gdata + gsize;
gsize += nvtxs;
}
else { /* Set up the graph in MOC mode */
gsize = 0;
if ((wgtflag&1) == 0)
gsize += graph->nedges;
gsize += 2*nvtxs;
graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata");
gsize = 0;
for (i=0; i<ncon; i++)
tvwgt[i] = idxsum_strd(nvtxs, vwgt+i, ncon);
nvwgt = graph->nvwgt = fmalloc(ncon*nvtxs, "SetUpGraph: nvwgt");
for (i=0; i<nvtxs; i++) {
for (j=0; j<ncon; j++)
nvwgt[i*ncon+j] = (1.0*vwgt[i*ncon+j])/(1.0*tvwgt[j]);
}
/* Create the edge weight vectors if they are not supplied */
if ((wgtflag&1) == 0) {
adjwgt = graph->adjwgt = idxset(graph->nedges, 1, graph->gdata+gsize);
gsize += graph->nedges;
}
else
graph->adjwgt = adjwgt;
/* Compute the initial values of the adjwgtsum */
graph->adjwgtsum = graph->gdata + gsize;
gsize += nvtxs;
for (i=0; i<nvtxs; i++) {
sum = 0;
for (j=xadj[i]; j<xadj[i+1]; j++)
sum += adjwgt[j];
graph->adjwgtsum[i] = sum;
}
graph->cmap = graph->gdata + gsize;
gsize += nvtxs;
}
if (OpType != OP_KMETIS && OpType != OP_KVMETIS) {
graph->label = idxmalloc(nvtxs, "SetUpGraph: label");
for (i=0; i<nvtxs; i++)
graph->label[i] = i;
}
}
/*************************************************************************
* This function sets up the graph from the user input
**************************************************************************/
void SetUpGraphKway(GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy)
{
int i;
InitGraph(graph);
graph->nvtxs = nvtxs;
graph->nedges = xadj[nvtxs];
graph->ncon = 1;
graph->xadj = xadj;
graph->vwgt = NULL;
graph->adjncy = adjncy;
graph->adjwgt = NULL;
graph->gdata = idxmalloc(2*nvtxs, "SetUpGraph: gdata");
graph->adjwgtsum = graph->gdata;
graph->cmap = graph->gdata + nvtxs;
/* Compute the initial values of the adjwgtsum */
for (i=0; i<nvtxs; i++)
graph->adjwgtsum[i] = xadj[i+1]-xadj[i];
}
/*************************************************************************
* This function sets up the graph from the user input
**************************************************************************/
void SetUpGraph2(GraphType *graph, int nvtxs, int ncon, idxtype *xadj,
idxtype *adjncy, float *nvwgt, idxtype *adjwgt)
{
int i, j, sum;
InitGraph(graph);
graph->nvtxs = nvtxs;
graph->nedges = xadj[nvtxs];
graph->ncon = ncon;
graph->xadj = xadj;
graph->adjncy = adjncy;
graph->adjwgt = adjwgt;
graph->nvwgt = fmalloc(nvtxs*ncon, "SetUpGraph2: graph->nvwgt");
scopy(nvtxs*ncon, nvwgt, graph->nvwgt);
graph->gdata = idxmalloc(2*nvtxs, "SetUpGraph: gdata");
/* Compute the initial values of the adjwgtsum */
graph->adjwgtsum = graph->gdata;
for (i=0; i<nvtxs; i++) {
sum = 0;
for (j=xadj[i]; j<xadj[i+1]; j++)
sum += adjwgt[j];
graph->adjwgtsum[i] = sum;
}
graph->cmap = graph->gdata+nvtxs;
graph->label = idxmalloc(nvtxs, "SetUpGraph: label");
for (i=0; i<nvtxs; i++)
graph->label[i] = i;
}
/*************************************************************************
* This function sets up the graph from the user input
**************************************************************************/
void VolSetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon, idxtype *xadj,
idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int wgtflag)
{
int i, j, k, sum, gsize;
idxtype *adjwgt;
float *nvwgt;
idxtype tvwgt[MAXNCON];
InitGraph(graph);
graph->nvtxs = nvtxs;
graph->nedges = xadj[nvtxs];
graph->ncon = ncon;
graph->xadj = xadj;
graph->adjncy = adjncy;
if (ncon == 1) { /* We are in the non mC mode */
gsize = graph->nedges; /* This is for the edge weights */
if ((wgtflag&2) == 0)
gsize += nvtxs; /* vwgts */
if ((wgtflag&1) == 0)
gsize += nvtxs; /* vsize */
gsize += 2*nvtxs;
graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata");
/* Create the vertex/edge weight vectors if they are not supplied */
gsize = 0;
if ((wgtflag&2) == 0) {
vwgt = graph->vwgt = idxset(nvtxs, 1, graph->gdata);
gsize += nvtxs;
}
else
graph->vwgt = vwgt;
if ((wgtflag&1) == 0) {
vsize = graph->vsize = idxset(nvtxs, 1, graph->gdata);
gsize += nvtxs;
}
else
graph->vsize = vsize;
/* Allocate memory for edge weights and initialize them to the sum of the vsize */
adjwgt = graph->adjwgt = graph->gdata+gsize;
gsize += graph->nedges;
for (i=0; i<nvtxs; i++) {
for (j=xadj[i]; j<xadj[i+1]; j++)
adjwgt[j] = 1+vsize[i]+vsize[adjncy[j]];
}
/* Compute the initial values of the adjwgtsum */
graph->adjwgtsum = graph->gdata + gsize;
gsize += nvtxs;
for (i=0; i<nvtxs; i++) {
sum = 0;
for (j=xadj[i]; j<xadj[i+1]; j++)
sum += adjwgt[j];
graph->adjwgtsum[i] = sum;
}
graph->cmap = graph->gdata + gsize;
gsize += nvtxs;
}
else { /* Set up the graph in MOC mode */
gsize = graph->nedges;
if ((wgtflag&1) == 0)
gsize += nvtxs;
gsize += 2*nvtxs;
graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata");
gsize = 0;
/* Create the normalized vertex weights along each constrain */
if ((wgtflag&2) == 0)
vwgt = idxsmalloc(nvtxs, 1, "SetUpGraph: vwgt");
for (i=0; i<ncon; i++)
tvwgt[i] = idxsum_strd(nvtxs, vwgt+i, ncon);
nvwgt = graph->nvwgt = fmalloc(ncon*nvtxs, "SetUpGraph: nvwgt");
for (i=0; i<nvtxs; i++) {
for (j=0; j<ncon; j++)
nvwgt[i*ncon+j] = (1.0*vwgt[i*ncon+j])/(1.0*tvwgt[j]);
}
if ((wgtflag&2) == 0)
free(vwgt);
/* Create the vsize vector if it is not supplied */
if ((wgtflag&1) == 0) {
vsize = graph->vsize = idxset(nvtxs, 1, graph->gdata);
gsize += nvtxs;
}
else
graph->vsize = vsize;
/* Allocate memory for edge weights and initialize them to the sum of the vsize */
adjwgt = graph->adjwgt = graph->gdata+gsize;
gsize += graph->nedges;
for (i=0; i<nvtxs; i++) {
for (j=xadj[i]; j<xadj[i+1]; j++)
adjwgt[j] = 1+vsize[i]+vsize[adjncy[j]];
}
/* Compute the initial values of the adjwgtsum */
graph->adjwgtsum = graph->gdata + gsize;
gsize += nvtxs;
for (i=0; i<nvtxs; i++) {
sum = 0;
for (j=xadj[i]; j<xadj[i+1]; j++)
sum += adjwgt[j];
graph->adjwgtsum[i] = sum;
}
graph->cmap = graph->gdata + gsize;
gsize += nvtxs;
}
if (OpType != OP_KVMETIS) {
graph->label = idxmalloc(nvtxs, "SetUpGraph: label");
for (i=0; i<nvtxs; i++)
graph->label[i] = i;
}
}
/*************************************************************************
* This function randomly permutes the adjacency lists of a graph
**************************************************************************/
void RandomizeGraph(GraphType *graph)
{
int i, j, k, l, tmp, nvtxs;
idxtype *xadj, *adjncy, *adjwgt;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
for (i=0; i<nvtxs; i++) {
l = xadj[i+1]-xadj[i];
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = xadj[i] + RandomInRange(l);
SWAP(adjncy[j], adjncy[k], tmp);
SWAP(adjwgt[j], adjwgt[k], tmp);
}
}
}
/*************************************************************************
* This function checks whether or not partition pid is contigous
**************************************************************************/
int IsConnectedSubdomain(CtrlType *ctrl, GraphType *graph, int pid, int report)
{
int i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
idxtype *xadj, *adjncy, *where, *touched, *queue;
idxtype *cptr;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
where = graph->where;
touched = idxsmalloc(nvtxs, 0, "IsConnected: touched");
queue = idxmalloc(nvtxs, "IsConnected: queue");
cptr = idxmalloc(nvtxs+1, "IsConnected: cptr");
nleft = 0;
for (i=0; i<nvtxs; i++) {
if (where[i] == pid)
nleft++;
}
for (i=0; i<nvtxs; i++) {
if (where[i] == pid)
break;
}
touched[i] = 1;
queue[0] = i;
first = 0; last = 1;
cptr[0] = 0; /* This actually points to queue */
ncmps = 0;
while (first != nleft) {
if (first == last) { /* Find another starting vertex */
cptr[++ncmps] = first;
for (i=0; i<nvtxs; i++) {
if (where[i] == pid && !touched[i])
break;
}
queue[last++] = i;
touched[i] = 1;
}
i = queue[first++];
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (where[k] == pid && !touched[k]) {
queue[last++] = k;
touched[k] = 1;
}
}
}
cptr[++ncmps] = first;
if (ncmps > 1 && report) {
printf("The graph has %d connected components in partition %d:\t", ncmps, pid);
for (i=0; i<ncmps; i++) {
wgt = 0;
for (j=cptr[i]; j<cptr[i+1]; j++)
wgt += graph->vwgt[queue[j]];
printf("[%5d %5d] ", cptr[i+1]-cptr[i], wgt);
/*
if (cptr[i+1]-cptr[i] == 1)
printf("[%d %d] ", queue[cptr[i]], xadj[queue[cptr[i]]+1]-xadj[queue[cptr[i]]]);
*/
}
printf("\n");
}
GKfree(&touched, &queue, &cptr, LTERM);
return (ncmps == 1 ? 1 : 0);
}
/*************************************************************************
* This function checks whether a graph is contigous or not
**************************************************************************/
int IsConnected(CtrlType *ctrl, GraphType *graph, int report)
{
int i, j, k, nvtxs, first, last;
idxtype *xadj, *adjncy, *touched, *queue;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
touched = idxsmalloc(nvtxs, 0, "IsConnected: touched");
queue = idxmalloc(nvtxs, "IsConnected: queue");
touched[0] = 1;
queue[0] = 0;
first = 0; last = 1;
while (first < last) {
i = queue[first++];
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (!touched[k]) {
queue[last++] = k;
touched[k] = 1;
}
}
}
if (first != nvtxs && report)
printf("The graph is not connected. It has %d disconnected vertices!\n", nvtxs-first);
return (first == nvtxs ? 1 : 0);
}
/*************************************************************************
* This function checks whether or not partition pid is contigous
**************************************************************************/
int IsConnected2(GraphType *graph, int report)
{
int i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
idxtype *xadj, *adjncy, *where, *touched, *queue;
idxtype *cptr;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
where = graph->where;
touched = idxsmalloc(nvtxs, 0, "IsConnected: touched");
queue = idxmalloc(nvtxs, "IsConnected: queue");
cptr = idxmalloc(nvtxs+1, "IsConnected: cptr");
nleft = nvtxs;
touched[0] = 1;
queue[0] = 0;
first = 0; last = 1;
cptr[0] = 0; /* This actually points to queue */
ncmps = 0;
while (first != nleft) {
if (first == last) { /* Find another starting vertex */
cptr[++ncmps] = first;
for (i=0; i<nvtxs; i++) {
if (!touched[i])
break;
}
queue[last++] = i;
touched[i] = 1;
}
i = queue[first++];
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (!touched[k]) {
queue[last++] = k;
touched[k] = 1;
}
}
}
cptr[++ncmps] = first;
if (ncmps > 1 && report) {
printf("%d connected components:\t", ncmps);
for (i=0; i<ncmps; i++) {
if (cptr[i+1]-cptr[i] > 200)
printf("[%5d] ", cptr[i+1]-cptr[i]);
}
printf("\n");
}
GKfree(&touched, &queue, &cptr, LTERM);
return (ncmps == 1 ? 1 : 0);
}
/*************************************************************************
* This function returns the number of connected components in cptr,cind
* The separator of the graph is used to split it and then find its components.
**************************************************************************/
int FindComponents(CtrlType *ctrl, GraphType *graph, idxtype *cptr, idxtype *cind)
{
int i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
idxtype *xadj, *adjncy, *where, *touched, *queue;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
where = graph->where;
touched = idxsmalloc(nvtxs, 0, "IsConnected: queue");
for (i=0; i<graph->nbnd; i++)
touched[graph->bndind[i]] = 1;
queue = cind;
nleft = 0;
for (i=0; i<nvtxs; i++) {
if (where[i] != 2)
nleft++;
}
for (i=0; i<nvtxs; i++) {
if (where[i] != 2)
break;
}
touched[i] = 1;
queue[0] = i;
first = 0; last = 1;
cptr[0] = 0; /* This actually points to queue */
ncmps = 0;
while (first != nleft) {
if (first == last) { /* Find another starting vertex */
cptr[++ncmps] = first;
for (i=0; i<nvtxs; i++) {
if (!touched[i])
break;
}
queue[last++] = i;
touched[i] = 1;
}
i = queue[first++];
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (!touched[k]) {
queue[last++] = k;
touched[k] = 1;
}
}
}
cptr[++ncmps] = first;
free(touched);
return ncmps;
}

View File

@ -0,0 +1,425 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* initpart.c
*
* This file contains code that performs the initial partition of the
* coarsest graph
*
* Started 7/23/97
* George
*
* $Id: initpart.c,v 1.2 2003/07/31 16:23:29 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function computes the initial bisection of the coarsest graph
**************************************************************************/
void Init2WayPartition(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
{
int dbglvl;
dbglvl = ctrl->dbglvl;
IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE);
IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
switch (ctrl->IType) {
case IPART_GGPKL:
if (graph->nedges == 0)
RandomBisection(ctrl, graph, tpwgts, ubfactor);
else
GrowBisection(ctrl, graph, tpwgts, ubfactor);
break;
case 3:
RandomBisection(ctrl, graph, tpwgts, ubfactor);
break;
default:
errexit("Unknown initial partition type: %d\n", ctrl->IType);
}
IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d\n", graph->mincut));
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
ctrl->dbglvl = dbglvl;
/*
IsConnectedSubdomain(ctrl, graph, 0);
IsConnectedSubdomain(ctrl, graph, 1);
*/
}
/*************************************************************************
* This function computes the initial bisection of the coarsest graph
**************************************************************************/
void InitSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor)
{
int dbglvl;
dbglvl = ctrl->dbglvl;
IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE);
IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
GrowBisectionNode(ctrl, graph, ubfactor);
Compute2WayNodePartitionParams(ctrl, graph);
IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Sep: %d\n", graph->mincut));
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
ctrl->dbglvl = dbglvl;
}
/*************************************************************************
* This function takes a graph and produces a bisection by using a region
* growing algorithm. The resulting partition is returned in
* graph->where
**************************************************************************/
void GrowBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
{
int i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where;
idxtype *queue, *touched, *gain, *bestwhere;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
Allocate2WayPartitionMemory(ctrl, graph);
where = graph->where;
bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
queue = idxmalloc(nvtxs, "BisectGraph: queue");
touched = idxmalloc(nvtxs, "BisectGraph: touched");
ASSERTP(tpwgts[0]+tpwgts[1] == idxsum(nvtxs, vwgt), ("%d %d\n", tpwgts[0]+tpwgts[1], idxsum(nvtxs, vwgt)));
maxpwgt[0] = ubfactor*tpwgts[0];
maxpwgt[1] = ubfactor*tpwgts[1];
minpwgt[0] = (1.0/ubfactor)*tpwgts[0];
minpwgt[1] = (1.0/ubfactor)*tpwgts[1];
nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
bestcut = idxsum(nvtxs, graph->adjwgtsum)+1; /* The +1 is for the 0 edges case */
for (; nbfs>0; nbfs--) {
idxset(nvtxs, 0, touched);
pwgts[1] = tpwgts[0]+tpwgts[1];
pwgts[0] = 0;
idxset(nvtxs, 1, where);
queue[0] = RandomInRange(nvtxs);
touched[queue[0]] = 1;
first = 0; last = 1;
nleft = nvtxs-1;
drain = 0;
/* Start the BFS from queue to get a partition */
for (;;) {
if (first == last) { /* Empty. Disconnected graph! */
if (nleft == 0 || drain)
break;
k = RandomInRange(nleft);
for (i=0; i<nvtxs; i++) {
if (touched[i] == 0) {
if (k == 0)
break;
else
k--;
}
}
queue[0] = i;
touched[i] = 1;
first = 0; last = 1;;
nleft--;
}
i = queue[first++];
if (pwgts[0] > 0 && pwgts[1]-vwgt[i] < minpwgt[1]) {
drain = 1;
continue;
}
where[i] = 0;
INC_DEC(pwgts[0], pwgts[1], vwgt[i]);
if (pwgts[1] <= maxpwgt[1])
break;
drain = 0;
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (touched[k] == 0) {
queue[last++] = k;
touched[k] = 1;
nleft--;
}
}
}
/* Check to see if we hit any bad limiting cases */
if (pwgts[1] == 0) {
i = RandomInRange(nvtxs);
where[i] = 1;
INC_DEC(pwgts[1], pwgts[0], vwgt[i]);
}
/*************************************************************
* Do some partition refinement
**************************************************************/
Compute2WayPartitionParams(ctrl, graph);
/*printf("IPART: %3d [%5d %5d] [%5d %5d] %5d\n", graph->nvtxs, pwgts[0], pwgts[1], graph->pwgts[0], graph->pwgts[1], graph->mincut); */
Balance2Way(ctrl, graph, tpwgts, ubfactor);
/*printf("BPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut);*/
FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
/*printf("RPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut);*/
if (bestcut > graph->mincut) {
bestcut = graph->mincut;
idxcopy(nvtxs, where, bestwhere);
if (bestcut == 0)
break;
}
}
graph->mincut = bestcut;
idxcopy(nvtxs, bestwhere, where);
GKfree(&bestwhere, &queue, &touched, LTERM);
}
/*************************************************************************
* This function takes a graph and produces a bisection by using a region
* growing algorithm. The resulting partition is returned in
* graph->where
**************************************************************************/
void GrowBisectionNode(CtrlType *ctrl, GraphType *graph, float ubfactor)
{
int i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], tpwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *bndind;
idxtype *queue, *touched, *gain, *bestwhere;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
queue = idxmalloc(nvtxs, "BisectGraph: queue");
touched = idxmalloc(nvtxs, "BisectGraph: touched");
tpwgts[0] = idxsum(nvtxs, vwgt);
tpwgts[1] = tpwgts[0]/2;
tpwgts[0] -= tpwgts[1];
maxpwgt[0] = ubfactor*tpwgts[0];
maxpwgt[1] = ubfactor*tpwgts[1];
minpwgt[0] = (1.0/ubfactor)*tpwgts[0];
minpwgt[1] = (1.0/ubfactor)*tpwgts[1];
/* Allocate memory for graph->rdata. Allocate sufficient memory for both edge and node */
graph->rdata = idxmalloc(5*nvtxs+3, "GrowBisectionNode: graph->rdata");
graph->pwgts = graph->rdata;
graph->where = graph->rdata + 3;
graph->bndptr = graph->rdata + nvtxs + 3;
graph->bndind = graph->rdata + 2*nvtxs + 3;
graph->nrinfo = (NRInfoType *)(graph->rdata + 3*nvtxs + 3);
graph->id = graph->rdata + 3*nvtxs + 3;
graph->ed = graph->rdata + 4*nvtxs + 3;
where = graph->where;
bndind = graph->bndind;
nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
bestcut = tpwgts[0]+tpwgts[1];
for (nbfs++; nbfs>0; nbfs--) {
idxset(nvtxs, 0, touched);
pwgts[1] = tpwgts[0]+tpwgts[1];
pwgts[0] = 0;
idxset(nvtxs, 1, where);
queue[0] = RandomInRange(nvtxs);
touched[queue[0]] = 1;
first = 0; last = 1;
nleft = nvtxs-1;
drain = 0;
/* Start the BFS from queue to get a partition */
if (nbfs >= 1) {
for (;;) {
if (first == last) { /* Empty. Disconnected graph! */
if (nleft == 0 || drain)
break;
k = RandomInRange(nleft);
for (i=0; i<nvtxs; i++) {
if (touched[i] == 0) {
if (k == 0)
break;
else
k--;
}
}
queue[0] = i;
touched[i] = 1;
first = 0; last = 1;;
nleft--;
}
i = queue[first++];
if (pwgts[1]-vwgt[i] < minpwgt[1]) {
drain = 1;
continue;
}
where[i] = 0;
INC_DEC(pwgts[0], pwgts[1], vwgt[i]);
if (pwgts[1] <= maxpwgt[1])
break;
drain = 0;
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (touched[k] == 0) {
queue[last++] = k;
touched[k] = 1;
nleft--;
}
}
}
}
/*************************************************************
* Do some partition refinement
**************************************************************/
Compute2WayPartitionParams(ctrl, graph);
Balance2Way(ctrl, graph, tpwgts, ubfactor);
FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
/* Construct and refine the vertex separator */
for (i=0; i<graph->nbnd; i++)
where[bndind[i]] = 2;
Compute2WayNodePartitionParams(ctrl, graph);
FM_2WayNodeRefine(ctrl, graph, ubfactor, 6);
/* printf("ISep: [%d %d %d] %d\n", graph->pwgts[0], graph->pwgts[1], graph->pwgts[2], bestcut); */
if (bestcut > graph->mincut) {
bestcut = graph->mincut;
idxcopy(nvtxs, where, bestwhere);
}
}
graph->mincut = bestcut;
idxcopy(nvtxs, bestwhere, where);
Compute2WayNodePartitionParams(ctrl, graph);
GKfree(&bestwhere, &queue, &touched, LTERM);
}
/*************************************************************************
* This function takes a graph and produces a bisection by using a region
* growing algorithm. The resulting partition is returned in
* graph->where
**************************************************************************/
void RandomBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
{
int i, ii, j, k, nvtxs, pwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where;
idxtype *perm, *bestwhere;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
Allocate2WayPartitionMemory(ctrl, graph);
where = graph->where;
bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
perm = idxmalloc(nvtxs, "BisectGraph: queue");
ASSERTP(tpwgts[0]+tpwgts[1] == idxsum(nvtxs, vwgt), ("%d %d\n", tpwgts[0]+tpwgts[1], idxsum(nvtxs, vwgt)));
maxpwgt[0] = ubfactor*tpwgts[0];
maxpwgt[1] = ubfactor*tpwgts[1];
minpwgt[0] = (1.0/ubfactor)*tpwgts[0];
minpwgt[1] = (1.0/ubfactor)*tpwgts[1];
nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
bestcut = idxsum(nvtxs, graph->adjwgtsum)+1; /* The +1 is for the 0 edges case */
for (; nbfs>0; nbfs--) {
RandomPermute(nvtxs, perm, 1);
idxset(nvtxs, 1, where);
pwgts[1] = tpwgts[0]+tpwgts[1];
pwgts[0] = 0;
if (nbfs != 1) {
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (pwgts[0]+vwgt[i] < maxpwgt[0]) {
where[i] = 0;
pwgts[0] += vwgt[i];
pwgts[1] -= vwgt[i];
if (pwgts[0] > minpwgt[0])
break;
}
}
}
/*************************************************************
* Do some partition refinement
**************************************************************/
Compute2WayPartitionParams(ctrl, graph);
/* printf("IPART: %3d [%5d %5d] [%5d %5d] %5d\n", graph->nvtxs, pwgts[0], pwgts[1], graph->pwgts[0], graph->pwgts[1], graph->mincut); */
Balance2Way(ctrl, graph, tpwgts, ubfactor);
/* printf("BPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut); */
FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
/* printf("RPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut); */
if (bestcut > graph->mincut) {
bestcut = graph->mincut;
idxcopy(nvtxs, where, bestwhere);
if (bestcut == 0)
break;
}
}
graph->mincut = bestcut;
idxcopy(nvtxs, bestwhere, where);
GKfree(&bestwhere, &perm, LTERM);
}

View File

@ -0,0 +1,129 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* kmetis.c
*
* This file contains the top level routines for the multilevel k-way partitioning
* algorithm KMETIS.
*
* Started 7/28/97
* George
*
* $Id: kmetis.c,v 1.1 2003/07/16 15:55:04 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point for KMETIS
**************************************************************************/
void METIS_PartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
int *options, int *edgecut, idxtype *part)
{
int i;
float *tpwgts;
tpwgts = fmalloc(*nparts, "KMETIS: tpwgts");
for (i=0; i<*nparts; i++)
tpwgts[i] = 1.0/(1.0*(*nparts));
METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts,
tpwgts, options, edgecut, part);
free(tpwgts);
}
/*************************************************************************
* This function is the entry point for KWMETIS
**************************************************************************/
void METIS_WPartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
float *tpwgts, int *options, int *edgecut, idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
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*log2Int(*nparts)), 20*(*nparts));
ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo);
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
*edgecut = MlevelKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
if (*numflag == 1)
Change2FNumbering(*nvtxs, xadj, adjncy, part);
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
int MlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor)
{
int i, j, nvtxs, tvwgt, tpwgts2[2];
GraphType *cgraph;
int wgtflag=3, numflag=0, options[10], edgecut;
cgraph = Coarsen2Way(ctrl, graph);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
AllocateKWayPartitionMemory(ctrl, cgraph, nparts);
options[0] = 1;
options[OPTION_CTYPE] = MATCH_SHEMKWAY;
options[OPTION_ITYPE] = IPART_GGPKL;
options[OPTION_RTYPE] = RTYPE_FM;
options[OPTION_DBGLVL] = 0;
METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt,
cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options,
&edgecut, cgraph->where);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut));
IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where));
RefineKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor);
idxcopy(graph->nvtxs, graph->where, part);
GKfree(&graph->gdata, &graph->rdata, LTERM);
return graph->mincut;
}

View File

@ -0,0 +1,130 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* kvmetis.c
*
* This file contains the top level routines for the multilevel k-way partitioning
* algorithm KMETIS.
*
* Started 7/28/97
* George
*
* $Id: kvmetis.c,v 1.1 2003/07/16 15:55:04 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point for KMETIS
**************************************************************************/
void METIS_PartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *vsize, int *wgtflag, int *numflag, int *nparts,
int *options, int *volume, idxtype *part)
{
int i;
float *tpwgts;
tpwgts = fmalloc(*nparts, "KMETIS: tpwgts");
for (i=0; i<*nparts; i++)
tpwgts[i] = 1.0/(1.0*(*nparts));
METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts,
tpwgts, options, volume, part);
free(tpwgts);
}
/*************************************************************************
* This function is the entry point for KWMETIS
**************************************************************************/
void METIS_WPartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *vsize, int *wgtflag, int *numflag, int *nparts,
float *tpwgts, int *options, int *volume, idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
VolSetUpGraph(&graph, OP_KVMETIS, *nvtxs, 1, xadj, adjncy, vwgt, vsize, *wgtflag);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = KVMETIS_CTYPE;
ctrl.IType = KVMETIS_ITYPE;
ctrl.RType = KVMETIS_RTYPE;
ctrl.dbglvl = KVMETIS_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_KVMETIS;
ctrl.CoarsenTo = amax((*nvtxs)/(40*log2Int(*nparts)), 20*(*nparts));
ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo);
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
*volume = MlevelVolKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
if (*numflag == 1)
Change2FNumbering(*nvtxs, xadj, adjncy, part);
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
int MlevelVolKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part,
float *tpwgts, float ubfactor)
{
int i, j, nvtxs, tvwgt, tpwgts2[2];
GraphType *cgraph;
int wgtflag=3, numflag=0, options[10], edgecut;
cgraph = Coarsen2Way(ctrl, graph);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
AllocateVolKWayPartitionMemory(ctrl, cgraph, nparts);
options[0] = 1;
options[OPTION_CTYPE] = MATCH_SHEMKWAY;
options[OPTION_ITYPE] = IPART_GGPKL;
options[OPTION_RTYPE] = RTYPE_FM;
options[OPTION_DBGLVL] = 0;
METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt,
cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options,
&edgecut, cgraph->where);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut));
IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where));
RefineVolKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor);
idxcopy(graph->nvtxs, graph->where, part);
GKfree(&graph->gdata, &graph->rdata, LTERM);
return graph->minvol;
}

View File

@ -0,0 +1,672 @@
/*
* kwayfm.c
*
* This file contains code that implements the multilevel k-way refinement
*
* Started 7/28/97
* George
*
* $Id: kwayfm.c,v 1.1 2003/07/16 15:55:04 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function performs k-way refinement
**************************************************************************/
void Random_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor)
{
int i, ii, iii, j, jj, k, l, pass, nvtxs, nmoves, nbnd, tvwgt, myndegrees;
int from, me, to, oldcut, vwgt, gain;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts;
EDegreeType *myedegrees;
RInfoType *myrinfo;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
bndptr = graph->bndptr;
bndind = graph->bndind;
where = graph->where;
pwgts = graph->pwgts;
/* Setup the weight intervals of the various subdomains */
minwgt = idxwspacemalloc(ctrl, nparts);
maxwgt = idxwspacemalloc(ctrl, nparts);
itpwgts = idxwspacemalloc(ctrl, nparts);
tvwgt = idxsum(nparts, pwgts);
ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
for (i=0; i<nparts; i++) {
itpwgts[i] = tpwgts[i]*tvwgt;
maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
}
perm = idxwspacemalloc(ctrl, nvtxs);
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n",
pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
graph->mincut));
for (pass=0; pass<npasses; pass++) {
ASSERT(ComputeCut(graph, where) == graph->mincut);
oldcut = graph->mincut;
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (nmoves=iii=0; iii<graph->nbnd; iii++) {
ii = perm[iii];
if (ii >= nbnd)
continue;
i = bndind[ii];
myrinfo = graph->rinfo+i;
if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */
from = where[i];
vwgt = graph->vwgt[i];
if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from])
continue; /* This cannot be moved! */
myedegrees = myrinfo->edegrees;
myndegrees = myrinfo->ndegrees;
j = myrinfo->id;
for (k=0; k<myndegrees; k++) {
to = myedegrees[k].pid;
gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */
if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain && gain >= 0)
break;
}
if (k == myndegrees)
continue; /* break out if you did not find a candidate */
for (j=k+1; j<myndegrees; j++) {
to = myedegrees[j].pid;
if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) ||
(myedegrees[j].ed == myedegrees[k].ed &&
itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]))
k = j;
}
to = myedegrees[k].pid;
j = 0;
if (myedegrees[k].ed-myrinfo->id > 0)
j = 1;
else if (myedegrees[k].ed-myrinfo->id == 0) {
if ((iii&7) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])
j = 1;
}
if (j == 0)
continue;
/*=====================================================================
* If we got here, we can now move the vertex from 'from' to 'to'
*======================================================================*/
graph->mincut -= myedegrees[k].ed-myrinfo->id;
IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
/* Update where, weight, and ID/ED information of the vertex you moved */
where[i] = to;
INC_DEC(pwgts[to], pwgts[from], vwgt);
myrinfo->ed += myrinfo->id-myedegrees[k].ed;
SWAP(myrinfo->id, myedegrees[k].ed, j);
if (myedegrees[k].ed == 0)
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].pid = from;
if (myrinfo->ed-myrinfo->id < 0)
BNDDelete(nbnd, bndind, bndptr, i);
/* Update the degrees of adjacent vertices */
for (j=xadj[i]; j<xadj[i+1]; j++) {
ii = adjncy[j];
me = where[ii];
myrinfo = graph->rinfo+ii;
if (myrinfo->edegrees == NULL) {
myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
}
myedegrees = myrinfo->edegrees;
ASSERT(CheckRInfo(myrinfo));
if (me == from) {
INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1)
BNDInsert(nbnd, bndind, bndptr, ii);
}
else if (me == to) {
INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1)
BNDDelete(nbnd, bndind, bndptr, ii);
}
/* Remove contribution from the .ed of 'from' */
if (me != from) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == from) {
if (myedegrees[k].ed == adjwgt[j])
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].ed -= adjwgt[j];
break;
}
}
}
/* Add contribution to the .ed of 'to' */
if (me != to) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == to) {
myedegrees[k].ed += adjwgt[j];
break;
}
}
if (k == myrinfo->ndegrees) {
myedegrees[myrinfo->ndegrees].pid = to;
myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
}
}
ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
ASSERT(CheckRInfo(myrinfo));
}
nmoves++;
}
}
graph->nbnd = nbnd;
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n",
pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, ComputeVolume(graph, where)));
if (graph->mincut == oldcut)
break;
}
idxwspacefree(ctrl, nparts);
idxwspacefree(ctrl, nparts);
idxwspacefree(ctrl, nparts);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function performs k-way refinement
**************************************************************************/
void Greedy_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
{
int i, ii, iii, j, jj, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain;
int from, me, to, oldcut, vwgt;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts;
EDegreeType *myedegrees;
RInfoType *myrinfo;
PQueueType queue;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
bndind = graph->bndind;
bndptr = graph->bndptr;
where = graph->where;
pwgts = graph->pwgts;
/* Setup the weight intervals of the various subdomains */
minwgt = idxwspacemalloc(ctrl, nparts);
maxwgt = idxwspacemalloc(ctrl, nparts);
itpwgts = idxwspacemalloc(ctrl, nparts);
tvwgt = idxsum(nparts, pwgts);
ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
for (i=0; i<nparts; i++) {
itpwgts[i] = tpwgts[i]*tvwgt;
maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
}
perm = idxwspacemalloc(ctrl, nvtxs);
moved = idxwspacemalloc(ctrl, nvtxs);
PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]);
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n",
pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
graph->mincut));
for (pass=0; pass<npasses; pass++) {
ASSERT(ComputeCut(graph, where) == graph->mincut);
PQueueReset(&queue);
idxset(nvtxs, -1, moved);
oldcut = graph->mincut;
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (ii=0; ii<nbnd; ii++) {
i = bndind[perm[ii]];
PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id);
moved[i] = 2;
}
for (iii=0;;iii++) {
if ((i = PQueueGetMax(&queue)) == -1)
break;
moved[i] = 1;
myrinfo = graph->rinfo+i;
from = where[i];
vwgt = graph->vwgt[i];
if (pwgts[from]-vwgt < minwgt[from])
continue; /* This cannot be moved! */
myedegrees = myrinfo->edegrees;
myndegrees = myrinfo->ndegrees;
j = myrinfo->id;
for (k=0; k<myndegrees; k++) {
to = myedegrees[k].pid;
gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */
if (pwgts[to]+vwgt <= maxwgt[to]+gain && gain >= 0)
break;
}
if (k == myndegrees)
continue; /* break out if you did not find a candidate */
for (j=k+1; j<myndegrees; j++) {
to = myedegrees[j].pid;
if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) ||
(myedegrees[j].ed == myedegrees[k].ed &&
itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]))
k = j;
}
to = myedegrees[k].pid;
j = 0;
if (myedegrees[k].ed-myrinfo->id > 0)
j = 1;
else if (myedegrees[k].ed-myrinfo->id == 0) {
if ((iii&7) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])
j = 1;
}
if (j == 0)
continue;
/*=====================================================================
* If we got here, we can now move the vertex from 'from' to 'to'
*======================================================================*/
graph->mincut -= myedegrees[k].ed-myrinfo->id;
IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
/* Update where, weight, and ID/ED information of the vertex you moved */
where[i] = to;
INC_DEC(pwgts[to], pwgts[from], vwgt);
myrinfo->ed += myrinfo->id-myedegrees[k].ed;
SWAP(myrinfo->id, myedegrees[k].ed, j);
if (myedegrees[k].ed == 0)
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].pid = from;
if (myrinfo->ed < myrinfo->id)
BNDDelete(nbnd, bndind, bndptr, i);
/* Update the degrees of adjacent vertices */
for (j=xadj[i]; j<xadj[i+1]; j++) {
ii = adjncy[j];
me = where[ii];
myrinfo = graph->rinfo+ii;
if (myrinfo->edegrees == NULL) {
myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
}
myedegrees = myrinfo->edegrees;
ASSERT(CheckRInfo(myrinfo));
oldgain = (myrinfo->ed-myrinfo->id);
if (me == from) {
INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1)
BNDInsert(nbnd, bndind, bndptr, ii);
}
else if (me == to) {
INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1)
BNDDelete(nbnd, bndind, bndptr, ii);
}
/* Remove contribution from the .ed of 'from' */
if (me != from) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == from) {
if (myedegrees[k].ed == adjwgt[j])
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].ed -= adjwgt[j];
break;
}
}
}
/* Add contribution to the .ed of 'to' */
if (me != to) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == to) {
myedegrees[k].ed += adjwgt[j];
break;
}
}
if (k == myrinfo->ndegrees) {
myedegrees[myrinfo->ndegrees].pid = to;
myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
}
}
/* Update the queue */
if (me == to || me == from) {
gain = myrinfo->ed-myrinfo->id;
if (moved[ii] == 2) {
if (gain >= 0)
PQueueUpdate(&queue, ii, oldgain, gain);
else {
PQueueDelete(&queue, ii, oldgain);
moved[ii] = -1;
}
}
else if (moved[ii] == -1 && gain >= 0) {
PQueueInsert(&queue, ii, gain);
moved[ii] = 2;
}
}
ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
ASSERT(CheckRInfo(myrinfo));
}
}
graph->nbnd = nbnd;
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Cut: %6d\n",
pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, graph->mincut));
if (graph->mincut == oldcut)
break;
}
PQueueFree(ctrl, &queue);
idxwspacefree(ctrl, nparts);
idxwspacefree(ctrl, nparts);
idxwspacefree(ctrl, nparts);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function performs k-way refinement
**************************************************************************/
void Greedy_KWayEdgeBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
{
int i, ii, iii, j, jj, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain, nmoves;
int from, me, to, oldcut, vwgt;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts;
EDegreeType *myedegrees;
RInfoType *myrinfo;
PQueueType queue;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
bndind = graph->bndind;
bndptr = graph->bndptr;
where = graph->where;
pwgts = graph->pwgts;
/* Setup the weight intervals of the various subdomains */
minwgt = idxwspacemalloc(ctrl, nparts);
maxwgt = idxwspacemalloc(ctrl, nparts);
itpwgts = idxwspacemalloc(ctrl, nparts);
tvwgt = idxsum(nparts, pwgts);
ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
for (i=0; i<nparts; i++) {
itpwgts[i] = tpwgts[i]*tvwgt;
maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
}
perm = idxwspacemalloc(ctrl, nvtxs);
moved = idxwspacemalloc(ctrl, nvtxs);
PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]);
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d [B]\n",
pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
graph->mincut));
for (pass=0; pass<npasses; pass++) {
ASSERT(ComputeCut(graph, where) == graph->mincut);
/* Check to see if things are out of balance, given the tolerance */
for (i=0; i<nparts; i++) {
if (pwgts[i] > maxwgt[i])
break;
}
if (i == nparts) /* Things are balanced. Return right away */
break;
PQueueReset(&queue);
idxset(nvtxs, -1, moved);
oldcut = graph->mincut;
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (ii=0; ii<nbnd; ii++) {
i = bndind[perm[ii]];
PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id);
moved[i] = 2;
}
nmoves = 0;
for (;;) {
if ((i = PQueueGetMax(&queue)) == -1)
break;
moved[i] = 1;
myrinfo = graph->rinfo+i;
from = where[i];
vwgt = graph->vwgt[i];
if (pwgts[from]-vwgt < minwgt[from])
continue; /* This cannot be moved! */
myedegrees = myrinfo->edegrees;
myndegrees = myrinfo->ndegrees;
for (k=0; k<myndegrees; k++) {
to = myedegrees[k].pid;
if (pwgts[to]+vwgt <= maxwgt[to] || itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from])
break;
}
if (k == myndegrees)
continue; /* break out if you did not find a candidate */
for (j=k+1; j<myndegrees; j++) {
to = myedegrees[j].pid;
if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])
k = j;
}
to = myedegrees[k].pid;
if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && myedegrees[k].ed-myrinfo->id < 0)
continue;
/*=====================================================================
* If we got here, we can now move the vertex from 'from' to 'to'
*======================================================================*/
graph->mincut -= myedegrees[k].ed-myrinfo->id;
IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
/* Update where, weight, and ID/ED information of the vertex you moved */
where[i] = to;
INC_DEC(pwgts[to], pwgts[from], vwgt);
myrinfo->ed += myrinfo->id-myedegrees[k].ed;
SWAP(myrinfo->id, myedegrees[k].ed, j);
if (myedegrees[k].ed == 0)
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].pid = from;
if (myrinfo->ed == 0)
BNDDelete(nbnd, bndind, bndptr, i);
/* Update the degrees of adjacent vertices */
for (j=xadj[i]; j<xadj[i+1]; j++) {
ii = adjncy[j];
me = where[ii];
myrinfo = graph->rinfo+ii;
if (myrinfo->edegrees == NULL) {
myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
}
myedegrees = myrinfo->edegrees;
ASSERT(CheckRInfo(myrinfo));
oldgain = (myrinfo->ed-myrinfo->id);
if (me == from) {
INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
if (myrinfo->ed > 0 && bndptr[ii] == -1)
BNDInsert(nbnd, bndind, bndptr, ii);
}
else if (me == to) {
INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
if (myrinfo->ed == 0 && bndptr[ii] != -1)
BNDDelete(nbnd, bndind, bndptr, ii);
}
/* Remove contribution from the .ed of 'from' */
if (me != from) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == from) {
if (myedegrees[k].ed == adjwgt[j])
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].ed -= adjwgt[j];
break;
}
}
}
/* Add contribution to the .ed of 'to' */
if (me != to) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == to) {
myedegrees[k].ed += adjwgt[j];
break;
}
}
if (k == myrinfo->ndegrees) {
myedegrees[myrinfo->ndegrees].pid = to;
myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
}
}
/* Update the queue */
if (me == to || me == from) {
gain = myrinfo->ed-myrinfo->id;
if (moved[ii] == 2) {
if (myrinfo->ed > 0)
PQueueUpdate(&queue, ii, oldgain, gain);
else {
PQueueDelete(&queue, ii, oldgain);
moved[ii] = -1;
}
}
else if (moved[ii] == -1 && myrinfo->ed > 0) {
PQueueInsert(&queue, ii, gain);
moved[ii] = 2;
}
}
ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
ASSERT(CheckRInfo(myrinfo));
}
nmoves++;
}
graph->nbnd = nbnd;
IFSET(ctrl->dbglvl, DBG_REFINE,
printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d\n",
pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut));
}
PQueueFree(ctrl, &queue);
idxwspacefree(ctrl, nparts);
idxwspacefree(ctrl, nparts);
idxwspacefree(ctrl, nparts);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}

View File

@ -0,0 +1,392 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* kwayrefine.c
*
* This file contains the driving routines for multilevel k-way refinement
*
* Started 7/28/97
* George
*
* $Id: kwayrefine.c,v 1.1 2003/07/16 15:55:05 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of refinement
**************************************************************************/
void RefineKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
{
int i, nlevels, mustfree=0;
GraphType *ptr;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
/* Compute the parameters of the coarsest graph */
ComputeKWayPartitionParams(ctrl, graph, nparts);
/* Take care any non-contiguity */
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->AuxTmr1));
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25);
EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts);
EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25);
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr1));
/* Determine how many levels are there */
for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++);
for (i=0; ;i++) {
/* PrintSubDomainGraph(graph, nparts, graph->where); */
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN && (i == nlevels/2 || i == nlevels/2+1))
EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) {
ComputeKWayBalanceBoundary(ctrl, graph, nparts);
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN)
Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1);
else
Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1);
ComputeKWayBoundary(ctrl, graph, nparts);
}
switch (ctrl->RType) {
case RTYPE_KWAYRANDOM:
Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
break;
case RTYPE_KWAYGREEDY:
Greedy_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10);
break;
case RTYPE_KWAYRANDOM_MCONN:
Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
break;
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
if (graph == orggraph)
break;
GKfree(&graph->gdata, LTERM); /* Deallocate the graph related arrays */
graph = graph->finer;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
if (graph->vwgt == NULL) {
graph->vwgt = idxsmalloc(graph->nvtxs, 1, "RefineKWay: graph->vwgt");
graph->adjwgt = idxsmalloc(graph->nedges, 1, "RefineKWay: graph->adjwgt");
mustfree = 1;
}
ProjectKWayPartition(ctrl, graph, nparts);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
}
if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) {
ComputeKWayBalanceBoundary(ctrl, graph, nparts);
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8);
Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
}
else {
Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8);
Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
}
}
/* Take care any trivial non-contiguity */
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->AuxTmr2));
EliminateComponents(ctrl, graph, nparts, tpwgts, ubfactor);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr2));
if (mustfree)
GKfree(&graph->vwgt, &graph->adjwgt, LTERM);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
}
/*************************************************************************
* This function allocates memory for k-way edge refinement
**************************************************************************/
void AllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts)
{
int nvtxs, pad64;
nvtxs = graph->nvtxs;
pad64 = (3*nvtxs+nparts)%2;
graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(RInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateKWayPartitionMemory: rdata");
graph->pwgts = graph->rdata;
graph->where = graph->rdata + nparts;
graph->bndptr = graph->rdata + nvtxs + nparts;
graph->bndind = graph->rdata + 2*nvtxs + nparts;
graph->rinfo = (RInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64);
/*
if (ctrl->wspace.edegrees != NULL)
free(ctrl->wspace.edegrees);
ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateKWayPartitionMemory: edegrees");
*/
}
/*************************************************************************
* This function computes the initial id/ed
**************************************************************************/
void ComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, j, k, l, nvtxs, nbnd, mincut, me, other;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where, *bndind, *bndptr;
RInfoType *rinfo, *myrinfo;
EDegreeType *myedegrees;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
pwgts = idxset(nparts, 0, graph->pwgts);
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
rinfo = graph->rinfo;
/*------------------------------------------------------------
/ Compute now the id/ed degrees
/------------------------------------------------------------*/
ctrl->wspace.cdegree = 0;
nbnd = mincut = 0;
for (i=0; i<nvtxs; i++) {
me = where[i];
pwgts[me] += vwgt[i];
myrinfo = rinfo+i;
myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0;
myrinfo->edegrees = NULL;
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (me != where[adjncy[j]])
myrinfo->ed += adjwgt[j];
}
myrinfo->id = graph->adjwgtsum[i] - myrinfo->ed;
if (myrinfo->ed > 0)
mincut += myrinfo->ed;
if (myrinfo->ed-myrinfo->id >= 0)
BNDInsert(nbnd, bndind, bndptr, i);
/* Time to compute the particular external degrees */
if (myrinfo->ed > 0) {
myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
for (j=xadj[i]; j<xadj[i+1]; j++) {
other = where[adjncy[j]];
if (me != other) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == other) {
myedegrees[k].ed += adjwgt[j];
break;
}
}
if (k == myrinfo->ndegrees) {
myedegrees[myrinfo->ndegrees].pid = other;
myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
}
}
}
ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
}
}
graph->mincut = mincut/2;
graph->nbnd = nbnd;
}
/*************************************************************************
* This function projects a partition, and at the same time computes the
* parameters for refinement.
**************************************************************************/
void ProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees;
idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
idxtype *cmap, *where, *bndptr, *bndind;
idxtype *cwhere;
GraphType *cgraph;
RInfoType *crinfo, *rinfo, *myrinfo;
EDegreeType *myedegrees;
idxtype *htable;
cgraph = graph->coarser;
cwhere = cgraph->where;
crinfo = cgraph->rinfo;
nvtxs = graph->nvtxs;
cmap = graph->cmap;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
AllocateKWayPartitionMemory(ctrl, graph, nparts);
where = graph->where;
rinfo = graph->rinfo;
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
/* Go through and project partition and compute id/ed for the nodes */
for (i=0; i<nvtxs; i++) {
k = cmap[i];
where[i] = cwhere[k];
cmap[i] = crinfo[k].ed; /* For optimization */
}
htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts));
ctrl->wspace.cdegree = 0;
for (nbnd=0, i=0; i<nvtxs; i++) {
me = where[i];
myrinfo = rinfo+i;
myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0;
myrinfo->edegrees = NULL;
myrinfo->id = adjwgtsum[i];
if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */
istart = xadj[i];
iend = xadj[i+1];
myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += iend-istart;
ndegrees = 0;
for (j=istart; j<iend; j++) {
other = where[adjncy[j]];
if (me != other) {
myrinfo->ed += adjwgt[j];
if ((k = htable[other]) == -1) {
htable[other] = ndegrees;
myedegrees[ndegrees].pid = other;
myedegrees[ndegrees++].ed = adjwgt[j];
}
else {
myedegrees[k].ed += adjwgt[j];
}
}
}
myrinfo->id -= myrinfo->ed;
/* Remove space for edegrees if it was interior */
if (myrinfo->ed == 0) {
myrinfo->edegrees = NULL;
ctrl->wspace.cdegree -= iend-istart;
}
else {
if (myrinfo->ed-myrinfo->id >= 0)
BNDInsert(nbnd, bndind, bndptr, i);
myrinfo->ndegrees = ndegrees;
for (j=0; j<ndegrees; j++)
htable[myedegrees[j].pid] = -1;
}
}
}
idxcopy(nparts, cgraph->pwgts, graph->pwgts);
graph->mincut = cgraph->mincut;
graph->nbnd = nbnd;
FreeGraph(graph->coarser);
graph->coarser = NULL;
idxwspacefree(ctrl, nparts);
ASSERT(CheckBnd2(graph));
}
/*************************************************************************
* This function checks if the partition weights are within the balance
* contraints
**************************************************************************/
int IsBalanced(idxtype *pwgts, int nparts, float *tpwgts, float ubfactor)
{
int i, j, tvwgt;
tvwgt = idxsum(nparts, pwgts);
for (i=0; i<nparts; i++) {
if (pwgts[i] > tpwgts[i]*tvwgt*(ubfactor+0.005))
return 0;
}
return 1;
}
/*************************************************************************
* This function computes the boundary definition for balancing
**************************************************************************/
void ComputeKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, nvtxs, nbnd;
idxtype *bndind, *bndptr;
nvtxs = graph->nvtxs;
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
/*------------------------------------------------------------
/ Compute the new boundary
/------------------------------------------------------------*/
nbnd = 0;
for (i=0; i<nvtxs; i++) {
if (graph->rinfo[i].ed-graph->rinfo[i].id >= 0)
BNDInsert(nbnd, bndind, bndptr, i);
}
graph->nbnd = nbnd;
}
/*************************************************************************
* This function computes the boundary definition for balancing
**************************************************************************/
void ComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, nvtxs, nbnd;
idxtype *bndind, *bndptr;
nvtxs = graph->nvtxs;
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
/*------------------------------------------------------------
/ Compute the new boundary
/------------------------------------------------------------*/
nbnd = 0;
for (i=0; i<nvtxs; i++) {
if (graph->rinfo[i].ed > 0)
BNDInsert(nbnd, bndind, bndptr, i);
}
graph->nbnd = nbnd;
}

View File

@ -0,0 +1,468 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* kwayvolrefine.c
*
* This file contains the driving routines for multilevel k-way refinement
*
* Started 7/28/97
* George
*
* $Id: kwayvolrefine.c,v 1.1 2003/07/16 15:55:05 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of refinement
**************************************************************************/
void RefineVolKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts,
float *tpwgts, float ubfactor)
{
int i, nlevels;
GraphType *ptr;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
/* Take care any non-contiguity */
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->AuxTmr1));
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
ComputeVolKWayPartitionParams(ctrl, graph, nparts);
EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25);
EliminateVolSubDomainEdges(ctrl, graph, nparts, tpwgts);
EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25);
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr1));
/* Determine how many levels are there */
for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++);
/* Compute the parameters of the coarsest graph */
ComputeVolKWayPartitionParams(ctrl, graph, nparts);
for (i=0; ;i++) {
/*PrintSubDomainGraph(graph, nparts, graph->where);*/
MALLOC_CHECK(NULL);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) {
ComputeVolKWayBalanceBoundary(ctrl, graph, nparts);
switch (ctrl->RType) {
case RTYPE_KWAYRANDOM:
Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1);
break;
case RTYPE_KWAYRANDOM_MCONN:
Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1);
break;
}
ComputeVolKWayBoundary(ctrl, graph, nparts);
}
switch (ctrl->RType) {
case RTYPE_KWAYRANDOM:
Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
break;
case RTYPE_KWAYRANDOM_MCONN:
Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
break;
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
if (graph == orggraph)
break;
GKfree(&graph->gdata, LTERM); /* Deallocate the graph related arrays */
graph = graph->finer;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
ProjectVolKWayPartition(ctrl, graph, nparts);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
}
if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) {
ComputeVolKWayBalanceBoundary(ctrl, graph, nparts);
switch (ctrl->RType) {
case RTYPE_KWAYRANDOM:
Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8);
Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
break;
case RTYPE_KWAYRANDOM_MCONN:
Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8);
Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
break;
}
}
EliminateVolComponents(ctrl, graph, nparts, tpwgts, ubfactor);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
}
/*************************************************************************
* This function allocates memory for k-way edge refinement
**************************************************************************/
void AllocateVolKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts)
{
int nvtxs, pad64;
nvtxs = graph->nvtxs;
pad64 = (3*nvtxs+nparts)%2;
graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(VRInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateVolKWayPartitionMemory: rdata");
graph->pwgts = graph->rdata;
graph->where = graph->rdata + nparts;
graph->bndptr = graph->rdata + nvtxs + nparts;
graph->bndind = graph->rdata + 2*nvtxs + nparts;
graph->vrinfo = (VRInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64);
}
/*************************************************************************
* This function computes the initial id/ed
**************************************************************************/
void ComputeVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, ii, j, k, kk, l, nvtxs, nbnd, mincut, minvol, me, other, pid;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where;
VRInfoType *rinfo, *myrinfo, *orinfo;
VEDegreeType *myedegrees, *oedegrees;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
pwgts = idxset(nparts, 0, graph->pwgts);
rinfo = graph->vrinfo;
starttimer(ctrl->AuxTmr1);
/*------------------------------------------------------------
/ Compute now the id/ed degrees
/------------------------------------------------------------*/
ctrl->wspace.cdegree = 0;
mincut = 0;
for (i=0; i<nvtxs; i++) {
me = where[i];
pwgts[me] += vwgt[i];
myrinfo = rinfo+i;
myrinfo->id = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0;
myrinfo->edegrees = NULL;
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (me == where[adjncy[j]]) {
myrinfo->id += adjwgt[j];
myrinfo->nid++;
}
}
myrinfo->ed = graph->adjwgtsum[i] - myrinfo->id;
mincut += myrinfo->ed;
/* Time to compute the particular external degrees */
if (myrinfo->ed > 0) {
myedegrees = myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
for (j=xadj[i]; j<xadj[i+1]; j++) {
other = where[adjncy[j]];
if (me != other) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == other) {
myedegrees[k].ed += adjwgt[j];
myedegrees[k].ned++;
break;
}
}
if (k == myrinfo->ndegrees) {
myedegrees[myrinfo->ndegrees].gv = 0;
myedegrees[myrinfo->ndegrees].pid = other;
myedegrees[myrinfo->ndegrees].ed = adjwgt[j];
myedegrees[myrinfo->ndegrees++].ned = 1;
}
}
}
ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
}
}
graph->mincut = mincut/2;
stoptimer(ctrl->AuxTmr1);
ComputeKWayVolGains(ctrl, graph, nparts);
}
/*************************************************************************
* This function computes the initial id/ed
**************************************************************************/
void ComputeKWayVolGains(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, ii, j, k, kk, l, nvtxs, me, other, pid, myndegrees;
idxtype *xadj, *vsize, *adjncy, *adjwgt, *where, *bndind, *bndptr, *ophtable;
VRInfoType *rinfo, *myrinfo, *orinfo;
VEDegreeType *myedegrees, *oedegrees;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vsize = graph->vsize;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
rinfo = graph->vrinfo;
starttimer(ctrl->AuxTmr2);
ophtable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts));
/*------------------------------------------------------------
/ Compute now the iv/ev degrees
/------------------------------------------------------------*/
graph->minvol = graph->nbnd = 0;
for (i=0; i<nvtxs; i++) {
myrinfo = rinfo+i;
myrinfo->gv = -MAXIDX;
if (myrinfo->ndegrees > 0) {
me = where[i];
myedegrees = myrinfo->edegrees;
myndegrees = myrinfo->ndegrees;
graph->minvol += myndegrees*vsize[i];
for (j=xadj[i]; j<xadj[i+1]; j++) {
ii = adjncy[j];
other = where[ii];
orinfo = rinfo+ii;
oedegrees = orinfo->edegrees;
for (k=0; k<orinfo->ndegrees; k++)
ophtable[oedegrees[k].pid] = k;
ophtable[other] = 1; /* this is to simplify coding */
if (me == other) {
/* Find which domains 'i' is connected and 'ii' is not and update their gain */
for (k=0; k<myndegrees; k++) {
if (ophtable[myedegrees[k].pid] == -1)
myedegrees[k].gv -= vsize[ii];
}
}
else {
ASSERT(ophtable[me] != -1);
if (oedegrees[ophtable[me]].ned == 1) { /* I'm the only connection of 'ii' in 'me' */
/* Increase the gains for all the common domains between 'i' and 'ii' */
for (k=0; k<myndegrees; k++) {
if (ophtable[myedegrees[k].pid] != -1)
myedegrees[k].gv += vsize[ii];
}
}
else {
/* Find which domains 'i' is connected and 'ii' is not and update their gain */
for (k=0; k<myndegrees; k++) {
if (ophtable[myedegrees[k].pid] == -1)
myedegrees[k].gv -= vsize[ii];
}
}
}
for (kk=0; kk<orinfo->ndegrees; kk++)
ophtable[oedegrees[kk].pid] = -1;
ophtable[other] = -1;
}
/* Compute the max vgain */
for (k=0; k<myndegrees; k++) {
if (myedegrees[k].gv > myrinfo->gv)
myrinfo->gv = myedegrees[k].gv;
}
}
if (myrinfo->ed > 0 && myrinfo->id == 0)
myrinfo->gv += vsize[i];
if (myrinfo->gv >= 0 || myrinfo->ed-myrinfo->id >= 0)
BNDInsert(graph->nbnd, bndind, bndptr, i);
}
stoptimer(ctrl->AuxTmr2);
idxwspacefree(ctrl, nparts);
}
/*************************************************************************
* This function projects a partition, and at the same time computes the
* parameters for refinement.
**************************************************************************/
void ProjectVolKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, j, k, nvtxs, me, other, istart, iend, ndegrees;
idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
idxtype *cmap, *where;
idxtype *cwhere;
GraphType *cgraph;
VRInfoType *crinfo, *rinfo, *myrinfo;
VEDegreeType *myedegrees;
idxtype *htable;
cgraph = graph->coarser;
cwhere = cgraph->where;
crinfo = cgraph->vrinfo;
nvtxs = graph->nvtxs;
cmap = graph->cmap;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
AllocateVolKWayPartitionMemory(ctrl, graph, nparts);
where = graph->where;
rinfo = graph->vrinfo;
/* Go through and project partition and compute id/ed for the nodes */
for (i=0; i<nvtxs; i++) {
k = cmap[i];
where[i] = cwhere[k];
cmap[i] = crinfo[k].ed; /* For optimization */
}
htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts));
ctrl->wspace.cdegree = 0;
for (i=0; i<nvtxs; i++) {
me = where[i];
myrinfo = rinfo+i;
myrinfo->id = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0;
myrinfo->edegrees = NULL;
myrinfo->id = adjwgtsum[i];
myrinfo->nid = xadj[i+1]-xadj[i];
if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */
istart = xadj[i];
iend = xadj[i+1];
myedegrees = myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += iend-istart;
ndegrees = 0;
for (j=istart; j<iend; j++) {
other = where[adjncy[j]];
if (me != other) {
myrinfo->ed += adjwgt[j];
myrinfo->nid--;
if ((k = htable[other]) == -1) {
htable[other] = ndegrees;
myedegrees[ndegrees].gv = 0;
myedegrees[ndegrees].pid = other;
myedegrees[ndegrees].ed = adjwgt[j];
myedegrees[ndegrees++].ned = 1;
}
else {
myedegrees[k].ed += adjwgt[j];
myedegrees[k].ned++;
}
}
}
myrinfo->id -= myrinfo->ed;
/* Remove space for edegrees if it was interior */
if (myrinfo->ed == 0) {
myrinfo->edegrees = NULL;
ctrl->wspace.cdegree -= iend-istart;
}
else {
myrinfo->ndegrees = ndegrees;
for (j=0; j<ndegrees; j++)
htable[myedegrees[j].pid] = -1;
}
}
}
ComputeKWayVolGains(ctrl, graph, nparts);
idxcopy(nparts, cgraph->pwgts, graph->pwgts);
graph->mincut = cgraph->mincut;
FreeGraph(graph->coarser);
graph->coarser = NULL;
idxwspacefree(ctrl, nparts);
}
/*************************************************************************
* This function computes the boundary definition for balancing
**************************************************************************/
void ComputeVolKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, nvtxs, nbnd;
idxtype *bndind, *bndptr;
nvtxs = graph->nvtxs;
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
/*------------------------------------------------------------
/ Compute the new boundary
/------------------------------------------------------------*/
nbnd = 0;
for (i=0; i<nvtxs; i++) {
if (graph->vrinfo[i].gv >=0 || graph->vrinfo[i].ed-graph->vrinfo[i].id >= 0)
BNDInsert(nbnd, bndind, bndptr, i);
}
graph->nbnd = nbnd;
}
/*************************************************************************
* This function computes the boundary definition for balancing
**************************************************************************/
void ComputeVolKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, nvtxs, nbnd;
idxtype *bndind, *bndptr;
nvtxs = graph->nvtxs;
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
/*------------------------------------------------------------
/ Compute the new boundary
/------------------------------------------------------------*/
nbnd = 0;
for (i=0; i<nvtxs; i++) {
if (graph->vrinfo[i].ed > 0)
BNDInsert(nbnd, bndind, bndptr, i);
}
graph->nbnd = nbnd;
}

View File

@ -0,0 +1,138 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* macros.h
*
* This file contains macros used in multilevel
*
* Started 9/25/94
* George
*
* $Id: macros.h,v 1.7 2003/07/21 19:11:40 karypis Exp $
*
*/
/*************************************************************************
* The following macro returns a random number in the specified range
**************************************************************************/
#define RandomInRange(u) ((int)(1.0*(u)*rand()/(RAND_MAX+1.0)))
#define amax(a, b) ((a) >= (b) ? (a) : (b))
#define amin(a, b) ((a) >= (b) ? (b) : (a))
#define AND(a, b) ((a) < 0 ? ((-(a))&(b)) : ((a)&(b)))
#define OR(a, b) ((a) < 0 ? -((-(a))|(b)) : ((a)|(b)))
#define XOR(a, b) ((a) < 0 ? -((-(a))^(b)) : ((a)^(b)))
#define SWAP(a, b, tmp) \
do {(tmp) = (a); (a) = (b); (b) = (tmp);} while(0)
#define INC_DEC(a, b, val) \
do {(a) += (val); (b) -= (val);} while(0)
#define scopy(n, a, b) (float *)memcpy((void *)(b), (void *)(a), sizeof(float)*(n))
#define idxcopy(n, a, b) (idxtype *)memcpy((void *)(b), (void *)(a), sizeof(idxtype)*(n))
#define HASHFCT(key, size) ((key)%(size))
/*************************************************************************
* Timer macros
**************************************************************************/
#define cleartimer(tmr) (tmr = 0.0)
#define starttimer(tmr) (tmr -= seconds())
#define stoptimer(tmr) (tmr += seconds())
#define gettimer(tmr) (tmr)
/*************************************************************************
* This macro is used to handle dbglvl
**************************************************************************/
#define IFSET(a, flag, cmd) if ((a)&(flag)) (cmd);
/*************************************************************************
* These macros are used for debuging memory leaks
**************************************************************************/
#ifdef DMALLOC
#define imalloc(n, msg) (malloc(sizeof(int)*(n)))
#define fmalloc(n, msg) (malloc(sizeof(float)*(n)))
#define idxmalloc(n, msg) (malloc(sizeof(idxtype)*(n)))
#define ismalloc(n, val, msg) (iset((n), (val), malloc(sizeof(int)*(n))))
#define idxsmalloc(n, val, msg) (idxset((n), (val), malloc(sizeof(idxtype)*(n))))
#define GKmalloc(a, b) (malloc((a)))
#endif
#ifdef DMALLOC
# define MALLOC_CHECK(ptr);
/*
# define MALLOC_CHECK(ptr) \
if (malloc_verify((ptr)) == DMALLOC_VERIFY_ERROR) { \
printf("***MALLOC_CHECK failed on line %d of file %s: " #ptr "\n", \
__LINE__, __FILE__); \
abort(); \
}
*/
#else
# define MALLOC_CHECK(ptr) ;
#endif
/*************************************************************************
* This macro converts a length array in a CSR one
**************************************************************************/
#define MAKECSR(i, n, a) \
do { \
for (i=1; i<n; i++) a[i] += a[i-1]; \
for (i=n; i>0; i--) a[i] = a[i-1]; \
a[0] = 0; \
} while(0)
/*************************************************************************
* These macros insert and remove nodes from the boundary list
**************************************************************************/
#define BNDInsert(nbnd, bndind, bndptr, vtx) \
do { \
ASSERT(bndptr[vtx] == -1); \
bndind[nbnd] = vtx; \
bndptr[vtx] = nbnd++;\
} while(0)
#define BNDDelete(nbnd, bndind, bndptr, vtx) \
do { \
ASSERT(bndptr[vtx] != -1); \
bndind[bndptr[vtx]] = bndind[--nbnd]; \
bndptr[bndind[nbnd]] = bndptr[vtx]; \
bndptr[vtx] = -1; \
} while(0)
/*************************************************************************
* These are debugging macros
**************************************************************************/
#ifdef DEBUG
# define ASSERT(expr) \
if (!(expr)) { \
printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \
__LINE__, __FILE__); \
abort(); \
}
#else
# define ASSERT(expr) ;
#endif
#ifdef DEBUG
# define ASSERTP(expr, msg) \
if (!(expr)) { \
printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \
__LINE__, __FILE__); \
printf msg ; \
abort(); \
}
#else
# define ASSERTP(expr, msg) ;
#endif

View File

@ -0,0 +1,267 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* match.c
*
* This file contains the code that computes matchings and creates the next
* level coarse graph.
*
* Started 7/23/97
* George
*
* $Id: match.c,v 1.1 2003/07/16 15:55:06 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void Match_RM(CtrlType *ctrl, GraphType *graph)
{
int i, ii, j, nvtxs, cnvtxs, maxidx;
idxtype *xadj, *vwgt, *adjncy, *adjwgt;
idxtype *match, *cmap, *perm;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
cmap = graph->cmap;
match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
perm = idxwspacemalloc(ctrl, nvtxs);
RandomPermute(nvtxs, perm, 1);
cnvtxs = 0;
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
/* Find a random matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (match[adjncy[j]] == UNMATCHED && vwgt[i]+vwgt[adjncy[j]] <= ctrl->maxvwgt) {
maxidx = adjncy[j];
break;
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void Match_RM_NVW(CtrlType *ctrl, GraphType *graph)
{
int i, ii, j, nvtxs, cnvtxs, maxidx;
idxtype *xadj, *adjncy;
idxtype *match, *cmap, *perm;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
cmap = graph->cmap;
match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
perm = idxwspacemalloc(ctrl, nvtxs);
RandomPermute(nvtxs, perm, 1);
cnvtxs = 0;
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
/* Find a random matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (match[adjncy[j]] == UNMATCHED) {
maxidx = adjncy[j];
break;
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
CreateCoarseGraph_NVW(ctrl, graph, cnvtxs, match, perm);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void Match_HEM(CtrlType *ctrl, GraphType *graph)
{
int i, ii, j, k, nvtxs, cnvtxs, maxidx, maxwgt;
idxtype *xadj, *vwgt, *adjncy, *adjwgt;
idxtype *match, *cmap, *perm;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
cmap = graph->cmap;
match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
perm = idxwspacemalloc(ctrl, nvtxs);
RandomPermute(nvtxs, perm, 1);
cnvtxs = 0;
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
maxwgt = 0;
/* Find a heavy-edge matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (match[k] == UNMATCHED && maxwgt < adjwgt[j] && vwgt[i]+vwgt[k] <= ctrl->maxvwgt) {
maxwgt = adjwgt[j];
maxidx = adjncy[j];
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void Match_SHEM(CtrlType *ctrl, GraphType *graph)
{
int i, ii, j, k, nvtxs, cnvtxs, maxidx, maxwgt, avgdegree;
idxtype *xadj, *vwgt, *adjncy, *adjwgt;
idxtype *match, *cmap, *degrees, *perm, *tperm;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
cmap = graph->cmap;
match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
perm = idxwspacemalloc(ctrl, nvtxs);
tperm = idxwspacemalloc(ctrl, nvtxs);
degrees = idxwspacemalloc(ctrl, nvtxs);
RandomPermute(nvtxs, tperm, 1);
avgdegree = 0.7*(xadj[nvtxs]/nvtxs);
for (i=0; i<nvtxs; i++)
degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]);
BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm);
cnvtxs = 0;
/* Take care any islands. Islands are matched with non-islands due to coarsening */
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
if (xadj[i] < xadj[i+1])
break;
maxidx = i;
for (j=nvtxs-1; j>ii; j--) {
k = perm[j];
if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) {
maxidx = k;
break;
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
/* Continue with normal matching */
for (; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
maxwgt = 0;
/* Find a heavy-edge matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (match[adjncy[j]] == UNMATCHED && maxwgt < adjwgt[j] && vwgt[i]+vwgt[adjncy[j]] <= ctrl->maxvwgt) {
maxwgt = adjwgt[j];
maxidx = adjncy[j];
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
idxwspacefree(ctrl, nvtxs); /* degrees */
idxwspacefree(ctrl, nvtxs); /* tperm */
CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}

View File

@ -0,0 +1,260 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mbalance.c
*
* This file contains code that is used to forcefully balance either
* bisections or k-sections
*
* Started 7/29/97
* George
*
* $Id: mbalance.c,v 1.1 2003/07/16 15:55:07 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of the bisection balancing algorithms.
**************************************************************************/
void MocBalance2Way(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor)
{
if (Compute2WayHLoadImbalance(graph->ncon, graph->npwgts, tpwgts) < lbfactor)
return;
MocGeneral2WayBalance(ctrl, graph, tpwgts, lbfactor);
}
/*************************************************************************
* This function performs an edge-based FM refinement
**************************************************************************/
void MocGeneral2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor)
{
int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum;
idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
idxtype *moved, *swaps, *perm, *qnum;
float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal;
PQueueType parts[MAXNCON][2];
int higain, oldgain, mincut, newcut, mincutorder;
int qsizes[MAXNCON][2];
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
npwgts = graph->npwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
moved = idxwspacemalloc(ctrl, nvtxs);
swaps = idxwspacemalloc(ctrl, nvtxs);
perm = idxwspacemalloc(ctrl, nvtxs);
qnum = idxwspacemalloc(ctrl, nvtxs);
limit = amin(amax(0.01*nvtxs, 15), 100);
/* Initialize the queues */
for (i=0; i<ncon; i++) {
PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
qsizes[i][0] = qsizes[i][1] = 0;
}
for (i=0; i<nvtxs; i++) {
qnum[i] = samax(ncon, nvwgt+i*ncon);
qsizes[qnum[i]][where[i]]++;
}
/*
printf("Weight Distribution: \t");
for (i=0; i<ncon; i++)
printf(" [%d %d]", qsizes[i][0], qsizes[i][1]);
printf("\n");
*/
for (from=0; from<2; from++) {
for (j=0; j<ncon; j++) {
if (qsizes[j][from] == 0) {
for (i=0; i<nvtxs; i++) {
if (where[i] != from)
continue;
k = samax2(ncon, nvwgt+i*ncon);
if (k == j && qsizes[qnum[i]][from] > qsizes[j][from] && nvwgt[i*ncon+qnum[i]] < 1.3*nvwgt[i*ncon+j]) {
qsizes[qnum[i]][from]--;
qsizes[j][from]++;
qnum[i] = j;
}
}
}
}
}
/*
printf("Weight Distribution (after):\t ");
for (i=0; i<ncon; i++)
printf(" [%d %d]", qsizes[i][0], qsizes[i][1]);
printf("\n");
*/
for (i=0; i<ncon; i++)
mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
minbal = origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
newcut = mincut = graph->mincut;
mincutorder = -1;
if (ctrl->dbglvl&DBG_REFINE) {
printf("Parts: [");
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal);
}
idxset(nvtxs, -1, moved);
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
/* Insert all nodes in the priority queues */
nbnd = graph->nbnd;
RandomPermute(nvtxs, perm, 1);
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]);
}
for (nswaps=0; nswaps<nvtxs; nswaps++) {
if (minbal < lbfactor)
break;
SelectQueue(ncon, npwgts, tpwgts, &from, &cnum, parts);
to = (from+1)%2;
if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1)
break;
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
newcut -= (ed[higain]-id[higain]);
newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
if (newbal < minbal || (newbal == minbal &&
(newcut < mincut || (newcut == mincut && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) {
mincut = newcut;
minbal = newbal;
mincutorder = nswaps;
for (i=0; i<ncon; i++)
mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
}
else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
newcut += (ed[higain]-id[higain]);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
break;
}
where[higain] = to;
moved[higain] = nswaps;
swaps[nswaps] = higain;
if (ctrl->dbglvl&DBG_MOVEINFO) {
printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf(", %.3f LB: %.3f\n", minbal, newbal);
}
/**************************************************************
* Update the id[i]/ed[i] values of the affected nodes
***************************************************************/
SWAP(id[higain], ed[higain], tmp);
if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
BNDDelete(nbnd, bndind, bndptr, higain);
if (ed[higain] > 0 && bndptr[higain] == -1)
BNDInsert(nbnd, bndind, bndptr, higain);
for (j=xadj[higain]; j<xadj[higain+1]; j++) {
k = adjncy[j];
oldgain = ed[k]-id[k];
kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
INC_DEC(id[k], ed[k], kwgt);
/* Update the queue position */
if (moved[k] == -1)
PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]);
/* Update its boundary information */
if (ed[k] == 0 && bndptr[k] != -1)
BNDDelete(nbnd, bndind, bndptr, k);
else if (ed[k] > 0 && bndptr[k] == -1)
BNDInsert(nbnd, bndind, bndptr, k);
}
}
/****************************************************************
* Roll back computations
*****************************************************************/
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);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((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);
}
}
if (ctrl->dbglvl&DBG_REFINE) {
printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
}
graph->mincut = mincut;
graph->nbnd = nbnd;
for (i=0; i<ncon; i++) {
PQueueFree(ctrl, &parts[i][0]);
PQueueFree(ctrl, &parts[i][1]);
}
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}

View File

@ -0,0 +1,328 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mbalance2.c
*
* This file contains code that is used to forcefully balance either
* bisections or k-sections
*
* Started 7/29/97
* George
*
* $Id: mbalance2.c,v 1.1 2003/07/16 15:55:07 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of the bisection balancing algorithms.
**************************************************************************/
void MocBalance2Way2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
{
int i;
float tvec[MAXNCON];
Compute2WayHLoadImbalanceVec(graph->ncon, graph->npwgts, tpwgts, tvec);
if (!AreAllBelow(graph->ncon, tvec, ubvec))
MocGeneral2WayBalance2(ctrl, graph, tpwgts, ubvec);
}
/*************************************************************************
* This function performs an edge-based FM refinement
**************************************************************************/
void MocGeneral2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
{
int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum;
idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
idxtype *moved, *swaps, *perm, *qnum;
float *nvwgt, *npwgts, origbal[MAXNCON], minbal[MAXNCON], newbal[MAXNCON];
PQueueType parts[MAXNCON][2];
int higain, oldgain, mincut, newcut, mincutorder;
float *maxwgt, *minwgt, tvec[MAXNCON];
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
npwgts = graph->npwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
moved = idxwspacemalloc(ctrl, nvtxs);
swaps = idxwspacemalloc(ctrl, nvtxs);
perm = idxwspacemalloc(ctrl, nvtxs);
qnum = idxwspacemalloc(ctrl, nvtxs);
limit = amin(amax(0.01*nvtxs, 15), 100);
/* Setup the weight intervals of the two subdomains */
minwgt = fwspacemalloc(ctrl, 2*ncon);
maxwgt = fwspacemalloc(ctrl, 2*ncon);
for (i=0; i<2; i++) {
for (j=0; j<ncon; j++) {
maxwgt[i*ncon+j] = tpwgts[i]*ubvec[j];
minwgt[i*ncon+j] = tpwgts[i]*(1.0/ubvec[j]);
}
}
/* Initialize the queues */
for (i=0; i<ncon; i++) {
PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
}
for (i=0; i<nvtxs; i++)
qnum[i] = samax(ncon, nvwgt+i*ncon);
Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, origbal);
for (i=0; i<ncon; i++)
minbal[i] = origbal[i];
newcut = mincut = graph->mincut;
mincutorder = -1;
if (ctrl->dbglvl&DBG_REFINE) {
printf("Parts: [");
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: ", tpwgts[0], tpwgts[1],
graph->nvtxs, graph->nbnd, graph->mincut);
for (i=0; i<ncon; i++)
printf("%.3f ", origbal[i]);
printf("[B]\n");
}
idxset(nvtxs, -1, moved);
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
/* Insert all nodes in the priority queues */
nbnd = graph->nbnd;
RandomPermute(nvtxs, perm, 1);
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]);
}
for (nswaps=0; nswaps<nvtxs; nswaps++) {
if (AreAllBelow(ncon, minbal, ubvec))
break;
SelectQueue3(ncon, npwgts, tpwgts, &from, &cnum, parts, maxwgt);
to = (from+1)%2;
if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1)
break;
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
newcut -= (ed[higain]-id[higain]);
Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, newbal);
if (IsBetter2wayBalance(ncon, newbal, minbal, ubvec) ||
(IsBetter2wayBalance(ncon, newbal, origbal, ubvec) && newcut < mincut)) {
mincut = newcut;
for (i=0; i<ncon; i++)
minbal[i] = newbal[i];
mincutorder = nswaps;
}
else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
newcut += (ed[higain]-id[higain]);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
break;
}
where[higain] = to;
moved[higain] = nswaps;
swaps[nswaps] = higain;
if (ctrl->dbglvl&DBG_MOVEINFO) {
printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut);
for (i=0; i<ncon; i++)
printf("(%.3f, %.3f) ", npwgts[i], npwgts[ncon+i]);
Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec);
printf(", LB: ");
for (i=0; i<ncon; i++)
printf("%.3f ", tvec[i]);
if (mincutorder == nswaps)
printf(" *\n");
else
printf("\n");
}
/**************************************************************
* Update the id[i]/ed[i] values of the affected nodes
***************************************************************/
SWAP(id[higain], ed[higain], tmp);
if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
BNDDelete(nbnd, bndind, bndptr, higain);
if (ed[higain] > 0 && bndptr[higain] == -1)
BNDInsert(nbnd, bndind, bndptr, higain);
for (j=xadj[higain]; j<xadj[higain+1]; j++) {
k = adjncy[j];
oldgain = ed[k]-id[k];
kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
INC_DEC(id[k], ed[k], kwgt);
/* Update the queue position */
if (moved[k] == -1)
PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]);
/* Update its boundary information */
if (ed[k] == 0 && bndptr[k] != -1)
BNDDelete(nbnd, bndind, bndptr, k);
else if (ed[k] > 0 && bndptr[k] == -1)
BNDInsert(nbnd, bndind, bndptr, k);
}
}
/****************************************************************
* 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);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((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);
}
}
if (ctrl->dbglvl&DBG_REFINE) {
printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd);
for (i=0; i<ncon; i++)
printf("(%.3f, %.3f) ", npwgts[i], npwgts[ncon+i]);
printf("], LB: ");
Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec);
for (i=0; i<ncon; i++)
printf("%.3f ", tvec[i]);
printf("\n");
}
graph->mincut = mincut;
graph->nbnd = nbnd;
for (i=0; i<ncon; i++) {
PQueueFree(ctrl, &parts[i][0]);
PQueueFree(ctrl, &parts[i][1]);
}
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
fwspacefree(ctrl, 2*ncon);
fwspacefree(ctrl, 2*ncon);
}
/*************************************************************************
* This function selects the partition number and the queue from which
* we will move vertices out
**************************************************************************/
void SelectQueue3(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum,
PQueueType queues[MAXNCON][2], float *maxwgt)
{
int i, j, maxgain=0;
float maxdiff=0.0, diff;
*from = -1;
*cnum = -1;
/* First determine the side and the queue, irrespective of the presence of nodes */
for (j=0; j<2; j++) {
for (i=0; i<ncon; i++) {
diff = npwgts[j*ncon+i]-maxwgt[j*ncon+i];
if (diff >= maxdiff) {
maxdiff = diff;
*from = j;
*cnum = i;
}
}
}
/* DELETE
j = *from;
for (i=0; i<ncon; i++)
printf("[%5d %5d %.4f %.4f] ", i, PQueueGetSize(&queues[i][j]), npwgts[j*ncon+i], maxwgt[j*ncon+i]);
printf("***[%5d %5d]\n", *cnum, *from);
*/
/* If the desired queue is empty, select a node from that side anyway */
if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) {
for (i=0; i<ncon; i++) {
if (PQueueGetSize(&queues[i][*from]) > 0) {
maxdiff = (npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]);
*cnum = i;
break;
}
}
for (i++; i<ncon; i++) {
diff = npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i];
if (diff > maxdiff && PQueueGetSize(&queues[i][*from]) > 0) {
maxdiff = diff;
*cnum = i;
}
}
}
/* If the constraints ar OK, select a high gain vertex */
if (*from == -1) {
maxgain = -100000;
for (j=0; j<2; j++) {
for (i=0; i<ncon; i++) {
if (PQueueGetSize(&queues[i][j]) > 0 && PQueueGetKey(&queues[i][j]) > maxgain) {
maxgain = PQueueGetKey(&queues[i][0]);
*from = j;
*cnum = i;
}
}
}
/* printf("(%2d %2d) %3d\n", *from, *cnum, maxgain); */
}
}

View File

@ -0,0 +1,106 @@
/*
* mcoarsen.c
*
* This file contains the driving routines for the coarsening process
*
* Started 7/23/97
* George
*
* $Id: mcoarsen.c,v 1.2 2003/07/31 16:23:29 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function takes a graph and creates a sequence of coarser graphs
**************************************************************************/
GraphType *MCCoarsen2Way(CtrlType *ctrl, GraphType *graph)
{
int i, clevel;
GraphType *cgraph;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->CoarsenTmr));
cgraph = graph;
clevel = 0;
do {
if (ctrl->dbglvl&DBG_COARSEN) {
printf("%6d %7d %10d [%d] [%6.4f", cgraph->nvtxs, cgraph->nedges,
idxsum(cgraph->nvtxs, cgraph->adjwgtsum), ctrl->CoarsenTo, ctrl->nmaxvwgt);
for (i=0; i<graph->ncon; i++)
printf(" %5.3f", ssum_strd(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon));
printf("]\n");
}
switch (ctrl->CType) {
case MATCH_RM:
MCMatch_RM(ctrl, cgraph);
break;
case MATCH_HEM:
if (clevel < 1 || cgraph->nedges == 0)
MCMatch_RM(ctrl, cgraph);
else
MCMatch_HEM(ctrl, cgraph);
break;
case MATCH_SHEM:
if (clevel < 1 || cgraph->nedges == 0)
MCMatch_RM(ctrl, cgraph);
else
MCMatch_SHEM(ctrl, cgraph);
break;
case MATCH_SHEMKWAY:
if (clevel < 1 || cgraph->nedges == 0)
MCMatch_RM(ctrl, cgraph);
else
MCMatch_SHEM(ctrl, cgraph);
break;
case MATCH_SHEBM_ONENORM:
if (clevel < 1 || cgraph->nedges == 0)
MCMatch_RM(ctrl, cgraph);
else
MCMatch_SHEBM(ctrl, cgraph, 1);
break;
case MATCH_SHEBM_INFNORM:
if (clevel < 1 || cgraph->nedges == 0)
MCMatch_RM(ctrl, cgraph);
else
MCMatch_SHEBM(ctrl, cgraph, -1);
break;
case MATCH_SBHEM_ONENORM:
if (clevel < 1 || cgraph->nedges == 0)
MCMatch_RM(ctrl, cgraph);
else
MCMatch_SBHEM(ctrl, cgraph, 1);
break;
case MATCH_SBHEM_INFNORM:
if (clevel < 1 || cgraph->nedges == 0)
MCMatch_RM(ctrl, cgraph);
else
MCMatch_SBHEM(ctrl, cgraph, -1);
break;
default:
errexit("Unknown CType: %d\n", ctrl->CType);
}
cgraph = cgraph->coarser;
clevel++;
} while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2);
if (ctrl->dbglvl&DBG_COARSEN) {
printf("%6d %7d %10d [%d] [%6.4f", cgraph->nvtxs, cgraph->nedges,
idxsum(cgraph->nvtxs, cgraph->adjwgtsum), ctrl->CoarsenTo, ctrl->nmaxvwgt);
for (i=0; i<graph->ncon; i++)
printf(" %5.3f", ssum_strd(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon));
printf("]\n");
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->CoarsenTmr));
return cgraph;
}

View File

@ -0,0 +1,208 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* memory.c
*
* This file contains routines that deal with memory allocation
*
* Started 2/24/96
* George
*
* $Id: memory.c,v 1.1 2003/07/24 18:39:08 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function allocates memory for the workspace
**************************************************************************/
void AllocateWorkSpace(CtrlType *ctrl, GraphType *graph, int nparts)
{
ctrl->wspace.pmat = NULL;
if (ctrl->optype == OP_KMETIS) {
ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateWorkSpace: edegrees");
ctrl->wspace.vedegrees = NULL;
ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees;
ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat");
/* Memory requirements for different phases
Coarsening
Matching: 4*nvtxs vectors
Contraction: 2*nvtxs vectors (from the above 4), 1*nparts, 1*Nedges
Total = MAX(4*nvtxs, 2*nvtxs+nparts+nedges)
Refinement
Random Refinement/Balance: 5*nparts + 1*nvtxs + 2*nedges
Greedy Refinement/Balance: 5*nparts + 2*nvtxs + 2*nedges + 1*PQueue(==Nvtxs)
Total = 5*nparts + 3*nvtxs + 2*nedges
Total = 5*nparts + 3*nvtxs + 2*nedges
*/
ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */
5*(nparts+1) + /* Partition weights etc */
graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */
20 /* padding for 64 bit machines */
;
}
else if (ctrl->optype == OP_KVMETIS) {
ctrl->wspace.edegrees = NULL;
ctrl->wspace.vedegrees = (VEDegreeType *)GKmalloc(graph->nedges*sizeof(VEDegreeType), "AllocateWorkSpace: vedegrees");
ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.vedegrees;
ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat");
/* Memory requirements for different phases are identical to KMETIS */
ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */
3*(nparts+1) + /* Partition weights etc */
graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */
20 /* padding for 64 bit machines */
;
}
else {
ctrl->wspace.edegrees = (EDegreeType *)idxmalloc(graph->nedges, "AllocateWorkSpace: edegrees");
ctrl->wspace.vedegrees = NULL;
ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees;
ctrl->wspace.maxcore = 5*(graph->nvtxs+1) + /* Refinement vectors */
4*(nparts+1) + /* Partition weights etc */
2*graph->ncon*graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* 2-way refinement */
2*graph->ncon*(NEG_GAINSPAN+PLUS_GAINSPAN+1)*(sizeof(ListNodeType *)/sizeof(idxtype)) + /* 2-way refinement */
20 /* padding for 64 bit machines */
;
}
ctrl->wspace.maxcore += HTLENGTH;
ctrl->wspace.core = idxmalloc(ctrl->wspace.maxcore, "AllocateWorkSpace: maxcore");
ctrl->wspace.ccore = 0;
}
/*************************************************************************
* This function allocates memory for the workspace
**************************************************************************/
void FreeWorkSpace(CtrlType *ctrl, GraphType *graph)
{
GKfree(&ctrl->wspace.edegrees, &ctrl->wspace.vedegrees, &ctrl->wspace.core, &ctrl->wspace.pmat, LTERM);
}
/*************************************************************************
* This function returns how may words are left in the workspace
**************************************************************************/
int WspaceAvail(CtrlType *ctrl)
{
return ctrl->wspace.maxcore - ctrl->wspace.ccore;
}
/*************************************************************************
* This function allocate space from the core
**************************************************************************/
idxtype *idxwspacemalloc(CtrlType *ctrl, int n)
{
n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
ctrl->wspace.ccore += n;
ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore);
return ctrl->wspace.core + ctrl->wspace.ccore - n;
}
/*************************************************************************
* This function frees space from the core
**************************************************************************/
void idxwspacefree(CtrlType *ctrl, int n)
{
n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
ctrl->wspace.ccore -= n;
ASSERT(ctrl->wspace.ccore >= 0);
}
/*************************************************************************
* This function allocate space from the core
**************************************************************************/
float *fwspacemalloc(CtrlType *ctrl, int n)
{
n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
ctrl->wspace.ccore += n;
ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore);
return (float *) (ctrl->wspace.core + ctrl->wspace.ccore - n);
}
/*************************************************************************
* This function frees space from the core
**************************************************************************/
void fwspacefree(CtrlType *ctrl, int n)
{
n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
ctrl->wspace.ccore -= n;
ASSERT(ctrl->wspace.ccore >= 0);
}
/*************************************************************************
* This function creates a CoarseGraphType data structure and initializes
* the various fields
**************************************************************************/
GraphType *CreateGraph(void)
{
GraphType *graph;
graph = (GraphType *)GKmalloc(sizeof(GraphType), "CreateCoarseGraph: graph");
InitGraph(graph);
return graph;
}
/*************************************************************************
* This function creates a CoarseGraphType data structure and initializes
* the various fields
**************************************************************************/
void InitGraph(GraphType *graph)
{
graph->gdata = graph->rdata = NULL;
graph->nvtxs = graph->nedges = -1;
graph->mincut = graph->minvol = -1;
graph->xadj = graph->vwgt = graph->adjncy = graph->adjwgt = NULL;
graph->adjwgtsum = NULL;
graph->label = NULL;
graph->cmap = NULL;
graph->where = graph->pwgts = NULL;
graph->id = graph->ed = NULL;
graph->bndptr = graph->bndind = NULL;
graph->rinfo = NULL;
graph->vrinfo = NULL;
graph->nrinfo = NULL;
graph->ncon = -1;
graph->nvwgt = NULL;
graph->npwgts = NULL;
graph->vsize = NULL;
graph->coarser = graph->finer = NULL;
}
/*************************************************************************
* This function deallocates any memory stored in a graph
**************************************************************************/
void FreeGraph(GraphType *graph)
{
GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->npwgts, LTERM);
free(graph);
}

View File

@ -0,0 +1,399 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mesh.c
*
* This file contains routines for converting 3D and 4D finite element
* meshes into dual or nodal graphs
*
* Started 8/18/97
* George
*
* $Id: mesh.c,v 1.2 2003/07/22 20:29:03 karypis Exp $
*
*/
#include <metis.h>
/*****************************************************************************
* This function creates a graph corresponding to the dual of a finite element
* mesh. At this point the supported elements are triangles, tetrahedrons, and
* bricks.
******************************************************************************/
void METIS_MeshToDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag,
idxtype *dxadj, idxtype *dadjncy)
{
int esizes[] = {-1, 3, 4, 8, 4};
if (*numflag == 1)
ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts);
GENDUALMETIS(*ne, *nn, *etype, elmnts, dxadj, dadjncy);
if (*numflag == 1)
ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *ne, dxadj, dadjncy);
}
/*****************************************************************************
* This function creates a graph corresponding to the finite element mesh.
* At this point the supported elements are triangles, tetrahedrons.
******************************************************************************/
void METIS_MeshToNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag,
idxtype *dxadj, idxtype *dadjncy)
{
int esizes[] = {-1, 3, 4, 8, 4};
if (*numflag == 1)
ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts);
switch (*etype) {
case 1:
TRINODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy);
break;
case 2:
TETNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy);
break;
case 3:
HEXNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy);
break;
case 4:
QUADNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy);
break;
}
if (*numflag == 1)
ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *nn, dxadj, dadjncy);
}
/*****************************************************************************
* This function creates the dual of a finite element mesh
******************************************************************************/
void GENDUALMETIS(int nelmnts, int nvtxs, int etype, idxtype *elmnts, idxtype *dxadj,
idxtype *dadjncy)
{
int i, j, jj, k, kk, kkk, l, m, n, nedges, mask;
idxtype *nptr, *nind;
idxtype *mark, ind[200], wgt[200];
int esize, esizes[] = {-1, 3, 4, 8, 4},
mgcnum, mgcnums[] = {-1, 2, 3, 4, 2};
mask = (1<<11)-1;
mark = idxsmalloc(mask+1, -1, "GENDUALMETIS: mark");
/* Get the element size and magic number for the particular element */
esize = esizes[etype];
mgcnum = mgcnums[etype];
/* Construct the node-element list first */
nptr = idxsmalloc(nvtxs+1, 0, "GENDUALMETIS: nptr");
for (j=esize*nelmnts, i=0; i<j; i++)
nptr[elmnts[i]]++;
MAKECSR(i, nvtxs, nptr);
nind = idxmalloc(nptr[nvtxs], "GENDUALMETIS: nind");
for (k=i=0; i<nelmnts; i++) {
for (j=0; j<esize; j++, k++)
nind[nptr[elmnts[k]]++] = i;
}
for (i=nvtxs; i>0; i--)
nptr[i] = nptr[i-1];
nptr[0] = 0;
for (i=0; i<nelmnts; i++)
dxadj[i] = esize*i;
for (i=0; i<nelmnts; i++) {
for (m=j=0; j<esize; j++) {
n = elmnts[esize*i+j];
for (k=nptr[n+1]-1; k>=nptr[n]; k--) {
if ((kk = nind[k]) <= i)
break;
kkk = kk&mask;
if ((l = mark[kkk]) == -1) {
ind[m] = kk;
wgt[m] = 1;
mark[kkk] = m++;
}
else if (ind[l] == kk) {
wgt[l]++;
}
else {
for (jj=0; jj<m; jj++) {
if (ind[jj] == kk) {
wgt[jj]++;
break;
}
}
if (jj == m) {
ind[m] = kk;
wgt[m++] = 1;
}
}
}
}
for (j=0; j<m; j++) {
if (wgt[j] == mgcnum) {
k = ind[j];
dadjncy[dxadj[i]++] = k;
dadjncy[dxadj[k]++] = i;
}
mark[ind[j]&mask] = -1;
}
}
/* Go and consolidate the dxadj and dadjncy */
for (j=i=0; i<nelmnts; i++) {
for (k=esize*i; k<dxadj[i]; k++, j++)
dadjncy[j] = dadjncy[k];
dxadj[i] = j;
}
for (i=nelmnts; i>0; i--)
dxadj[i] = dxadj[i-1];
dxadj[0] = 0;
free(mark);
free(nptr);
free(nind);
}
/*****************************************************************************
* This function creates the nodal graph of a finite element mesh
******************************************************************************/
void TRINODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
{
int i, j, jj, k, kk, kkk, l, m, n, nedges;
idxtype *nptr, *nind;
idxtype *mark;
/* Construct the node-element list first */
nptr = idxsmalloc(nvtxs+1, 0, "TRINODALMETIS: nptr");
for (j=3*nelmnts, i=0; i<j; i++)
nptr[elmnts[i]]++;
MAKECSR(i, nvtxs, nptr);
nind = idxmalloc(nptr[nvtxs], "TRINODALMETIS: nind");
for (k=i=0; i<nelmnts; i++) {
for (j=0; j<3; j++, k++)
nind[nptr[elmnts[k]]++] = i;
}
for (i=nvtxs; i>0; i--)
nptr[i] = nptr[i-1];
nptr[0] = 0;
mark = idxsmalloc(nvtxs, -1, "TRINODALMETIS: mark");
nedges = dxadj[0] = 0;
for (i=0; i<nvtxs; i++) {
mark[i] = i;
for (j=nptr[i]; j<nptr[i+1]; j++) {
for (jj=3*nind[j], k=0; k<3; k++, jj++) {
kk = elmnts[jj];
if (mark[kk] != i) {
mark[kk] = i;
dadjncy[nedges++] = kk;
}
}
}
dxadj[i+1] = nedges;
}
free(mark);
free(nptr);
free(nind);
}
/*****************************************************************************
* This function creates the nodal graph of a finite element mesh
******************************************************************************/
void TETNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
{
int i, j, jj, k, kk, kkk, l, m, n, nedges;
idxtype *nptr, *nind;
idxtype *mark;
/* Construct the node-element list first */
nptr = idxsmalloc(nvtxs+1, 0, "TETNODALMETIS: nptr");
for (j=4*nelmnts, i=0; i<j; i++)
nptr[elmnts[i]]++;
MAKECSR(i, nvtxs, nptr);
nind = idxmalloc(nptr[nvtxs], "TETNODALMETIS: nind");
for (k=i=0; i<nelmnts; i++) {
for (j=0; j<4; j++, k++)
nind[nptr[elmnts[k]]++] = i;
}
for (i=nvtxs; i>0; i--)
nptr[i] = nptr[i-1];
nptr[0] = 0;
mark = idxsmalloc(nvtxs, -1, "TETNODALMETIS: mark");
nedges = dxadj[0] = 0;
for (i=0; i<nvtxs; i++) {
mark[i] = i;
for (j=nptr[i]; j<nptr[i+1]; j++) {
for (jj=4*nind[j], k=0; k<4; k++, jj++) {
kk = elmnts[jj];
if (mark[kk] != i) {
mark[kk] = i;
dadjncy[nedges++] = kk;
}
}
}
dxadj[i+1] = nedges;
}
free(mark);
free(nptr);
free(nind);
}
/*****************************************************************************
* This function creates the nodal graph of a finite element mesh
******************************************************************************/
void HEXNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
{
int i, j, jj, k, kk, kkk, l, m, n, nedges;
idxtype *nptr, *nind;
idxtype *mark;
int table[8][3] = {1, 3, 4,
0, 2, 5,
1, 3, 6,
0, 2, 7,
0, 5, 7,
1, 4, 6,
2, 5, 7,
3, 4, 6};
/* Construct the node-element list first */
nptr = idxsmalloc(nvtxs+1, 0, "HEXNODALMETIS: nptr");
for (j=8*nelmnts, i=0; i<j; i++)
nptr[elmnts[i]]++;
MAKECSR(i, nvtxs, nptr);
nind = idxmalloc(nptr[nvtxs], "HEXNODALMETIS: nind");
for (k=i=0; i<nelmnts; i++) {
for (j=0; j<8; j++, k++)
nind[nptr[elmnts[k]]++] = i;
}
for (i=nvtxs; i>0; i--)
nptr[i] = nptr[i-1];
nptr[0] = 0;
mark = idxsmalloc(nvtxs, -1, "HEXNODALMETIS: mark");
nedges = dxadj[0] = 0;
for (i=0; i<nvtxs; i++) {
mark[i] = i;
for (j=nptr[i]; j<nptr[i+1]; j++) {
jj=8*nind[j];
for (k=0; k<8; k++) {
if (elmnts[jj+k] == i)
break;
}
ASSERT(k != 8);
/* You found the index, now go and put the 3 neighbors */
kk = elmnts[jj+table[k][0]];
if (mark[kk] != i) {
mark[kk] = i;
dadjncy[nedges++] = kk;
}
kk = elmnts[jj+table[k][1]];
if (mark[kk] != i) {
mark[kk] = i;
dadjncy[nedges++] = kk;
}
kk = elmnts[jj+table[k][2]];
if (mark[kk] != i) {
mark[kk] = i;
dadjncy[nedges++] = kk;
}
}
dxadj[i+1] = nedges;
}
free(mark);
free(nptr);
free(nind);
}
/*****************************************************************************
* This function creates the nodal graph of a finite element mesh
******************************************************************************/
void QUADNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
{
int i, j, jj, k, kk, kkk, l, m, n, nedges;
idxtype *nptr, *nind;
idxtype *mark;
int table[4][2] = {1, 3,
0, 2,
1, 3,
0, 2};
/* Construct the node-element list first */
nptr = idxsmalloc(nvtxs+1, 0, "QUADNODALMETIS: nptr");
for (j=4*nelmnts, i=0; i<j; i++)
nptr[elmnts[i]]++;
MAKECSR(i, nvtxs, nptr);
nind = idxmalloc(nptr[nvtxs], "QUADNODALMETIS: nind");
for (k=i=0; i<nelmnts; i++) {
for (j=0; j<4; j++, k++)
nind[nptr[elmnts[k]]++] = i;
}
for (i=nvtxs; i>0; i--)
nptr[i] = nptr[i-1];
nptr[0] = 0;
mark = idxsmalloc(nvtxs, -1, "QUADNODALMETIS: mark");
nedges = dxadj[0] = 0;
for (i=0; i<nvtxs; i++) {
mark[i] = i;
for (j=nptr[i]; j<nptr[i+1]; j++) {
jj=4*nind[j];
for (k=0; k<4; k++) {
if (elmnts[jj+k] == i)
break;
}
ASSERT(k != 4);
/* You found the index, now go and put the 2 neighbors */
kk = elmnts[jj+table[k][0]];
if (mark[kk] != i) {
mark[kk] = i;
dadjncy[nedges++] = kk;
}
kk = elmnts[jj+table[k][1]];
if (mark[kk] != i) {
mark[kk] = i;
dadjncy[nedges++] = kk;
}
}
dxadj[i+1] = nedges;
}
free(mark);
free(nptr);
free(nind);
}

View File

@ -0,0 +1,204 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* meshpart.c
*
* This file contains routines for partitioning finite element meshes.
*
* Started 9/29/97
* George
*
* $Id: meshpart.c,v 1.1 2003/07/16 15:55:08 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function partitions a finite element mesh by partitioning its nodal
* graph using KMETIS and then assigning elements in a load balanced fashion.
**************************************************************************/
void METIS_PartMeshNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag,
int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
int i, j, k, me;
idxtype *xadj, *adjncy, *pwgts;
int options[10], pnumflag=0, wgtflag=0;
int nnbrs, nbrind[200], nbrwgt[200], maxpwgt;
int esize, esizes[] = {-1, 3, 4, 8, 4};
esize = esizes[*etype];
if (*numflag == 1)
ChangeMesh2CNumbering((*ne)*esize, elmnts);
xadj = idxmalloc(*nn+1, "METIS_MESHPARTNODAL: xadj");
adjncy = idxmalloc(20*(*nn), "METIS_MESHPARTNODAL: adjncy");
METIS_MeshToNodal(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy);
adjncy = realloc(adjncy, xadj[*nn]*sizeof(idxtype));
options[0] = 0;
METIS_PartGraphKway(nn, xadj, adjncy, NULL, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, npart);
/* OK, now compute an element partition based on the nodal partition npart */
idxset(*ne, -1, epart);
pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTNODAL: pwgts");
for (i=0; i<*ne; i++) {
me = npart[elmnts[i*esize]];
for (j=1; j<esize; j++) {
if (npart[elmnts[i*esize+j]] != me)
break;
}
if (j == esize) {
epart[i] = me;
pwgts[me]++;
}
}
maxpwgt = 1.03*(*ne)/(*nparts);
for (i=0; i<*ne; i++) {
if (epart[i] == -1) { /* Assign the boundary element */
nnbrs = 0;
for (j=0; j<esize; j++) {
me = npart[elmnts[i*esize+j]];
for (k=0; k<nnbrs; k++) {
if (nbrind[k] == me) {
nbrwgt[k]++;
break;
}
}
if (k == nnbrs) {
nbrind[nnbrs] = me;
nbrwgt[nnbrs++] = 1;
}
}
/* Try to assign it first to the domain with most things in common */
j = iamax(nnbrs, nbrwgt);
if (pwgts[nbrind[j]] < maxpwgt) {
epart[i] = nbrind[j];
}
else {
/* If that fails, assign it to a light domain */
for (j=0; j<nnbrs; j++) {
if (pwgts[nbrind[j]] < maxpwgt) {
epart[i] = nbrind[j];
break;
}
}
if (j == nnbrs)
epart[i] = nbrind[iamax(nnbrs, nbrwgt)];
}
pwgts[epart[i]]++;
}
}
if (*numflag == 1)
ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart);
GKfree(&xadj, &adjncy, &pwgts, LTERM);
}
/*************************************************************************
* This function partitions a finite element mesh by partitioning its dual
* graph using KMETIS and then assigning nodes in a load balanced fashion.
**************************************************************************/
void METIS_PartMeshDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag,
int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
{
int i, j, k, me;
idxtype *xadj, *adjncy, *pwgts, *nptr, *nind;
int options[10], pnumflag=0, wgtflag=0;
int nnbrs, nbrind[200], nbrwgt[200], maxpwgt;
int esize, esizes[] = {-1, 3, 4, 8, 4};
esize = esizes[*etype];
if (*numflag == 1)
ChangeMesh2CNumbering((*ne)*esize, elmnts);
xadj = idxmalloc(*ne+1, "METIS_MESHPARTNODAL: xadj");
adjncy = idxmalloc(esize*(*ne), "METIS_MESHPARTNODAL: adjncy");
METIS_MeshToDual(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy);
options[0] = 0;
METIS_PartGraphKway(ne, xadj, adjncy, NULL, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, epart);
/* Construct the node-element list */
nptr = idxsmalloc(*nn+1, 0, "METIS_MESHPARTDUAL: nptr");
for (j=esize*(*ne), i=0; i<j; i++)
nptr[elmnts[i]]++;
MAKECSR(i, *nn, nptr);
nind = idxmalloc(nptr[*nn], "METIS_MESHPARTDUAL: nind");
for (k=i=0; i<(*ne); i++) {
for (j=0; j<esize; j++, k++)
nind[nptr[elmnts[k]]++] = i;
}
for (i=(*nn); i>0; i--)
nptr[i] = nptr[i-1];
nptr[0] = 0;
/* OK, now compute a nodal partition based on the element partition npart */
idxset(*nn, -1, npart);
pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTDUAL: pwgts");
for (i=0; i<*nn; i++) {
me = epart[nind[nptr[i]]];
for (j=nptr[i]+1; j<nptr[i+1]; j++) {
if (epart[nind[j]] != me)
break;
}
if (j == nptr[i+1]) {
npart[i] = me;
pwgts[me]++;
}
}
maxpwgt = 1.03*(*nn)/(*nparts);
for (i=0; i<*nn; i++) {
if (npart[i] == -1) { /* Assign the boundary element */
nnbrs = 0;
for (j=nptr[i]; j<nptr[i+1]; j++) {
me = epart[nind[j]];
for (k=0; k<nnbrs; k++) {
if (nbrind[k] == me) {
nbrwgt[k]++;
break;
}
}
if (k == nnbrs) {
nbrind[nnbrs] = me;
nbrwgt[nnbrs++] = 1;
}
}
/* Try to assign it first to the domain with most things in common */
j = iamax(nnbrs, nbrwgt);
if (pwgts[nbrind[j]] < maxpwgt) {
npart[i] = nbrind[j];
}
else {
/* If that fails, assign it to a light domain */
npart[i] = nbrind[0];
for (j=0; j<nnbrs; j++) {
if (pwgts[nbrind[j]] < maxpwgt) {
npart[i] = nbrind[j];
break;
}
}
}
pwgts[npart[i]]++;
}
}
if (*numflag == 1)
ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart);
GKfree(&xadj, &adjncy, &pwgts, &nptr, &nind, LTERM);
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* metis.h
*
* This file includes all necessary header files
*
* Started 8/27/94
* George
*
* $Id: metis.h,v 1.3 2003/07/25 13:52:00 karypis Exp $
*/
/*
#define DEBUG 1
#define DMALLOC 1
*/
#include "stdheaders.h"
#ifdef DMALLOC
#include <dmalloc.h>
#endif
#include "../parmetis.h" /* Get the idxtype definition */
#include "defs.h"
#include "struct.h"
#include "macros.h"
#include "rename.h"
#include "proto.h"

View File

@ -0,0 +1,341 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mfm.c
*
* This file contains code that implements the edge-based FM refinement
*
* Started 7/23/97
* George
*
* $Id: mfm.c,v 1.1 2003/07/24 18:39:09 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function performs an edge-based FM refinement
**************************************************************************/
void MocFM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, float *tpwgts, int npasses)
{
int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum;
idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
idxtype *moved, *swaps, *perm, *qnum;
float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal;
PQueueType parts[MAXNCON][2];
int higain, oldgain, mincut, initcut, newcut, mincutorder;
float rtpwgts[2];
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
npwgts = graph->npwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
moved = idxwspacemalloc(ctrl, nvtxs);
swaps = idxwspacemalloc(ctrl, nvtxs);
perm = idxwspacemalloc(ctrl, nvtxs);
qnum = idxwspacemalloc(ctrl, nvtxs);
limit = amin(amax(0.01*nvtxs, 25), 150);
/* Initialize the queues */
for (i=0; i<ncon; i++) {
PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
}
for (i=0; i<nvtxs; i++)
qnum[i] = samax(ncon, nvwgt+i*ncon);
origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
rtpwgts[0] = origbal*tpwgts[0];
rtpwgts[1] = origbal*tpwgts[1];
if (ctrl->dbglvl&DBG_REFINE) {
printf("Parts: [");
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal);
}
idxset(nvtxs, -1, moved);
for (pass=0; pass<npasses; pass++) { /* Do a number of passes */
for (i=0; i<ncon; i++) {
PQueueReset(&parts[i][0]);
PQueueReset(&parts[i][1]);
}
mincutorder = -1;
newcut = mincut = initcut = graph->mincut;
for (i=0; i<ncon; i++)
mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
minbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
/* Insert boundary nodes in the priority queues */
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (ii=0; ii<nbnd; ii++) {
i = bndind[perm[ii]];
ASSERT(ed[i] > 0 || id[i] == 0);
ASSERT(bndptr[i] != -1);
PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]);
}
for (nswaps=0; nswaps<nvtxs; nswaps++) {
SelectQueue(ncon, npwgts, rtpwgts, &from, &cnum, parts);
to = (from+1)%2;
if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1)
break;
ASSERT(bndptr[higain] != -1);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
newcut -= (ed[higain]-id[higain]);
newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
if ((newcut < mincut && newbal-origbal <= .00001) ||
(newcut == mincut && (newbal < minbal ||
(newbal == minbal && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) {
mincut = newcut;
minbal = newbal;
mincutorder = nswaps;
for (i=0; i<ncon; i++)
mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
}
else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
newcut += (ed[higain]-id[higain]);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
break;
}
where[higain] = to;
moved[higain] = nswaps;
swaps[nswaps] = higain;
if (ctrl->dbglvl&DBG_MOVEINFO) {
printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf(", %.3f LB: %.3f\n", minbal, 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];
oldgain = ed[k]-id[k];
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 */
PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain);
}
else { /* If it has not been moved, update its position in the queue */
if (moved[k] == -1)
PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]);
}
}
else {
if (ed[k] > 0) { /* It will now become a boundary vertex */
BNDInsert(nbnd, bndind, bndptr, k);
if (moved[k] == -1)
PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]);
}
}
}
}
/****************************************************************
* 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);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((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);
}
}
if (ctrl->dbglvl&DBG_REFINE) {
printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
}
graph->mincut = mincut;
graph->nbnd = nbnd;
if (mincutorder == -1 || mincut == initcut)
break;
}
for (i=0; i<ncon; i++) {
PQueueFree(ctrl, &parts[i][0]);
PQueueFree(ctrl, &parts[i][1]);
}
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function selects the partition number and the queue from which
* we will move vertices out
**************************************************************************/
void SelectQueue(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, PQueueType queues[MAXNCON][2])
{
int i, part, maxgain=0;
float max, maxdiff=0.0;
*from = -1;
*cnum = -1;
/* First determine the side and the queue, irrespective of the presence of nodes */
for (part=0; part<2; part++) {
for (i=0; i<ncon; i++) {
if (npwgts[part*ncon+i]-tpwgts[part] >= maxdiff) {
maxdiff = npwgts[part*ncon+i]-tpwgts[part];
*from = part;
*cnum = i;
}
}
}
/* printf("Selected %d(%d) -> %d\n", *from, *cnum, PQueueGetSize(&queues[*cnum][*from])); */
if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) {
/* The desired queue is empty, select a node from that side anyway */
for (i=0; i<ncon; i++) {
if (PQueueGetSize(&queues[i][*from]) > 0) {
max = npwgts[(*from)*ncon + i];
*cnum = i;
break;
}
}
for (i++; i<ncon; i++) {
if (npwgts[(*from)*ncon + i] > max && PQueueGetSize(&queues[i][*from]) > 0) {
max = npwgts[(*from)*ncon + i];
*cnum = i;
}
}
}
/* Check to see if you can focus on the cut */
if (maxdiff <= 0.0 || *from == -1) {
maxgain = -100000;
for (part=0; part<2; part++) {
for (i=0; i<ncon; i++) {
if (PQueueGetSize(&queues[i][part]) > 0 && PQueueGetKey(&queues[i][part]) > maxgain) {
maxgain = PQueueGetKey(&queues[i][part]);
*from = part;
*cnum = i;
}
}
}
}
}
/*************************************************************************
* This function checks if the balance achieved is better than the diff
* For now, it uses a 2-norm measure
**************************************************************************/
int BetterBalance(int ncon, float *npwgts, float *tpwgts, float *diff)
{
int i;
float ndiff[MAXNCON];
for (i=0; i<ncon; i++)
ndiff[i] = fabs(tpwgts[0]-npwgts[i]);
return snorm2(ncon, ndiff) < snorm2(ncon, diff);
}
/*************************************************************************
* This function computes the load imbalance over all the constrains
**************************************************************************/
float Compute2WayHLoadImbalance(int ncon, float *npwgts, float *tpwgts)
{
int i;
float max=0.0, temp;
for (i=0; i<ncon; i++) {
/* temp = amax(npwgts[i]/tpwgts[0], npwgts[ncon+i]/tpwgts[1]); */
temp = fabs(tpwgts[0]-npwgts[i])/tpwgts[0];
max = (max < temp ? temp : max);
}
return 1.0+max;
}
/*************************************************************************
* This function computes the load imbalance over all the constrains
* For now assume that we just want balanced partitionings
**************************************************************************/
void Compute2WayHLoadImbalanceVec(int ncon, float *npwgts, float *tpwgts, float *lbvec)
{
int i;
for (i=0; i<ncon; i++)
lbvec[i] = 1.0 + fabs(tpwgts[0]-npwgts[i])/tpwgts[0];
}

View File

@ -0,0 +1,349 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mfm2.c
*
* This file contains code that implements the edge-based FM refinement
*
* Started 7/23/97
* George
*
* $Id: mfm2.c,v 1.1 2003/07/16 15:55:09 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function performs an edge-based FM refinement
**************************************************************************/
void MocFM_2WayEdgeRefine2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *orgubvec,
int npasses)
{
int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum;
idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
idxtype *moved, *swaps, *perm, *qnum;
float *nvwgt, *npwgts, origdiff[MAXNCON], origbal[MAXNCON], minbal[MAXNCON];
PQueueType parts[MAXNCON][2];
int higain, oldgain, mincut, initcut, newcut, mincutorder;
float *maxwgt, *minwgt, ubvec[MAXNCON], tvec[MAXNCON];
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
npwgts = graph->npwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
moved = idxwspacemalloc(ctrl, nvtxs);
swaps = idxwspacemalloc(ctrl, nvtxs);
perm = idxwspacemalloc(ctrl, nvtxs);
qnum = idxwspacemalloc(ctrl, nvtxs);
limit = amin(amax(0.01*nvtxs, 15), 100);
Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, origbal);
for (i=0; i<ncon; i++) {
origdiff[i] = fabs(tpwgts[0]-npwgts[i]);
ubvec[i] = amax(origbal[i], orgubvec[i]);
}
/* Setup the weight intervals of the two subdomains */
minwgt = fwspacemalloc(ctrl, 2*ncon);
maxwgt = fwspacemalloc(ctrl, 2*ncon);
for (i=0; i<2; i++) {
for (j=0; j<ncon; j++) {
maxwgt[i*ncon+j] = tpwgts[i]*ubvec[j];
minwgt[i*ncon+j] = tpwgts[i]*(1.0/ubvec[j]);
}
}
/* Initialize the queues */
for (i=0; i<ncon; i++) {
PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
}
for (i=0; i<nvtxs; i++)
qnum[i] = samax(ncon, nvwgt+i*ncon);
if (ctrl->dbglvl&DBG_REFINE) {
printf("Parts: [");
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: ", tpwgts[0], tpwgts[1],
graph->nvtxs, graph->nbnd, graph->mincut);
for (i=0; i<ncon; i++)
printf("%.3f ", origbal[i]);
printf("\n");
}
idxset(nvtxs, -1, moved);
for (pass=0; pass<npasses; pass++) { /* Do a number of passes */
for (i=0; i<ncon; i++) {
PQueueReset(&parts[i][0]);
PQueueReset(&parts[i][1]);
}
mincutorder = -1;
newcut = mincut = initcut = graph->mincut;
Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, minbal);
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
/* Insert boundary nodes in the priority queues */
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (ii=0; ii<nbnd; ii++) {
i = bndind[perm[ii]];
ASSERT(ed[i] > 0 || id[i] == 0);
ASSERT(bndptr[i] != -1);
PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]);
}
for (nswaps=0; nswaps<nvtxs; nswaps++) {
SelectQueue2(ncon, npwgts, tpwgts, &from, &cnum, parts, maxwgt);
to = (from+1)%2;
if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1)
break;
ASSERT(bndptr[higain] != -1);
newcut -= (ed[higain]-id[higain]);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec);
if ((newcut < mincut && AreAllBelow(ncon, tvec, ubvec)) ||
(newcut == mincut && IsBetter2wayBalance(ncon, tvec, minbal, ubvec))) {
mincut = newcut;
for (i=0; i<ncon; i++)
minbal[i] = tvec[i];
mincutorder = nswaps;
}
else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
newcut += (ed[higain]-id[higain]);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
break;
}
where[higain] = to;
moved[higain] = nswaps;
swaps[nswaps] = higain;
if (ctrl->dbglvl&DBG_MOVEINFO) {
printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf(", LB: ");
for (i=0; i<ncon; i++)
printf("%.3f ", tvec[i]);
if (mincutorder == nswaps)
printf(" *\n");
else
printf("\n");
}
/**************************************************************
* 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];
oldgain = ed[k]-id[k];
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 */
PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain);
}
else { /* If it has not been moved, update its position in the queue */
if (moved[k] == -1)
PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]);
}
}
else {
if (ed[k] > 0) { /* It will now become a boundary vertex */
BNDInsert(nbnd, bndind, bndptr, k);
if (moved[k] == -1)
PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]);
}
}
}
}
/****************************************************************
* 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);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((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);
}
}
if (ctrl->dbglvl&DBG_REFINE) {
printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("], LB: ");
Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec);
for (i=0; i<ncon; i++)
printf("%.3f ", tvec[i]);
printf("\n");
}
graph->mincut = mincut;
graph->nbnd = nbnd;
if (mincutorder == -1 || mincut == initcut)
break;
}
for (i=0; i<ncon; i++) {
PQueueFree(ctrl, &parts[i][0]);
PQueueFree(ctrl, &parts[i][1]);
}
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
fwspacefree(ctrl, 2*ncon);
fwspacefree(ctrl, 2*ncon);
}
/*************************************************************************
* This function selects the partition number and the queue from which
* we will move vertices out
**************************************************************************/
void SelectQueue2(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum,
PQueueType queues[MAXNCON][2], float *maxwgt)
{
int i, j, maxgain=0;
float diff, max, maxdiff=0.0;
*from = -1;
*cnum = -1;
/* First determine the side and the queue, irrespective of the presence of nodes */
for (j=0; j<2; j++) {
for (i=0; i<ncon; i++) {
diff = npwgts[j*ncon+i]-maxwgt[j*ncon+i];
if (diff >= maxdiff) {
maxdiff = diff;
*from = j;
*cnum = i;
}
}
}
if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) {
/* The desired queue is empty, select a node from that side anyway */
for (i=0; i<ncon; i++) {
if (PQueueGetSize(&queues[i][*from]) > 0) {
max = (npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]);
*cnum = i;
break;
}
}
for (i++; i<ncon; i++) {
diff = npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i];
if (diff > max && PQueueGetSize(&queues[i][*from]) > 0) {
max = diff;
*cnum = i;
}
}
}
/* Check to see if you can focus on the cut */
if (maxdiff <= 0.0) {
maxgain = -100000;
for (j=0; j<2; j++) {
for (i=0; i<ncon; i++) {
if (PQueueGetSize(&queues[i][j]) > 0 && PQueueGetKey(&queues[i][j]) > maxgain) {
maxgain = PQueueGetKey(&queues[i][j]);
*from = j;
*cnum = i;
}
}
}
/* printf("(%2d %2d) %3d\n", *from, *cnum, maxgain); */
}
}
/*************************************************************************
* This function checks if the newbal is better than oldbal given the
* ubvector ubvec
**************************************************************************/
int IsBetter2wayBalance(int ncon, float *newbal, float *oldbal, float *ubvec)
{
int i, j;
float max1=0.0, max2=0.0, sum1=0.0, sum2=0.0, tmp;
for (i=0; i<ncon; i++) {
tmp = (newbal[i]-1)/(ubvec[i]-1);
max1 = (max1 < tmp ? tmp : max1);
sum1 += tmp;
tmp = (oldbal[i]-1)/(ubvec[i]-1);
max2 = (max2 < tmp ? tmp : max2);
sum2 += tmp;
}
if (max1 < max2)
return 1;
else if (max1 > max2)
return 0;
else
return sum1 <= sum2;
}

View File

@ -0,0 +1,259 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mincover.c
*
* This file implements the minimum cover algorithm
*
* Started 8/1/97
* George
*
* $Id: mincover.c,v 1.1 2003/07/16 15:55:09 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* Constants used by mincover algorithm
**************************************************************************/
#define INCOL 10
#define INROW 20
#define VC 1
#define SC 2
#define HC 3
#define VR 4
#define SR 5
#define HR 6
/*************************************************************************
* This function returns the min-cover of a bipartite graph.
* The algorithm used is due to Hopcroft and Karp as modified by Duff etal
* adj: the adjacency list of the bipartite graph
* asize: the number of vertices in the first part of the bipartite graph
* bsize-asize: the number of vertices in the second part
* 0..(asize-1) > A vertices
* asize..bsize > B vertices
*
* Returns:
* cover : the actual cover (array)
* csize : the size of the cover
**************************************************************************/
void MinCover(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *cover, int *csize)
{
int i, j;
idxtype *mate, *queue, *flag, *level, *lst;
int fptr, rptr, lstptr;
int row, maxlevel, col;
mate = idxsmalloc(bsize, -1, "MinCover: mate");
flag = idxmalloc(bsize, "MinCover: flag");
level = idxmalloc(bsize, "MinCover: level");
queue = idxmalloc(bsize, "MinCover: queue");
lst = idxmalloc(bsize, "MinCover: lst");
/* Get a cheap matching */
for (i=0; i<asize; i++) {
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (mate[adjncy[j]] == -1) {
mate[i] = adjncy[j];
mate[adjncy[j]] = i;
break;
}
}
}
/* Get into the main loop */
while (1) {
/* Initialization */
fptr = rptr = 0; /* Empty Queue */
lstptr = 0; /* Empty List */
for (i=0; i<bsize; i++) {
level[i] = -1;
flag[i] = 0;
}
maxlevel = bsize;
/* Insert free nodes into the queue */
for (i=0; i<asize; i++)
if (mate[i] == -1) {
queue[rptr++] = i;
level[i] = 0;
}
/* Perform the BFS */
while (fptr != rptr) {
row = queue[fptr++];
if (level[row] < maxlevel) {
flag[row] = 1;
for (j=xadj[row]; j<xadj[row+1]; j++) {
col = adjncy[j];
if (!flag[col]) { /* If this column has not been accessed yet */
flag[col] = 1;
if (mate[col] == -1) { /* Free column node was found */
maxlevel = level[row];
lst[lstptr++] = col;
}
else { /* This column node is matched */
if (flag[mate[col]])
printf("\nSomething wrong, flag[%d] is 1",mate[col]);
queue[rptr++] = mate[col];
level[mate[col]] = level[row] + 1;
}
}
}
}
}
if (lstptr == 0)
break; /* No free columns can be reached */
/* Perform restricted DFS from the free column nodes */
for (i=0; i<lstptr; i++)
MinCover_Augment(xadj, adjncy, lst[i], mate, flag, level, maxlevel);
}
MinCover_Decompose(xadj, adjncy, asize, bsize, mate, cover, csize);
GKfree(&mate, &flag, &level, &queue, &lst, LTERM);
}
/*************************************************************************
* This function perfoms a restricted DFS and augments matchings
**************************************************************************/
int MinCover_Augment(idxtype *xadj, idxtype *adjncy, int col, idxtype *mate, idxtype *flag, idxtype *level, int maxlevel)
{
int i;
int row = -1;
int status;
flag[col] = 2;
for (i=xadj[col]; i<xadj[col+1]; i++) {
row = adjncy[i];
if (flag[row] == 1) { /* First time through this row node */
if (level[row] == maxlevel) { /* (col, row) is an edge of the G^T */
flag[row] = 2; /* Mark this node as being visited */
if (maxlevel != 0)
status = MinCover_Augment(xadj, adjncy, mate[row], mate, flag, level, maxlevel-1);
else
status = 1;
if (status) {
mate[col] = row;
mate[row] = col;
return 1;
}
}
}
}
return 0;
}
/*************************************************************************
* This function performs a coarse decomposition and determines the
* min-cover.
* REF: Pothen ACMTrans. on Amth Software
**************************************************************************/
void MinCover_Decompose(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *mate, idxtype *cover, int *csize)
{
int i, k;
idxtype *where;
int card[10];
where = idxmalloc(bsize, "MinCover_Decompose: where");
for (i=0; i<10; i++)
card[i] = 0;
for (i=0; i<asize; i++)
where[i] = SC;
for (; i<bsize; i++)
where[i] = SR;
for (i=0; i<asize; i++)
if (mate[i] == -1)
MinCover_ColDFS(xadj, adjncy, i, mate, where, INCOL);
for (; i<bsize; i++)
if (mate[i] == -1)
MinCover_RowDFS(xadj, adjncy, i, mate, where, INROW);
for (i=0; i<bsize; i++)
card[where[i]]++;
k = 0;
if (abs(card[VC]+card[SC]-card[HR]) < abs(card[VC]-card[SR]-card[HR])) { /* S = VC+SC+HR */
/* printf("%d %d ",vc+sc, hr); */
for (i=0; i<bsize; i++)
if (where[i] == VC || where[i] == SC || where[i] == HR)
cover[k++] = i;
}
else { /* S = VC+SR+HR */
/* printf("%d %d ",vc, hr+sr); */
for (i=0; i<bsize; i++)
if (where[i] == VC || where[i] == SR || where[i] == HR)
cover[k++] = i;
}
*csize = k;
free(where);
}
/*************************************************************************
* This function perfoms a dfs starting from an unmatched col node
* forming alternate paths
**************************************************************************/
void MinCover_ColDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag)
{
int i;
if (flag == INCOL) {
if (where[root] == HC)
return;
where[root] = HC;
for (i=xadj[root]; i<xadj[root+1]; i++)
MinCover_ColDFS(xadj, adjncy, adjncy[i], mate, where, INROW);
}
else {
if (where[root] == HR)
return;
where[root] = HR;
if (mate[root] != -1)
MinCover_ColDFS(xadj, adjncy, mate[root], mate, where, INCOL);
}
}
/*************************************************************************
* This function perfoms a dfs starting from an unmatched col node
* forming alternate paths
**************************************************************************/
void MinCover_RowDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag)
{
int i;
if (flag == INROW) {
if (where[root] == VR)
return;
where[root] = VR;
for (i=xadj[root]; i<xadj[root+1]; i++)
MinCover_RowDFS(xadj, adjncy, adjncy[i], mate, where, INCOL);
}
else {
if (where[root] == VC)
return;
where[root] = VC;
if (mate[root] != -1)
MinCover_RowDFS(xadj, adjncy, mate[root], mate, where, INROW);
}
}

View File

@ -0,0 +1,358 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* minitpart.c
*
* This file contains code that performs the initial partition of the
* coarsest graph
*
* Started 7/23/97
* George
*
* $Id: minitpart.c,v 1.2 2003/07/31 16:23:29 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function computes the initial bisection of the coarsest graph
**************************************************************************/
void MocInit2WayPartition(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
{
int i, dbglvl;
dbglvl = ctrl->dbglvl;
IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE);
IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
switch (ctrl->IType) {
case IPART_GGPKL:
if (graph->nedges == 0)
MocRandomBisection(ctrl, graph, tpwgts, ubfactor);
else
MocGrowBisection(ctrl, graph, tpwgts, ubfactor);
break;
case IPART_RANDOM:
MocRandomBisection(ctrl, graph, tpwgts, ubfactor);
break;
default:
errexit("Unknown initial partition type: %d\n", ctrl->IType);
}
IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d\n", graph->mincut));
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
ctrl->dbglvl = dbglvl;
}
/*************************************************************************
* This function takes a graph and produces a bisection by using a region
* growing algorithm. The resulting partition is returned in
* graph->where
**************************************************************************/
void MocGrowBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
{
int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs;
idxtype *bestwhere, *where;
nvtxs = graph->nvtxs;
MocAllocate2WayPartitionMemory(ctrl, graph);
where = graph->where;
bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
bestcut = idxsum(graph->nedges, graph->adjwgt);
for (; nbfs>0; nbfs--) {
idxset(nvtxs, 1, where);
where[RandomInRange(nvtxs)] = 0;
MocCompute2WayPartitionParams(ctrl, graph);
MocInit2WayBalance(ctrl, graph, tpwgts);
MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
MocBalance2Way(ctrl, graph, tpwgts, 1.02);
MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
if (bestcut > graph->mincut) {
bestcut = graph->mincut;
idxcopy(nvtxs, where, bestwhere);
if (bestcut == 0)
break;
}
}
graph->mincut = bestcut;
idxcopy(nvtxs, bestwhere, where);
GKfree(&bestwhere, LTERM);
}
/*************************************************************************
* This function takes a graph and produces a bisection by using a region
* growing algorithm. The resulting partition is returned in
* graph->where
**************************************************************************/
void MocRandomBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
{
int i, ii, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs, qnum;
idxtype *bestwhere, *where, *perm;
int counts[MAXNCON];
float *nvwgt;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
nvwgt = graph->nvwgt;
MocAllocate2WayPartitionMemory(ctrl, graph);
where = graph->where;
bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
bestcut = idxsum(graph->nedges, graph->adjwgt);
perm = idxmalloc(nvtxs, "BisectGraph: perm");
for (; nbfs>0; nbfs--) {
for (i=0; i<ncon; i++)
counts[i] = 0;
RandomPermute(nvtxs, perm, 1);
/* Partition by spliting the queues randomly */
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
qnum = samax(ncon, nvwgt+i*ncon);
where[i] = counts[qnum];
counts[qnum] = (counts[qnum]+1)%2;
}
MocCompute2WayPartitionParams(ctrl, graph);
MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6);
MocBalance2Way(ctrl, graph, tpwgts, 1.02);
MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6);
MocBalance2Way(ctrl, graph, tpwgts, 1.02);
MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6);
/*
printf("Edgecut: %6d, NPwgts: [", graph->mincut);
for (i=0; i<graph->ncon; i++)
printf("(%.3f %.3f) ", graph->npwgts[i], graph->npwgts[graph->ncon+i]);
printf("]\n");
*/
if (bestcut > graph->mincut) {
bestcut = graph->mincut;
idxcopy(nvtxs, where, bestwhere);
if (bestcut == 0)
break;
}
}
graph->mincut = bestcut;
idxcopy(nvtxs, bestwhere, where);
GKfree(&bestwhere, &perm, LTERM);
}
/*************************************************************************
* This function balances two partitions by moving the highest gain
* (including negative gain) vertices to the other domain.
* It is used only when tha unbalance is due to non contigous
* subdomains. That is, the are no boundary vertices.
* It moves vertices from the domain that is overweight to the one that
* is underweight.
**************************************************************************/
void MocInit2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts)
{
int i, ii, j, k, l, kwgt, nvtxs, nbnd, ncon, nswaps, from, to, pass, me, cnum, tmp;
idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
idxtype *perm, *qnum;
float *nvwgt, *npwgts;
PQueueType parts[MAXNCON][2];
int higain, oldgain, mincut;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
adjncy = graph->adjncy;
nvwgt = graph->nvwgt;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
npwgts = graph->npwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
perm = idxwspacemalloc(ctrl, nvtxs);
qnum = idxwspacemalloc(ctrl, nvtxs);
/* This is called for initial partitioning so we know from where to pick nodes */
from = 1;
to = (from+1)%2;
if (ctrl->dbglvl&DBG_REFINE) {
printf("Parts: [");
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1],
graph->nvtxs, graph->nbnd, graph->mincut,
Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
}
for (i=0; i<ncon; i++) {
PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
}
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
ASSERT(CheckGraph(graph));
/* Compute the queues in which each vertex will be assigned to */
for (i=0; i<nvtxs; i++)
qnum[i] = samax(ncon, nvwgt+i*ncon);
/* Insert the nodes of the proper partition in the appropriate priority queue */
RandomPermute(nvtxs, perm, 1);
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (where[i] == from) {
if (ed[i] > 0)
PQueueInsert(&parts[qnum[i]][0], i, ed[i]-id[i]);
else
PQueueInsert(&parts[qnum[i]][1], i, ed[i]-id[i]);
}
}
mincut = graph->mincut;
nbnd = graph->nbnd;
for (nswaps=0; nswaps<nvtxs; nswaps++) {
if (AreAnyVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, tpwgts[from]))
break;
if ((cnum = SelectQueueOneWay(ncon, npwgts, tpwgts, from, parts)) == -1)
break;
if ((higain = PQueueGetMax(&parts[cnum][0])) == -1)
higain = PQueueGetMax(&parts[cnum][1]);
mincut -= (ed[higain]-id[higain]);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
where[higain] = to;
if (ctrl->dbglvl&DBG_MOVEINFO) {
printf("Moved %6d from %d(%d). [%5d] %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], mincut);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
if (ed[higain] == 0 && id[higain] > 0)
printf("\t Pulled from the interior!\n");
}
/**************************************************************
* Update the id[i]/ed[i] values of the affected nodes
***************************************************************/
SWAP(id[higain], ed[higain], tmp);
if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
BNDDelete(nbnd, bndind, bndptr, higain);
if (ed[higain] > 0 && bndptr[higain] == -1)
BNDInsert(nbnd, bndind, bndptr, higain);
for (j=xadj[higain]; j<xadj[higain+1]; j++) {
k = adjncy[j];
oldgain = ed[k]-id[k];
kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
INC_DEC(id[k], ed[k], kwgt);
/* Update the queue position */
if (where[k] == from) {
if (ed[k] > 0 && bndptr[k] == -1) { /* It moves in boundary */
PQueueDelete(&parts[qnum[k]][1], k, oldgain);
PQueueInsert(&parts[qnum[k]][0], k, ed[k]-id[k]);
}
else { /* It must be in the boundary already */
if (bndptr[k] == -1)
printf("What you thought was wrong!\n");
PQueueUpdate(&parts[qnum[k]][0], k, oldgain, ed[k]-id[k]);
}
}
/* Update its boundary information */
if (ed[k] == 0 && bndptr[k] != -1)
BNDDelete(nbnd, bndind, bndptr, k);
else if (ed[k] > 0 && bndptr[k] == -1)
BNDInsert(nbnd, bndind, bndptr, k);
}
ASSERTP(ComputeCut(graph, where) == mincut, ("%d != %d\n", ComputeCut(graph, where), mincut));
}
if (ctrl->dbglvl&DBG_REFINE) {
printf("\tMincut: %6d, NBND: %6d, NPwgts: ", mincut, nbnd);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
}
graph->mincut = mincut;
graph->nbnd = nbnd;
for (i=0; i<ncon; i++) {
PQueueFree(ctrl, &parts[i][0]);
PQueueFree(ctrl, &parts[i][1]);
}
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function selects the partition number and the queue from which
* we will move vertices out
**************************************************************************/
int SelectQueueOneWay(int ncon, float *npwgts, float *tpwgts, int from, PQueueType queues[MAXNCON][2])
{
int i, cnum=-1;
float max=0.0;
for (i=0; i<ncon; i++) {
if (npwgts[from*ncon+i]-tpwgts[from] >= max &&
PQueueGetSize(&queues[i][0]) + PQueueGetSize(&queues[i][1]) > 0) {
max = npwgts[from*ncon+i]-tpwgts[0];
cnum = i;
}
}
return cnum;
}

View File

@ -0,0 +1,368 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* minitpart2.c
*
* This file contains code that performs the initial partition of the
* coarsest graph
*
* Started 7/23/97
* George
*
* $Id: minitpart2.c,v 1.1 2003/07/16 15:55:10 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function computes the initial bisection of the coarsest graph
**************************************************************************/
void MocInit2WayPartition2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
{
int dbglvl;
dbglvl = ctrl->dbglvl;
IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE);
IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
switch (ctrl->IType) {
case IPART_GGPKL:
case IPART_RANDOM:
MocGrowBisection2(ctrl, graph, tpwgts, ubvec);
break;
case 3:
MocGrowBisectionNew2(ctrl, graph, tpwgts, ubvec);
break;
default:
errexit("Unknown initial partition type: %d\n", ctrl->IType);
}
IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d\n", graph->mincut));
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
ctrl->dbglvl = dbglvl;
}
/*************************************************************************
* This function takes a graph and produces a bisection by using a region
* growing algorithm. The resulting partition is returned in
* graph->where
**************************************************************************/
void MocGrowBisection2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
{
int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs;
idxtype *bestwhere, *where;
nvtxs = graph->nvtxs;
MocAllocate2WayPartitionMemory(ctrl, graph);
where = graph->where;
bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
bestcut = idxsum(graph->nedges, graph->adjwgt);
for (; nbfs>0; nbfs--) {
idxset(nvtxs, 1, where);
where[RandomInRange(nvtxs)] = 0;
MocCompute2WayPartitionParams(ctrl, graph);
MocBalance2Way2(ctrl, graph, tpwgts, ubvec);
MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4);
MocBalance2Way2(ctrl, graph, tpwgts, ubvec);
MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4);
if (bestcut > graph->mincut) {
bestcut = graph->mincut;
idxcopy(nvtxs, where, bestwhere);
if (bestcut == 0)
break;
}
}
graph->mincut = bestcut;
idxcopy(nvtxs, bestwhere, where);
GKfree(&bestwhere, LTERM);
}
/*************************************************************************
* This function takes a graph and produces a bisection by using a region
* growing algorithm. The resulting partition is returned in
* graph->where
**************************************************************************/
void MocGrowBisectionNew2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
{
int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs;
idxtype *bestwhere, *where;
nvtxs = graph->nvtxs;
MocAllocate2WayPartitionMemory(ctrl, graph);
where = graph->where;
bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
bestcut = idxsum(graph->nedges, graph->adjwgt);
for (; nbfs>0; nbfs--) {
idxset(nvtxs, 1, where);
where[RandomInRange(nvtxs)] = 0;
MocCompute2WayPartitionParams(ctrl, graph);
MocInit2WayBalance2(ctrl, graph, tpwgts, ubvec);
MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4);
if (bestcut > graph->mincut) {
bestcut = graph->mincut;
idxcopy(nvtxs, where, bestwhere);
if (bestcut == 0)
break;
}
}
graph->mincut = bestcut;
idxcopy(nvtxs, bestwhere, where);
GKfree(&bestwhere, LTERM);
}
/*************************************************************************
* This function balances two partitions by moving the highest gain
* (including negative gain) vertices to the other domain.
* It is used only when tha unbalance is due to non contigous
* subdomains. That is, the are no boundary vertices.
* It moves vertices from the domain that is overweight to the one that
* is underweight.
**************************************************************************/
void MocInit2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
{
int i, ii, j, k, l, kwgt, nvtxs, nbnd, ncon, nswaps, from, to, pass, me, cnum, tmp, imin;
idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
idxtype *moved, *perm, *qnum;
float *nvwgt, *npwgts, minwgt;
PQueueType parts[MAXNCON][2];
int higain, oldgain, mincut;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
adjncy = graph->adjncy;
nvwgt = graph->nvwgt;
adjwgt = graph->adjwgt;
where = graph->where;
id = graph->id;
ed = graph->ed;
npwgts = graph->npwgts;
bndptr = graph->bndptr;
bndind = graph->bndind;
moved = idxwspacemalloc(ctrl, nvtxs);
perm = idxwspacemalloc(ctrl, nvtxs);
qnum = idxwspacemalloc(ctrl, nvtxs);
/* This is called for initial partitioning so we know from where to pick nodes */
from = 1;
to = (from+1)%2;
if (ctrl->dbglvl&DBG_REFINE) {
printf("Parts: [");
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, ComputeLoadImbalance(ncon, 2, npwgts, tpwgts));
}
for (i=0; i<ncon; i++) {
PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
}
idxset(nvtxs, -1, moved);
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
ASSERT(CheckGraph(graph));
/* Compute the queues in which each vertex will be assigned to */
for (i=0; i<nvtxs; i++)
qnum[i] = samax(ncon, nvwgt+i*ncon);
/* Insert the nodes of the proper partition in the appropriate priority queue */
RandomPermute(nvtxs, perm, 1);
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (where[i] == from) {
if (ed[i] > 0)
PQueueInsert(&parts[qnum[i]][0], i, ed[i]-id[i]);
else
PQueueInsert(&parts[qnum[i]][1], i, ed[i]-id[i]);
}
}
/*
for (i=0; i<ncon; i++)
printf("Queue #%d has %d %d\n", i, parts[i][0].nnodes, parts[i][1].nnodes);
*/
/* Determine the termination criterion */
imin = 0;
for (i=1; i<ncon; i++)
imin = (ubvec[i] < ubvec[imin] ? i : imin);
minwgt = .5/ubvec[imin];
mincut = graph->mincut;
nbnd = graph->nbnd;
for (nswaps=0; nswaps<nvtxs; nswaps++) {
/* Exit as soon as the minimum weight crossed over */
if (npwgts[to*ncon+imin] > minwgt)
break;
if ((cnum = SelectQueueOneWay2(ncon, npwgts+to*ncon, parts, ubvec)) == -1)
break;
if ((higain = PQueueGetMax(&parts[cnum][0])) == -1)
higain = PQueueGetMax(&parts[cnum][1]);
mincut -= (ed[higain]-id[higain]);
saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
where[higain] = to;
moved[higain] = nswaps;
if (ctrl->dbglvl&DBG_MOVEINFO) {
printf("Moved %6d from %d(%d). [%5d] %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], mincut);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf(", LB: %.3f\n", ComputeLoadImbalance(ncon, 2, npwgts, tpwgts));
if (ed[higain] == 0 && id[higain] > 0)
printf("\t Pulled from the interior!\n");
}
/**************************************************************
* Update the id[i]/ed[i] values of the affected nodes
***************************************************************/
SWAP(id[higain], ed[higain], tmp);
if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
BNDDelete(nbnd, bndind, bndptr, higain);
if (ed[higain] > 0 && bndptr[higain] == -1)
BNDInsert(nbnd, bndind, bndptr, higain);
for (j=xadj[higain]; j<xadj[higain+1]; j++) {
k = adjncy[j];
oldgain = ed[k]-id[k];
kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
INC_DEC(id[k], ed[k], kwgt);
/* Update the queue position */
if (moved[k] == -1 && where[k] == from) {
if (ed[k] > 0 && bndptr[k] == -1) { /* It moves in boundary */
PQueueDelete(&parts[qnum[k]][1], k, oldgain);
PQueueInsert(&parts[qnum[k]][0], k, ed[k]-id[k]);
}
else { /* It must be in the boundary already */
if (bndptr[k] == -1)
printf("What you thought was wrong!\n");
PQueueUpdate(&parts[qnum[k]][0], k, oldgain, ed[k]-id[k]);
}
}
/* Update its boundary information */
if (ed[k] == 0 && bndptr[k] != -1)
BNDDelete(nbnd, bndind, bndptr, k);
else if (ed[k] > 0 && bndptr[k] == -1)
BNDInsert(nbnd, bndind, bndptr, k);
}
ASSERTP(ComputeCut(graph, where) == mincut, ("%d != %d\n", ComputeCut(graph, where), mincut));
}
if (ctrl->dbglvl&DBG_REFINE) {
printf("\tMincut: %6d, NBND: %6d, NPwgts: ", mincut, nbnd);
for (l=0; l<ncon; l++)
printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
printf(", LB: %.3f\n", ComputeLoadImbalance(ncon, 2, npwgts, tpwgts));
}
graph->mincut = mincut;
graph->nbnd = nbnd;
for (i=0; i<ncon; i++) {
PQueueFree(ctrl, &parts[i][0]);
PQueueFree(ctrl, &parts[i][1]);
}
ASSERT(ComputeCut(graph, where) == graph->mincut);
ASSERT(CheckBnd(graph));
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function selects the partition number and the queue from which
* we will move vertices out
**************************************************************************/
int SelectQueueOneWay2(int ncon, float *pto, PQueueType queues[MAXNCON][2], float *ubvec)
{
int i, cnum=-1, imax, maxgain;
float max=0.0;
float twgt[MAXNCON];
for (i=0; i<ncon; i++) {
if (max < pto[i]) {
imax = i;
max = pto[i];
}
}
for (i=0; i<ncon; i++)
twgt[i] = (max/(ubvec[imax]*ubvec[i]))/pto[i];
twgt[imax] = 0.0;
max = 0.0;
for (i=0; i<ncon; i++) {
if (max < twgt[i] && (PQueueGetSize(&queues[i][0]) > 0 || PQueueGetSize(&queues[i][1]) > 0)) {
max = twgt[i];
cnum = i;
}
}
if (max > 1)
return cnum;
/* optimize of cut */
maxgain = -10000000;
for (i=0; i<ncon; i++) {
if (PQueueGetSize(&queues[i][0]) > 0 && PQueueGetKey(&queues[i][0]) > maxgain) {
maxgain = PQueueGetKey(&queues[i][0]);
cnum = i;
}
}
return cnum;
}

View File

@ -0,0 +1,124 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mkmetis.c
*
* This file contains the top level routines for the multilevel k-way partitioning
* algorithm KMETIS.
*
* Started 7/28/97
* George
*
* $Id: mkmetis.c,v 1.1 2003/07/16 15:55:10 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point for KWMETIS
**************************************************************************/
void METIS_mCPartGraphKway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag,
int *nparts, float *rubvec, int *options, int *edgecut,
idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
SetUpGraph(&graph, OP_KMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = McKMETIS_CTYPE;
ctrl.IType = McKMETIS_ITYPE;
ctrl.RType = McKMETIS_RTYPE;
ctrl.dbglvl = McKMETIS_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)/(20*log2Int(*nparts)), 30*(*nparts));
ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
ASSERT(CheckGraph(&graph));
*edgecut = MCMlevelKWayPartitioning(&ctrl, &graph, *nparts, part, rubvec);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
if (*numflag == 1)
Change2FNumbering(*nvtxs, xadj, adjncy, part);
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
int MCMlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part,
float *rubvec)
{
int i, j, nvtxs;
GraphType *cgraph;
int options[10], edgecut;
cgraph = MCCoarsen2Way(ctrl, graph);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
MocAllocateKWayPartitionMemory(ctrl, cgraph, nparts);
options[0] = 1;
options[OPTION_CTYPE] = MATCH_SBHEM_INFNORM;
options[OPTION_ITYPE] = IPART_RANDOM;
options[OPTION_RTYPE] = RTYPE_FM;
options[OPTION_DBGLVL] = 0;
/* Determine what you will use as the initial partitioner, based on tolerances */
for (i=0; i<graph->ncon; i++) {
if (rubvec[i] > 1.2)
break;
}
if (i == graph->ncon)
METIS_mCPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon,
cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts,
options, &edgecut, cgraph->where);
else
METIS_mCHPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon,
cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts,
rubvec, options, &edgecut, cgraph->where);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut));
IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where));
MocRefineKWayHorizontal(ctrl, graph, cgraph, nparts, rubvec);
idxcopy(graph->nvtxs, graph->where, part);
GKfree(&graph->nvwgt, &graph->gdata, &graph->rdata, LTERM);
return graph->mincut;
}

View File

@ -0,0 +1,677 @@
/*
* mkwayfmh.c
*
* This file contains code that implements the multilevel k-way refinement
*
* Started 7/28/97
* George
*
* $Id: mkwayfmh.c,v 1.1 2003/07/16 15:55:10 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function performs k-way refinement
**************************************************************************/
void MCRandom_KWayEdgeRefineHorizontal(CtrlType *ctrl, GraphType *graph, int nparts,
float *orgubvec, int npasses)
{
int i, ii, iii, j, jj, k, l, pass, nvtxs, ncon, nmoves, nbnd, myndegrees, same;
int from, me, to, oldcut, gain;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *where, *perm, *bndptr, *bndind;
EDegreeType *myedegrees;
RInfoType *myrinfo;
float *npwgts, *nvwgt, *minwgt, *maxwgt, maxlb, minlb, ubvec[MAXNCON], tvec[MAXNCON];
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
bndptr = graph->bndptr;
bndind = graph->bndind;
where = graph->where;
npwgts = graph->npwgts;
/* Setup the weight intervals of the various subdomains */
minwgt = fwspacemalloc(ctrl, nparts*ncon);
maxwgt = fwspacemalloc(ctrl, nparts*ncon);
/* See if the orgubvec consists of identical constraints */
maxlb = minlb = orgubvec[0];
for (i=1; i<ncon; i++) {
minlb = (orgubvec[i] < minlb ? orgubvec[i] : minlb);
maxlb = (orgubvec[i] > maxlb ? orgubvec[i] : maxlb);
}
same = (fabs(maxlb-minlb) < .01 ? 1 : 0);
/* Let's not get very optimistic. Let Balancing do the work */
ComputeHKWayLoadImbalance(ncon, nparts, npwgts, ubvec);
for (i=0; i<ncon; i++)
ubvec[i] = amax(ubvec[i], orgubvec[i]);
if (!same) {
for (i=0; i<nparts; i++) {
for (j=0; j<ncon; j++) {
maxwgt[i*ncon+j] = ubvec[j]/nparts;
minwgt[i*ncon+j] = 1.0/(ubvec[j]*nparts);
}
}
}
else {
maxlb = ubvec[0];
for (i=1; i<ncon; i++)
maxlb = (ubvec[i] > maxlb ? ubvec[i] : maxlb);
for (i=0; i<nparts; i++) {
for (j=0; j<ncon; j++) {
maxwgt[i*ncon+j] = maxlb/nparts;
minwgt[i*ncon+j] = 1.0/(maxlb*nparts);
}
}
}
perm = idxwspacemalloc(ctrl, nvtxs);
if (ctrl->dbglvl&DBG_REFINE) {
printf("Partitions: [%5.4f %5.4f], Nv-Nb[%6d %6d]. Cut: %6d, LB: ",
npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)],
graph->nvtxs, graph->nbnd, graph->mincut);
ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec);
for (i=0; i<ncon; i++)
printf("%.3f ", tvec[i]);
printf("\n");
}
for (pass=0; pass<npasses; pass++) {
ASSERT(ComputeCut(graph, where) == graph->mincut);
oldcut = graph->mincut;
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (nmoves=iii=0; iii<graph->nbnd; iii++) {
ii = perm[iii];
if (ii >= nbnd)
continue;
i = bndind[ii];
myrinfo = graph->rinfo+i;
if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */
from = where[i];
nvwgt = graph->nvwgt+i*ncon;
if (myrinfo->id > 0 && AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, -1.0, nvwgt, minwgt+from*ncon))
continue; /* This cannot be moved! */
myedegrees = myrinfo->edegrees;
myndegrees = myrinfo->ndegrees;
for (k=0; k<myndegrees; k++) {
to = myedegrees[k].pid;
gain = myedegrees[k].ed - myrinfo->id;
if (gain >= 0 &&
(AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon) ||
IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec)))
break;
}
if (k == myndegrees)
continue; /* break out if you did not find a candidate */
for (j=k+1; j<myndegrees; j++) {
to = myedegrees[j].pid;
if ((myedegrees[j].ed > myedegrees[k].ed &&
(AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon) ||
IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec))) ||
(myedegrees[j].ed == myedegrees[k].ed &&
IsHBalanceBetterTT(ncon, nparts, npwgts+myedegrees[k].pid*ncon, npwgts+to*ncon, nvwgt, ubvec)))
k = j;
}
to = myedegrees[k].pid;
if (myedegrees[k].ed-myrinfo->id == 0
&& !IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec)
&& AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, npwgts+from*ncon, maxwgt+from*ncon))
continue;
/*=====================================================================
* If we got here, we can now move the vertex from 'from' to 'to'
*======================================================================*/
graph->mincut -= myedegrees[k].ed-myrinfo->id;
IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
/* Update where, weight, and ID/ED information of the vertex you moved */
saxpy(ncon, 1.0, nvwgt, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt, 1, npwgts+from*ncon, 1);
where[i] = to;
myrinfo->ed += myrinfo->id-myedegrees[k].ed;
SWAP(myrinfo->id, myedegrees[k].ed, j);
if (myedegrees[k].ed == 0)
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].pid = from;
if (myrinfo->ed-myrinfo->id < 0)
BNDDelete(nbnd, bndind, bndptr, i);
/* Update the degrees of adjacent vertices */
for (j=xadj[i]; j<xadj[i+1]; j++) {
ii = adjncy[j];
me = where[ii];
myrinfo = graph->rinfo+ii;
if (myrinfo->edegrees == NULL) {
myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
}
myedegrees = myrinfo->edegrees;
ASSERT(CheckRInfo(myrinfo));
if (me == from) {
INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1)
BNDInsert(nbnd, bndind, bndptr, ii);
}
else if (me == to) {
INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1)
BNDDelete(nbnd, bndind, bndptr, ii);
}
/* Remove contribution from the .ed of 'from' */
if (me != from) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == from) {
if (myedegrees[k].ed == adjwgt[j])
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].ed -= adjwgt[j];
break;
}
}
}
/* Add contribution to the .ed of 'to' */
if (me != to) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == to) {
myedegrees[k].ed += adjwgt[j];
break;
}
}
if (k == myrinfo->ndegrees) {
myedegrees[myrinfo->ndegrees].pid = to;
myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
}
}
ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
ASSERT(CheckRInfo(myrinfo));
}
nmoves++;
}
}
graph->nbnd = nbnd;
if (ctrl->dbglvl&DBG_REFINE) {
printf("\t [%5.4f %5.4f], Nb: %6d, Nmoves: %5d, Cut: %6d, LB: ",
npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)],
nbnd, nmoves, graph->mincut);
ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec);
for (i=0; i<ncon; i++)
printf("%.3f ", tvec[i]);
printf("\n");
}
if (graph->mincut == oldcut)
break;
}
fwspacefree(ctrl, ncon*nparts);
fwspacefree(ctrl, ncon*nparts);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function performs k-way refinement
**************************************************************************/
void MCGreedy_KWayEdgeBalanceHorizontal(CtrlType *ctrl, GraphType *graph, int nparts,
float *ubvec, int npasses)
{
int i, ii, iii, j, jj, k, l, pass, nvtxs, ncon, nbnd, myndegrees, oldgain, gain, nmoves;
int from, me, to, oldcut;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *where, *perm, *bndptr, *bndind, *moved;
EDegreeType *myedegrees;
RInfoType *myrinfo;
PQueueType queue;
float *npwgts, *nvwgt, *minwgt, *maxwgt, tvec[MAXNCON];
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
bndind = graph->bndind;
bndptr = graph->bndptr;
where = graph->where;
npwgts = graph->npwgts;
/* Setup the weight intervals of the various subdomains */
minwgt = fwspacemalloc(ctrl, ncon*nparts);
maxwgt = fwspacemalloc(ctrl, ncon*nparts);
for (i=0; i<nparts; i++) {
for (j=0; j<ncon; j++) {
maxwgt[i*ncon+j] = ubvec[j]/nparts;
minwgt[i*ncon+j] = 1.0/(ubvec[j]*nparts);
}
}
perm = idxwspacemalloc(ctrl, nvtxs);
moved = idxwspacemalloc(ctrl, nvtxs);
PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]);
if (ctrl->dbglvl&DBG_REFINE) {
printf("Partitions: [%5.4f %5.4f], Nv-Nb[%6d %6d]. Cut: %6d, LB: ",
npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)],
graph->nvtxs, graph->nbnd, graph->mincut);
ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec);
for (i=0; i<ncon; i++)
printf("%.3f ", tvec[i]);
printf("[B]\n");
}
for (pass=0; pass<npasses; pass++) {
ASSERT(ComputeCut(graph, where) == graph->mincut);
/* Check to see if things are out of balance, given the tolerance */
if (MocIsHBalanced(ncon, nparts, npwgts, ubvec))
break;
PQueueReset(&queue);
idxset(nvtxs, -1, moved);
oldcut = graph->mincut;
nbnd = graph->nbnd;
RandomPermute(nbnd, perm, 1);
for (ii=0; ii<nbnd; ii++) {
i = bndind[perm[ii]];
PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id);
moved[i] = 2;
}
nmoves = 0;
for (;;) {
if ((i = PQueueGetMax(&queue)) == -1)
break;
moved[i] = 1;
myrinfo = graph->rinfo+i;
from = where[i];
nvwgt = graph->nvwgt+i*ncon;
if (AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, -1.0, nvwgt, minwgt+from*ncon))
continue; /* This cannot be moved! */
myedegrees = myrinfo->edegrees;
myndegrees = myrinfo->ndegrees;
for (k=0; k<myndegrees; k++) {
to = myedegrees[k].pid;
if (IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec))
break;
}
if (k == myndegrees)
continue; /* break out if you did not find a candidate */
for (j=k+1; j<myndegrees; j++) {
to = myedegrees[j].pid;
if (IsHBalanceBetterTT(ncon, nparts, npwgts+myedegrees[k].pid*ncon, npwgts+to*ncon, nvwgt, ubvec))
k = j;
}
to = myedegrees[k].pid;
j = 0;
if (!AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, maxwgt+from*ncon))
j++;
if (myedegrees[k].ed-myrinfo->id >= 0)
j++;
if (!AreAllHVwgtsAbove(ncon, 1.0, npwgts+to*ncon, 0.0, nvwgt, minwgt+to*ncon) &&
AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon))
j++;
if (j == 0)
continue;
/* DELETE
if (myedegrees[k].ed-myrinfo->id < 0 &&
AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, maxwgt+from*ncon) &&
AreAllHVwgtsAbove(ncon, 1.0, npwgts+to*ncon, 0.0, nvwgt, minwgt+to*ncon) &&
AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon))
continue;
*/
/*=====================================================================
* If we got here, we can now move the vertex from 'from' to 'to'
*======================================================================*/
graph->mincut -= myedegrees[k].ed-myrinfo->id;
IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
/* Update where, weight, and ID/ED information of the vertex you moved */
saxpy(ncon, 1.0, nvwgt, 1, npwgts+to*ncon, 1);
saxpy(ncon, -1.0, nvwgt, 1, npwgts+from*ncon, 1);
where[i] = to;
myrinfo->ed += myrinfo->id-myedegrees[k].ed;
SWAP(myrinfo->id, myedegrees[k].ed, j);
if (myedegrees[k].ed == 0)
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].pid = from;
if (myrinfo->ed == 0)
BNDDelete(nbnd, bndind, bndptr, i);
/* Update the degrees of adjacent vertices */
for (j=xadj[i]; j<xadj[i+1]; j++) {
ii = adjncy[j];
me = where[ii];
myrinfo = graph->rinfo+ii;
if (myrinfo->edegrees == NULL) {
myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
}
myedegrees = myrinfo->edegrees;
ASSERT(CheckRInfo(myrinfo));
oldgain = (myrinfo->ed-myrinfo->id);
if (me == from) {
INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
if (myrinfo->ed > 0 && bndptr[ii] == -1)
BNDInsert(nbnd, bndind, bndptr, ii);
}
else if (me == to) {
INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
if (myrinfo->ed == 0 && bndptr[ii] != -1)
BNDDelete(nbnd, bndind, bndptr, ii);
}
/* Remove contribution from the .ed of 'from' */
if (me != from) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == from) {
if (myedegrees[k].ed == adjwgt[j])
myedegrees[k] = myedegrees[--myrinfo->ndegrees];
else
myedegrees[k].ed -= adjwgt[j];
break;
}
}
}
/* Add contribution to the .ed of 'to' */
if (me != to) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == to) {
myedegrees[k].ed += adjwgt[j];
break;
}
}
if (k == myrinfo->ndegrees) {
myedegrees[myrinfo->ndegrees].pid = to;
myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
}
}
/* Update the queue */
if (me == to || me == from) {
gain = myrinfo->ed-myrinfo->id;
if (moved[ii] == 2) {
if (myrinfo->ed > 0)
PQueueUpdate(&queue, ii, oldgain, gain);
else {
PQueueDelete(&queue, ii, oldgain);
moved[ii] = -1;
}
}
else if (moved[ii] == -1 && myrinfo->ed > 0) {
PQueueInsert(&queue, ii, gain);
moved[ii] = 2;
}
}
ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
ASSERT(CheckRInfo(myrinfo));
}
nmoves++;
}
graph->nbnd = nbnd;
if (ctrl->dbglvl&DBG_REFINE) {
printf("\t [%5.4f %5.4f], Nb: %6d, Nmoves: %5d, Cut: %6d, LB: ",
npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)],
nbnd, nmoves, graph->mincut);
ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec);
for (i=0; i<ncon; i++)
printf("%.3f ", tvec[i]);
printf("\n");
}
if (nmoves == 0)
break;
}
PQueueFree(ctrl, &queue);
fwspacefree(ctrl, ncon*nparts);
fwspacefree(ctrl, ncon*nparts);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function checks if the vertex weights of two vertices are below
* a given set of values
**************************************************************************/
int AreAllHVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit)
{
int i;
for (i=0; i<ncon; i++)
if (alpha*vwgt1[i] + beta*vwgt2[i] > limit[i])
return 0;
return 1;
}
/*************************************************************************
* This function checks if the vertex weights of two vertices are above
* a given set of values
**************************************************************************/
int AreAllHVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit)
{
int i;
for (i=0; i<ncon; i++)
if (alpha*vwgt1[i] + beta*vwgt2[i] < limit[i])
return 0;
return 1;
}
/*************************************************************************
* This function computes the load imbalance over all the constrains
* For now assume that we just want balanced partitionings
**************************************************************************/
void ComputeHKWayLoadImbalance(int ncon, int nparts, float *npwgts, float *lbvec)
{
int i, j;
float max;
for (i=0; i<ncon; i++) {
max = 0.0;
for (j=0; j<nparts; j++) {
if (npwgts[j*ncon+i] > max)
max = npwgts[j*ncon+i];
}
lbvec[i] = max*nparts;
}
}
/*************************************************************************
* This function determines if a partitioning is horizontally balanced
**************************************************************************/
int MocIsHBalanced(int ncon, int nparts, float *npwgts, float *ubvec)
{
int i, j;
float max;
for (i=0; i<ncon; i++) {
max = 0.0;
for (j=0; j<nparts; j++) {
if (npwgts[j*ncon+i] > max)
max = npwgts[j*ncon+i];
}
if (ubvec[i] < max*nparts)
return 0;
}
return 1;
}
/*************************************************************************
* This function checks if the pairwise balance of the between the two
* partitions will improve by moving the vertex v from pfrom to pto,
* subject to the target partition weights of tfrom, and tto respectively
**************************************************************************/
int IsHBalanceBetterFT(int ncon, int nparts, float *pfrom, float *pto, float *vwgt, float *ubvec)
{
int i, j, k;
float blb1=0.0, alb1=0.0, sblb=0.0, salb=0.0;
float blb2=0.0, alb2=0.0;
float temp;
for (i=0; i<ncon; i++) {
temp = amax(pfrom[i], pto[i])*nparts/ubvec[i];
if (blb1 < temp) {
blb2 = blb1;
blb1 = temp;
}
else if (blb2 < temp)
blb2 = temp;
sblb += temp;
temp = amax(pfrom[i]-vwgt[i], pto[i]+vwgt[i])*nparts/ubvec[i];
if (alb1 < temp) {
alb2 = alb1;
alb1 = temp;
}
else if (alb2 < temp)
alb2 = temp;
salb += temp;
}
if (alb1 < blb1)
return 1;
if (blb1 < alb1)
return 0;
if (alb2 < blb2)
return 1;
if (blb2 < alb2)
return 0;
return salb < sblb;
}
/*************************************************************************
* This function checks if it will be better to move a vertex to pt2 than
* to pt1 subject to their target weights of tt1 and tt2, respectively
* This routine takes into account the weight of the vertex in question
**************************************************************************/
int IsHBalanceBetterTT(int ncon, int nparts, float *pt1, float *pt2, float *vwgt, float *ubvec)
{
int i;
float m11=0.0, m12=0.0, m21=0.0, m22=0.0, sm1=0.0, sm2=0.0, temp;
for (i=0; i<ncon; i++) {
temp = (pt1[i]+vwgt[i])*nparts/ubvec[i];
if (m11 < temp) {
m12 = m11;
m11 = temp;
}
else if (m12 < temp)
m12 = temp;
sm1 += temp;
temp = (pt2[i]+vwgt[i])*nparts/ubvec[i];
if (m21 < temp) {
m22 = m21;
m21 = temp;
}
else if (m22 < temp)
m22 = temp;
sm2 += temp;
}
if (m21 < m11)
return 1;
if (m21 > m11)
return 0;
if (m22 < m12)
return 1;
if (m22 > m12)
return 0;
return sm2 < sm1;
}

View File

@ -0,0 +1,296 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mkwayrefine.c
*
* This file contains the driving routines for multilevel k-way refinement
*
* Started 7/28/97
* George
*
* $Id: mkwayrefine.c,v 1.1 2003/07/16 15:55:11 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of refinement
**************************************************************************/
void MocRefineKWayHorizontal(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts,
float *ubvec)
{
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
/* Compute the parameters of the coarsest graph */
MocComputeKWayPartitionParams(ctrl, graph, nparts);
for (;;) {
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
if (!MocIsHBalanced(graph->ncon, nparts, graph->npwgts, ubvec)) {
MocComputeKWayBalanceBoundary(ctrl, graph, nparts);
MCGreedy_KWayEdgeBalanceHorizontal(ctrl, graph, nparts, ubvec, 4);
ComputeKWayBoundary(ctrl, graph, nparts);
}
MCRandom_KWayEdgeRefineHorizontal(ctrl, graph, nparts, ubvec, 10);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
if (graph == orggraph)
break;
graph = graph->finer;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
MocProjectKWayPartition(ctrl, graph, nparts);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
}
if (!MocIsHBalanced(graph->ncon, nparts, graph->npwgts, ubvec)) {
MocComputeKWayBalanceBoundary(ctrl, graph, nparts);
MCGreedy_KWayEdgeBalanceHorizontal(ctrl, graph, nparts, ubvec, 4);
ComputeKWayBoundary(ctrl, graph, nparts);
MCRandom_KWayEdgeRefineHorizontal(ctrl, graph, nparts, ubvec, 10);
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
}
/*************************************************************************
* This function allocates memory for k-way edge refinement
**************************************************************************/
void MocAllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts)
{
int nvtxs, ncon, pad64;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
pad64 = (3*nvtxs+nparts)%2;
graph->rdata = idxmalloc(3*nvtxs+ncon*nparts+(sizeof(RInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateKWayPartitionMemory: rdata");
graph->npwgts = (float *)graph->rdata;
graph->where = graph->rdata + ncon*nparts;
graph->bndptr = graph->rdata + nvtxs + ncon*nparts;
graph->bndind = graph->rdata + 2*nvtxs + ncon*nparts;
graph->rinfo = (RInfoType *)(graph->rdata + 3*nvtxs+ncon*nparts + pad64);
}
/*************************************************************************
* This function computes the initial id/ed
**************************************************************************/
void MocComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, j, k, l, nvtxs, ncon, nbnd, mincut, me, other;
idxtype *xadj, *adjncy, *adjwgt, *where, *bndind, *bndptr;
RInfoType *rinfo, *myrinfo;
EDegreeType *myedegrees;
float *nvwgt, *npwgts;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
npwgts = sset(ncon*nparts, 0.0, graph->npwgts);
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
rinfo = graph->rinfo;
/*------------------------------------------------------------
/ Compute now the id/ed degrees
/------------------------------------------------------------*/
ctrl->wspace.cdegree = 0;
nbnd = mincut = 0;
for (i=0; i<nvtxs; i++) {
me = where[i];
saxpy(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1);
myrinfo = rinfo+i;
myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0;
myrinfo->edegrees = NULL;
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (me != where[adjncy[j]])
myrinfo->ed += adjwgt[j];
}
myrinfo->id = graph->adjwgtsum[i] - myrinfo->ed;
if (myrinfo->ed > 0)
mincut += myrinfo->ed;
if (myrinfo->ed-myrinfo->id >= 0)
BNDInsert(nbnd, bndind, bndptr, i);
/* Time to compute the particular external degrees */
if (myrinfo->ed > 0) {
myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
for (j=xadj[i]; j<xadj[i+1]; j++) {
other = where[adjncy[j]];
if (me != other) {
for (k=0; k<myrinfo->ndegrees; k++) {
if (myedegrees[k].pid == other) {
myedegrees[k].ed += adjwgt[j];
break;
}
}
if (k == myrinfo->ndegrees) {
myedegrees[myrinfo->ndegrees].pid = other;
myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
}
}
}
ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
}
}
graph->mincut = mincut/2;
graph->nbnd = nbnd;
}
/*************************************************************************
* This function projects a partition, and at the same time computes the
* parameters for refinement.
**************************************************************************/
void MocProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees;
idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
idxtype *cmap, *where, *bndptr, *bndind;
idxtype *cwhere;
GraphType *cgraph;
RInfoType *crinfo, *rinfo, *myrinfo;
EDegreeType *myedegrees;
idxtype *htable;
cgraph = graph->coarser;
cwhere = cgraph->where;
crinfo = cgraph->rinfo;
nvtxs = graph->nvtxs;
cmap = graph->cmap;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
MocAllocateKWayPartitionMemory(ctrl, graph, nparts);
where = graph->where;
rinfo = graph->rinfo;
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
/* Go through and project partition and compute id/ed for the nodes */
for (i=0; i<nvtxs; i++) {
k = cmap[i];
where[i] = cwhere[k];
cmap[i] = crinfo[k].ed; /* For optimization */
}
htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts));
ctrl->wspace.cdegree = 0;
for (nbnd=0, i=0; i<nvtxs; i++) {
me = where[i];
myrinfo = rinfo+i;
myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0;
myrinfo->edegrees = NULL;
myrinfo->id = adjwgtsum[i];
if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */
istart = xadj[i];
iend = xadj[i+1];
myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
ctrl->wspace.cdegree += iend-istart;
ndegrees = 0;
for (j=istart; j<iend; j++) {
other = where[adjncy[j]];
if (me != other) {
myrinfo->ed += adjwgt[j];
if ((k = htable[other]) == -1) {
htable[other] = ndegrees;
myedegrees[ndegrees].pid = other;
myedegrees[ndegrees++].ed = adjwgt[j];
}
else {
myedegrees[k].ed += adjwgt[j];
}
}
}
myrinfo->id -= myrinfo->ed;
/* Remove space for edegrees if it was interior */
if (myrinfo->ed == 0) {
myrinfo->edegrees = NULL;
ctrl->wspace.cdegree -= iend-istart;
}
else {
if (myrinfo->ed-myrinfo->id >= 0)
BNDInsert(nbnd, bndind, bndptr, i);
myrinfo->ndegrees = ndegrees;
for (j=0; j<ndegrees; j++)
htable[myedegrees[j].pid] = -1;
}
}
}
scopy(graph->ncon*nparts, cgraph->npwgts, graph->npwgts);
graph->mincut = cgraph->mincut;
graph->nbnd = nbnd;
FreeGraph(graph->coarser);
graph->coarser = NULL;
idxwspacefree(ctrl, nparts);
ASSERT(CheckBnd2(graph));
}
/*************************************************************************
* This function computes the boundary definition for balancing
**************************************************************************/
void MocComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
{
int i, nvtxs, nbnd;
idxtype *bndind, *bndptr;
nvtxs = graph->nvtxs;
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
/* Compute the new boundary */
nbnd = 0;
for (i=0; i<nvtxs; i++) {
if (graph->rinfo[i].ed > 0)
BNDInsert(nbnd, bndind, bndptr, i);
}
graph->nbnd = nbnd;
}

View File

@ -0,0 +1,501 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mmatch.c
*
* This file contains the code that computes matchings and creates the next
* level coarse graph.
*
* Started 7/23/97
* George
*
* $Id: mmatch.c,v 1.1 2003/07/16 15:55:11 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void MCMatch_RM(CtrlType *ctrl, GraphType *graph)
{
int i, ii, j, k, nvtxs, ncon, cnvtxs, maxidx;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *match, *cmap, *perm;
float *nvwgt;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
cmap = graph->cmap;
match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
perm = idxwspacemalloc(ctrl, nvtxs);
RandomPermute(nvtxs, perm, 1);
cnvtxs = 0;
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
/* Find a random matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (match[k] == UNMATCHED && AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) {
maxidx = k;
break;
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void MCMatch_HEM(CtrlType *ctrl, GraphType *graph)
{
int i, ii, j, k, l, nvtxs, cnvtxs, ncon, maxidx, maxwgt;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *match, *cmap, *perm;
float *nvwgt;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
cmap = graph->cmap;
match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
perm = idxwspacemalloc(ctrl, nvtxs);
RandomPermute(nvtxs, perm, 1);
cnvtxs = 0;
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
maxwgt = 0;
/* Find a heavy-edge matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (match[k] == UNMATCHED && maxwgt <= adjwgt[j] &&
AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) {
maxwgt = adjwgt[j];
maxidx = adjncy[j];
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void MCMatch_SHEM(CtrlType *ctrl, GraphType *graph)
{
int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *match, *cmap, *degrees, *perm, *tperm;
float *nvwgt;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
cmap = graph->cmap;
match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
perm = idxwspacemalloc(ctrl, nvtxs);
tperm = idxwspacemalloc(ctrl, nvtxs);
degrees = idxwspacemalloc(ctrl, nvtxs);
RandomPermute(nvtxs, tperm, 1);
avgdegree = 0.7*(xadj[nvtxs]/nvtxs);
for (i=0; i<nvtxs; i++)
degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]);
BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm);
cnvtxs = 0;
/* Take care any islands. Islands are matched with non-islands due to coarsening */
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
if (xadj[i] < xadj[i+1])
break;
maxidx = i;
for (j=nvtxs-1; j>ii; j--) {
k = perm[j];
if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) {
maxidx = k;
break;
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
/* Continue with normal matching */
for (; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
maxwgt = 0;
/* Find a heavy-edge matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (match[k] == UNMATCHED && maxwgt <= adjwgt[j] &&
AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) {
maxwgt = adjwgt[j];
maxidx = adjncy[j];
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
idxwspacefree(ctrl, nvtxs); /* degrees */
idxwspacefree(ctrl, nvtxs); /* tperm */
CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void MCMatch_SHEBM(CtrlType *ctrl, GraphType *graph, int norm)
{
int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *match, *cmap, *degrees, *perm, *tperm;
float *nvwgt;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
cmap = graph->cmap;
match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
perm = idxwspacemalloc(ctrl, nvtxs);
tperm = idxwspacemalloc(ctrl, nvtxs);
degrees = idxwspacemalloc(ctrl, nvtxs);
RandomPermute(nvtxs, tperm, 1);
avgdegree = 0.7*(xadj[nvtxs]/nvtxs);
for (i=0; i<nvtxs; i++)
degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]);
BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm);
cnvtxs = 0;
/* Take care any islands. Islands are matched with non-islands due to coarsening */
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
if (xadj[i] < xadj[i+1])
break;
maxidx = i;
for (j=nvtxs-1; j>ii; j--) {
k = perm[j];
if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) {
maxidx = k;
break;
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
/* Continue with normal matching */
for (; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
maxwgt = -1;
/* Find a heavy-edge matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (match[k] == UNMATCHED &&
AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt) &&
(maxwgt < adjwgt[j] ||
(maxwgt == adjwgt[j] &&
BetterVBalance(ncon, norm, nvwgt+i*ncon, nvwgt+maxidx*ncon, nvwgt+k*ncon) >= 0
)
)
) {
maxwgt = adjwgt[j];
maxidx = k;
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
idxwspacefree(ctrl, nvtxs); /* degrees */
idxwspacefree(ctrl, nvtxs); /* tperm */
CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function finds a matching using the HEM heuristic
**************************************************************************/
void MCMatch_SBHEM(CtrlType *ctrl, GraphType *graph, int norm)
{
int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree;
idxtype *xadj, *adjncy, *adjwgt;
idxtype *match, *cmap, *degrees, *perm, *tperm;
float *nvwgt, vbal;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
cmap = graph->cmap;
match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
perm = idxwspacemalloc(ctrl, nvtxs);
tperm = idxwspacemalloc(ctrl, nvtxs);
degrees = idxwspacemalloc(ctrl, nvtxs);
RandomPermute(nvtxs, tperm, 1);
avgdegree = 0.7*(xadj[nvtxs]/nvtxs);
for (i=0; i<nvtxs; i++)
degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]);
BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm);
cnvtxs = 0;
/* Take care any islands. Islands are matched with non-islands due to coarsening */
for (ii=0; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
if (xadj[i] < xadj[i+1])
break;
maxidx = i;
for (j=nvtxs-1; j>ii; j--) {
k = perm[j];
if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) {
maxidx = k;
break;
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
/* Continue with normal matching */
for (; ii<nvtxs; ii++) {
i = perm[ii];
if (match[i] == UNMATCHED) { /* Unmatched */
maxidx = i;
maxwgt = -1;
vbal = 0.0;
/* Find a heavy-edge matching, subject to maxvwgt constraints */
for (j=xadj[i]; j<xadj[i+1]; j++) {
k = adjncy[j];
if (match[k] == UNMATCHED && AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) {
if (maxidx != i)
vbal = BetterVBalance(ncon, norm, nvwgt+i*ncon, nvwgt+maxidx*ncon, nvwgt+k*ncon);
if (vbal > 0 || (vbal > -.01 && maxwgt < adjwgt[j])) {
maxwgt = adjwgt[j];
maxidx = k;
}
}
}
cmap[i] = cmap[maxidx] = cnvtxs++;
match[i] = maxidx;
match[maxidx] = i;
}
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
idxwspacefree(ctrl, nvtxs); /* degrees */
idxwspacefree(ctrl, nvtxs); /* tperm */
CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function checks if v+u2 provides a better balance in the weight
* vector that v+u1
**************************************************************************/
float BetterVBalance(int ncon, int norm, float *vwgt, float *u1wgt, float *u2wgt)
{
int i;
float sum1, sum2, max1, max2, min1, min2, diff1, diff2;
if (norm == -1) {
max1 = min1 = vwgt[0]+u1wgt[0];
max2 = min2 = vwgt[0]+u2wgt[0];
sum1 = vwgt[0]+u1wgt[0];
sum2 = vwgt[0]+u2wgt[0];
for (i=1; i<ncon; i++) {
if (max1 < vwgt[i]+u1wgt[i])
max1 = vwgt[i]+u1wgt[i];
if (min1 > vwgt[i]+u1wgt[i])
min1 = vwgt[i]+u1wgt[i];
if (max2 < vwgt[i]+u2wgt[i])
max2 = vwgt[i]+u2wgt[i];
if (min2 > vwgt[i]+u2wgt[i])
min2 = vwgt[i]+u2wgt[i];
sum1 += vwgt[i]+u1wgt[i];
sum2 += vwgt[i]+u2wgt[i];
}
return ((max1-min1)/sum1) - ((max2-min2)/sum2);
}
else if (norm == 1) {
sum1 = sum2 = 0.0;
for (i=0; i<ncon; i++) {
sum1 += vwgt[i]+u1wgt[i];
sum2 += vwgt[i]+u2wgt[i];
}
sum1 = sum1/(1.0*ncon);
sum2 = sum2/(1.0*ncon);
diff1 = diff2 = 0.0;
for (i=0; i<ncon; i++) {
diff1 += fabs(sum1 - (vwgt[i]+u1wgt[i]));
diff2 += fabs(sum2 - (vwgt[i]+u2wgt[i]));
}
return diff1 - diff2;
}
else {
errexit("Unknown norm: %d\n", norm);
}
return 0.0;
}
/*************************************************************************
* This function checks if the vertex weights of two vertices are below
* a given set of values
**************************************************************************/
int AreAllVwgtsBelowFast(int ncon, float *vwgt1, float *vwgt2, float limit)
{
int i;
for (i=0; i<ncon; i++)
if (vwgt1[i] + vwgt2[i] > limit)
return 0;
return 1;
}

View File

@ -0,0 +1,593 @@
/*
* mmd.c
*
* **************************************************************
* The following C function was developed from a FORTRAN subroutine
* in SPARSPAK written by Eleanor Chu, Alan George, Joseph Liu
* and Esmond Ng.
*
* The FORTRAN-to-C transformation and modifications such as dynamic
* memory allocation and deallocation were performed by Chunguang
* Sun.
* **************************************************************
*
* Taken from SMMS, George 12/13/94
*
* The meaning of invperm, and perm vectors is different from that
* in genqmd_ of SparsPak
*
* $Id: mmd.c,v 1.1 2003/07/16 15:55:11 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* genmmd -- multiple minimum external degree
* purpose -- this routine implements the minimum degree
* algorithm. it makes use of the implicit representation
* of elimination graphs by quotient graphs, and the notion
* of indistinguishable nodes. It also implements the modifications
* by multiple elimination and minimum external degree.
* Caution -- the adjacency vector adjncy will be destroyed.
* Input parameters --
* neqns -- number of equations.
* (xadj, adjncy) -- the adjacency structure.
* delta -- tolerance value for multiple elimination.
* maxint -- maximum machine representable (short) integer
* (any smaller estimate will do) for marking nodes.
* Output parameters --
* perm -- the minimum degree ordering.
* invp -- the inverse of perm.
* *ncsub -- an upper bound on the number of nonzero subscripts
* for the compressed storage scheme.
* Working parameters --
* head -- vector for head of degree lists.
* invp -- used temporarily for degree forward link.
* perm -- used temporarily for degree backward link.
* qsize -- vector for size of supernodes.
* list -- vector for temporary linked lists.
* marker -- a temporary marker vector.
* Subroutines used -- mmdelm, mmdint, mmdnum, mmdupd.
**************************************************************************/
void genmmd(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *invp, idxtype *perm,
int delta, idxtype *head, idxtype *qsize, idxtype *list, idxtype *marker,
int maxint, int *ncsub)
{
int ehead, i, mdeg, mdlmt, mdeg_node, nextmd, num, tag;
if (neqns <= 0)
return;
/* Adjust from C to Fortran */
xadj--; adjncy--; invp--; perm--; head--; qsize--; list--; marker--;
/* initialization for the minimum degree algorithm. */
*ncsub = 0;
mmdint(neqns, xadj, adjncy, head, invp, perm, qsize, list, marker);
/* 'num' counts the number of ordered nodes plus 1. */
num = 1;
/* eliminate all isolated nodes. */
nextmd = head[1];
while (nextmd > 0) {
mdeg_node = nextmd;
nextmd = invp[mdeg_node];
marker[mdeg_node] = maxint;
invp[mdeg_node] = -num;
num = num + 1;
}
/* search for node of the minimum degree. 'mdeg' is the current */
/* minimum degree; 'tag' is used to facilitate marking nodes. */
if (num > neqns)
goto n1000;
tag = 1;
head[1] = 0;
mdeg = 2;
/* infinite loop here ! */
while (1) {
while (head[mdeg] <= 0)
mdeg++;
/* use value of 'delta' to set up 'mdlmt', which governs */
/* when a degree update is to be performed. */
mdlmt = mdeg + delta;
ehead = 0;
n500:
mdeg_node = head[mdeg];
while (mdeg_node <= 0) {
mdeg++;
if (mdeg > mdlmt)
goto n900;
mdeg_node = head[mdeg];
};
/* remove 'mdeg_node' from the degree structure. */
nextmd = invp[mdeg_node];
head[mdeg] = nextmd;
if (nextmd > 0)
perm[nextmd] = -mdeg;
invp[mdeg_node] = -num;
*ncsub += mdeg + qsize[mdeg_node] - 2;
if ((num+qsize[mdeg_node]) > neqns)
goto n1000;
/* eliminate 'mdeg_node' and perform quotient graph */
/* transformation. reset 'tag' value if necessary. */
tag++;
if (tag >= maxint) {
tag = 1;
for (i = 1; i <= neqns; i++)
if (marker[i] < maxint)
marker[i] = 0;
};
mmdelm(mdeg_node, xadj, adjncy, head, invp, perm, qsize, list, marker, maxint, tag);
num += qsize[mdeg_node];
list[mdeg_node] = ehead;
ehead = mdeg_node;
if (delta >= 0)
goto n500;
n900:
/* update degrees of the nodes involved in the */
/* minimum degree nodes elimination. */
if (num > neqns)
goto n1000;
mmdupd( ehead, neqns, xadj, adjncy, delta, &mdeg, head, invp, perm, qsize, list, marker, maxint, &tag);
}; /* end of -- while ( 1 ) -- */
n1000:
mmdnum( neqns, perm, invp, qsize );
/* Adjust from Fortran back to C*/
xadj++; adjncy++; invp++; perm++; head++; qsize++; list++; marker++;
}
/**************************************************************************
* mmdelm ...... multiple minimum degree elimination
* Purpose -- This routine eliminates the node mdeg_node of minimum degree
* from the adjacency structure, which is stored in the quotient
* graph format. It also transforms the quotient graph representation
* of the elimination graph.
* Input parameters --
* mdeg_node -- node of minimum degree.
* maxint -- estimate of maximum representable (short) integer.
* tag -- tag value.
* Updated parameters --
* (xadj, adjncy) -- updated adjacency structure.
* (head, forward, backward) -- degree doubly linked structure.
* qsize -- size of supernode.
* marker -- marker vector.
* list -- temporary linked list of eliminated nabors.
***************************************************************************/
void mmdelm(int mdeg_node, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward,
idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker, int maxint,int tag)
{
int element, i, istop, istart, j,
jstop, jstart, link,
nabor, node, npv, nqnbrs, nxnode,
pvnode, rlmt, rloc, rnode, xqnbr;
/* find the reachable set of 'mdeg_node' and */
/* place it in the data structure. */
marker[mdeg_node] = tag;
istart = xadj[mdeg_node];
istop = xadj[mdeg_node+1] - 1;
/* 'element' points to the beginning of the list of */
/* eliminated nabors of 'mdeg_node', and 'rloc' gives the */
/* storage location for the next reachable node. */
element = 0;
rloc = istart;
rlmt = istop;
for ( i = istart; i <= istop; i++ ) {
nabor = adjncy[i];
if ( nabor == 0 ) break;
if ( marker[nabor] < tag ) {
marker[nabor] = tag;
if ( forward[nabor] < 0 ) {
list[nabor] = element;
element = nabor;
} else {
adjncy[rloc] = nabor;
rloc++;
};
}; /* end of -- if -- */
}; /* end of -- for -- */
/* merge with reachable nodes from generalized elements. */
while ( element > 0 ) {
adjncy[rlmt] = -element;
link = element;
n400:
jstart = xadj[link];
jstop = xadj[link+1] - 1;
for ( j = jstart; j <= jstop; j++ ) {
node = adjncy[j];
link = -node;
if ( node < 0 ) goto n400;
if ( node == 0 ) break;
if ((marker[node]<tag)&&(forward[node]>=0)) {
marker[node] = tag;
/*use storage from eliminated nodes if necessary.*/
while ( rloc >= rlmt ) {
link = -adjncy[rlmt];
rloc = xadj[link];
rlmt = xadj[link+1] - 1;
};
adjncy[rloc] = node;
rloc++;
};
}; /* end of -- for ( j = jstart; -- */
element = list[element];
}; /* end of -- while ( element > 0 ) -- */
if ( rloc <= rlmt ) adjncy[rloc] = 0;
/* for each node in the reachable set, do the following. */
link = mdeg_node;
n1100:
istart = xadj[link];
istop = xadj[link+1] - 1;
for ( i = istart; i <= istop; i++ ) {
rnode = adjncy[i];
link = -rnode;
if ( rnode < 0 ) goto n1100;
if ( rnode == 0 ) return;
/* 'rnode' is in the degree list structure. */
pvnode = backward[rnode];
if (( pvnode != 0 ) && ( pvnode != (-maxint) )) {
/* then remove 'rnode' from the structure. */
nxnode = forward[rnode];
if ( nxnode > 0 ) backward[nxnode] = pvnode;
if ( pvnode > 0 ) forward[pvnode] = nxnode;
npv = -pvnode;
if ( pvnode < 0 ) head[npv] = nxnode;
};
/* purge inactive quotient nabors of 'rnode'. */
jstart = xadj[rnode];
jstop = xadj[rnode+1] - 1;
xqnbr = jstart;
for ( j = jstart; j <= jstop; j++ ) {
nabor = adjncy[j];
if ( nabor == 0 ) break;
if ( marker[nabor] < tag ) {
adjncy[xqnbr] = nabor;
xqnbr++;
};
};
/* no active nabor after the purging. */
nqnbrs = xqnbr - jstart;
if ( nqnbrs <= 0 ) {
/* merge 'rnode' with 'mdeg_node'. */
qsize[mdeg_node] += qsize[rnode];
qsize[rnode] = 0;
marker[rnode] = maxint;
forward[rnode] = -mdeg_node;
backward[rnode] = -maxint;
} else {
/* flag 'rnode' for degree update, and */
/* add 'mdeg_node' as a nabor of 'rnode'. */
forward[rnode] = nqnbrs + 1;
backward[rnode] = 0;
adjncy[xqnbr] = mdeg_node;
xqnbr++;
if ( xqnbr <= jstop ) adjncy[xqnbr] = 0;
};
}; /* end of -- for ( i = istart; -- */
return;
}
/***************************************************************************
* mmdint ---- mult minimum degree initialization
* purpose -- this routine performs initialization for the
* multiple elimination version of the minimum degree algorithm.
* input parameters --
* neqns -- number of equations.
* (xadj, adjncy) -- adjacency structure.
* output parameters --
* (head, dfrow, backward) -- degree doubly linked structure.
* qsize -- size of supernode ( initialized to one).
* list -- linked list.
* marker -- marker vector.
****************************************************************************/
int mmdint(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward,
idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker)
{
int fnode, ndeg, node;
for ( node = 1; node <= neqns; node++ ) {
head[node] = 0;
qsize[node] = 1;
marker[node] = 0;
list[node] = 0;
};
/* initialize the degree doubly linked lists. */
for ( node = 1; node <= neqns; node++ ) {
ndeg = xadj[node+1] - xadj[node]/* + 1*/; /* george */
if (ndeg == 0)
ndeg = 1;
fnode = head[ndeg];
forward[node] = fnode;
head[ndeg] = node;
if ( fnode > 0 ) backward[fnode] = node;
backward[node] = -ndeg;
};
return 0;
}
/****************************************************************************
* mmdnum --- multi minimum degree numbering
* purpose -- this routine performs the final step in producing
* the permutation and inverse permutation vectors in the
* multiple elimination version of the minimum degree
* ordering algorithm.
* input parameters --
* neqns -- number of equations.
* qsize -- size of supernodes at elimination.
* updated parameters --
* invp -- inverse permutation vector. on input,
* if qsize[node] = 0, then node has been merged
* into the node -invp[node]; otherwise,
* -invp[node] is its inverse labelling.
* output parameters --
* perm -- the permutation vector.
****************************************************************************/
void mmdnum(int neqns, idxtype *perm, idxtype *invp, idxtype *qsize)
{
int father, nextf, node, nqsize, num, root;
for ( node = 1; node <= neqns; node++ ) {
nqsize = qsize[node];
if ( nqsize <= 0 ) perm[node] = invp[node];
if ( nqsize > 0 ) perm[node] = -invp[node];
};
/* for each node which has been merged, do the following. */
for ( node = 1; node <= neqns; node++ ) {
if ( perm[node] <= 0 ) {
/* trace the merged tree until one which has not */
/* been merged, call it root. */
father = node;
while ( perm[father] <= 0 )
father = - perm[father];
/* number node after root. */
root = father;
num = perm[root] + 1;
invp[node] = -num;
perm[root] = num;
/* shorten the merged tree. */
father = node;
nextf = - perm[father];
while ( nextf > 0 ) {
perm[father] = -root;
father = nextf;
nextf = -perm[father];
};
}; /* end of -- if ( perm[node] <= 0 ) -- */
}; /* end of -- for ( node = 1; -- */
/* ready to compute perm. */
for ( node = 1; node <= neqns; node++ ) {
num = -invp[node];
invp[node] = num;
perm[num] = node;
};
return;
}
/****************************************************************************
* mmdupd ---- multiple minimum degree update
* purpose -- this routine updates the degrees of nodes after a
* multiple elimination step.
* input parameters --
* ehead -- the beginning of the list of eliminated nodes
* (i.e., newly formed elements).
* neqns -- number of equations.
* (xadj, adjncy) -- adjacency structure.
* delta -- tolerance value for multiple elimination.
* maxint -- maximum machine representable (short) integer.
* updated parameters --
* mdeg -- new minimum degree after degree update.
* (head, forward, backward) -- degree doubly linked structure.
* qsize -- size of supernode.
* list -- marker vector for degree update.
* *tag -- tag value.
****************************************************************************/
void mmdupd(int ehead, int neqns, idxtype *xadj, idxtype *adjncy, int delta, int *mdeg,
idxtype *head, idxtype *forward, idxtype *backward, idxtype *qsize, idxtype *list,
idxtype *marker, int maxint,int *tag)
{
int deg, deg0, element, enode, fnode, i, iq2, istop,
istart, j, jstop, jstart, link, mdeg0, mtag, nabor,
node, q2head, qxhead;
mdeg0 = *mdeg + delta;
element = ehead;
n100:
if ( element <= 0 ) return;
/* for each of the newly formed element, do the following. */
/* reset tag value if necessary. */
mtag = *tag + mdeg0;
if ( mtag >= maxint ) {
*tag = 1;
for ( i = 1; i <= neqns; i++ )
if ( marker[i] < maxint ) marker[i] = 0;
mtag = *tag + mdeg0;
};
/* create two linked lists from nodes associated with 'element': */
/* one with two nabors (q2head) in the adjacency structure, and the*/
/* other with more than two nabors (qxhead). also compute 'deg0',*/
/* number of nodes in this element. */
q2head = 0;
qxhead = 0;
deg0 = 0;
link =element;
n400:
istart = xadj[link];
istop = xadj[link+1] - 1;
for ( i = istart; i <= istop; i++ ) {
enode = adjncy[i];
link = -enode;
if ( enode < 0 ) goto n400;
if ( enode == 0 ) break;
if ( qsize[enode] != 0 ) {
deg0 += qsize[enode];
marker[enode] = mtag;
/*'enode' requires a degree update*/
if ( backward[enode] == 0 ) {
/* place either in qxhead or q2head list. */
if ( forward[enode] != 2 ) {
list[enode] = qxhead;
qxhead = enode;
} else {
list[enode] = q2head;
q2head = enode;
};
};
}; /* enf of -- if ( qsize[enode] != 0 ) -- */
}; /* end of -- for ( i = istart; -- */
/* for each node in q2 list, do the following. */
enode = q2head;
iq2 = 1;
n900:
if ( enode <= 0 ) goto n1500;
if ( backward[enode] != 0 ) goto n2200;
(*tag)++;
deg = deg0;
/* identify the other adjacent element nabor. */
istart = xadj[enode];
nabor = adjncy[istart];
if ( nabor == element ) nabor = adjncy[istart+1];
link = nabor;
if ( forward[nabor] >= 0 ) {
/* nabor is uneliminated, increase degree count. */
deg += qsize[nabor];
goto n2100;
};
/* the nabor is eliminated. for each node in the 2nd element */
/* do the following. */
n1000:
istart = xadj[link];
istop = xadj[link+1] - 1;
for ( i = istart; i <= istop; i++ ) {
node = adjncy[i];
link = -node;
if ( node != enode ) {
if ( node < 0 ) goto n1000;
if ( node == 0 ) goto n2100;
if ( qsize[node] != 0 ) {
if ( marker[node] < *tag ) {
/* 'node' is not yet considered. */
marker[node] = *tag;
deg += qsize[node];
} else {
if ( backward[node] == 0 ) {
if ( forward[node] == 2 ) {
/* 'node' is indistinguishable from 'enode'.*/
/* merge them into a new supernode. */
qsize[enode] += qsize[node];
qsize[node] = 0;
marker[node] = maxint;
forward[node] = -enode;
backward[node] = -maxint;
} else {
/* 'node' is outmacthed by 'enode' */
if (backward[node]==0) backward[node] = -maxint;
};
}; /* end of -- if ( backward[node] == 0 ) -- */
}; /* end of -- if ( marker[node] < *tag ) -- */
}; /* end of -- if ( qsize[node] != 0 ) -- */
}; /* end of -- if ( node != enode ) -- */
}; /* end of -- for ( i = istart; -- */
goto n2100;
n1500:
/* for each 'enode' in the 'qx' list, do the following. */
enode = qxhead;
iq2 = 0;
n1600: if ( enode <= 0 ) goto n2300;
if ( backward[enode] != 0 ) goto n2200;
(*tag)++;
deg = deg0;
/*for each unmarked nabor of 'enode', do the following.*/
istart = xadj[enode];
istop = xadj[enode+1] - 1;
for ( i = istart; i <= istop; i++ ) {
nabor = adjncy[i];
if ( nabor == 0 ) break;
if ( marker[nabor] < *tag ) {
marker[nabor] = *tag;
link = nabor;
if ( forward[nabor] >= 0 )
/*if uneliminated, include it in deg count.*/
deg += qsize[nabor];
else {
n1700:
/* if eliminated, include unmarked nodes in this*/
/* element into the degree count. */
jstart = xadj[link];
jstop = xadj[link+1] - 1;
for ( j = jstart; j <= jstop; j++ ) {
node = adjncy[j];
link = -node;
if ( node < 0 ) goto n1700;
if ( node == 0 ) break;
if ( marker[node] < *tag ) {
marker[node] = *tag;
deg += qsize[node];
};
}; /* end of -- for ( j = jstart; -- */
}; /* end of -- if ( forward[nabor] >= 0 ) -- */
}; /* end of -- if ( marker[nabor] < *tag ) -- */
}; /* end of -- for ( i = istart; -- */
n2100:
/* update external degree of 'enode' in degree structure, */
/* and '*mdeg' if necessary. */
deg = deg - qsize[enode] + 1;
fnode = head[deg];
forward[enode] = fnode;
backward[enode] = -deg;
if ( fnode > 0 ) backward[fnode] = enode;
head[deg] = enode;
if ( deg < *mdeg ) *mdeg = deg;
n2200:
/* get next enode in current element. */
enode = list[enode];
if ( iq2 == 1 ) goto n900;
goto n1600;
n2300:
/* get next element in the list. */
*tag = mtag;
element = list[element];
goto n100;
}

View File

@ -0,0 +1,402 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mpmetis.c
*
* This file contains the top level routines for the multilevel recursive
* bisection algorithm PMETIS.
*
* Started 7/24/97
* George
*
* $Id: mpmetis.c,v 1.1 2003/07/16 15:55:12 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point for PWMETIS that accepts exact weights
* for the target partitions
**************************************************************************/
void METIS_mCPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
int *options, int *edgecut, idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = McPMETIS_CTYPE;
ctrl.IType = McPMETIS_ITYPE;
ctrl.RType = McPMETIS_RTYPE;
ctrl.dbglvl = McPMETIS_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_PMETIS;
ctrl.CoarsenTo = 100;
ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
*edgecut = MCMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, 1.000, 0);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
if (*numflag == 1)
Change2FNumbering(*nvtxs, xadj, adjncy, part);
}
/*************************************************************************
* This function is the entry point for PWMETIS that accepts exact weights
* for the target partitions
**************************************************************************/
void METIS_mCHPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
float *ubvec, int *options, int *edgecut, idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
float *myubvec;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = PMETIS_CTYPE;
ctrl.IType = PMETIS_ITYPE;
ctrl.RType = PMETIS_RTYPE;
ctrl.dbglvl = PMETIS_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_PMETIS;
ctrl.CoarsenTo = 100;
ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
myubvec = fmalloc(*ncon, "PWMETIS: mytpwgts");
scopy(*ncon, ubvec, myubvec);
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
*edgecut = MCHMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, myubvec, 0);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
GKfree(&myubvec, LTERM);
if (*numflag == 1)
Change2FNumbering(*nvtxs, xadj, adjncy, part);
}
/*************************************************************************
* This function is the entry point for PWMETIS that accepts exact weights
* for the target partitions
**************************************************************************/
void METIS_mCPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
float *nvwgt, idxtype *adjwgt, int *nparts, int *options, int *edgecut, idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
SetUpGraph2(&graph, *nvtxs, *ncon, xadj, adjncy, nvwgt, adjwgt);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = PMETIS_CTYPE;
ctrl.IType = PMETIS_ITYPE;
ctrl.RType = PMETIS_RTYPE;
ctrl.dbglvl = PMETIS_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_PMETIS;
ctrl.CoarsenTo = 100;
ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
*edgecut = MCMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, 1.000, 0);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
}
/*************************************************************************
* This function is the entry point for PWMETIS that accepts exact weights
* for the target partitions
**************************************************************************/
void METIS_mCHPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
float *nvwgt, idxtype *adjwgt, int *nparts, float *ubvec, int *options, int *edgecut,
idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
float *myubvec;
SetUpGraph2(&graph, *nvtxs, *ncon, xadj, adjncy, nvwgt, adjwgt);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = PMETIS_CTYPE;
ctrl.IType = PMETIS_ITYPE;
ctrl.RType = PMETIS_RTYPE;
ctrl.dbglvl = PMETIS_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_PMETIS;
ctrl.CoarsenTo = 100;
ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
myubvec = fmalloc(*ncon, "PWMETIS: mytpwgts");
scopy(*ncon, ubvec, myubvec);
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
*edgecut = MCHMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, myubvec, 0);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
GKfree(&myubvec, LTERM);
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
int MCMlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part,
float ubfactor, int fpart)
{
int i, j, nvtxs, ncon, cut;
idxtype *label, *where;
GraphType lgraph, rgraph;
float tpwgts[2];
nvtxs = graph->nvtxs;
if (nvtxs == 0) {
printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n");
return 0;
}
/* Determine the weights of the partitions */
tpwgts[0] = 1.0*(nparts>>1)/(1.0*nparts);
tpwgts[1] = 1.0 - tpwgts[0];
MCMlevelEdgeBisection(ctrl, graph, tpwgts, ubfactor);
cut = graph->mincut;
label = graph->label;
where = graph->where;
for (i=0; i<nvtxs; i++)
part[label[i]] = where[i] + fpart;
if (nparts > 2)
SplitGraphPart(ctrl, graph, &lgraph, &rgraph);
/* Free the memory of the top level graph */
GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->label, LTERM);
/* Do the recursive call */
if (nparts > 3) {
cut += MCMlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, ubfactor, fpart);
cut += MCMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, ubfactor, fpart+nparts/2);
}
else if (nparts == 3) {
cut += MCMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, ubfactor, fpart+nparts/2);
GKfree(&lgraph.gdata, &lgraph.nvwgt, &lgraph.label, LTERM);
}
return cut;
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
int MCHMlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part,
float *ubvec, int fpart)
{
int i, j, nvtxs, ncon, cut;
idxtype *label, *where;
GraphType lgraph, rgraph;
float tpwgts[2], *npwgts, *lubvec, *rubvec;
lubvec = rubvec = NULL;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
if (nvtxs == 0) {
printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n");
return 0;
}
/* Determine the weights of the partitions */
tpwgts[0] = 1.0*(nparts>>1)/(1.0*nparts);
tpwgts[1] = 1.0 - tpwgts[0];
/* For now, relax at the coarsest level only */
if (nparts == 2)
MCHMlevelEdgeBisection(ctrl, graph, tpwgts, ubvec);
else
MCMlevelEdgeBisection(ctrl, graph, tpwgts, 1.000);
cut = graph->mincut;
label = graph->label;
where = graph->where;
for (i=0; i<nvtxs; i++)
part[label[i]] = where[i] + fpart;
if (nparts > 2) {
/* Adjust the ubvecs before the split */
npwgts = graph->npwgts;
lubvec = fmalloc(ncon, "MCHMlevelRecursiveBisection");
rubvec = fmalloc(ncon, "MCHMlevelRecursiveBisection");
for (i=0; i<ncon; i++) {
lubvec[i] = ubvec[i]*tpwgts[0]/npwgts[i];
lubvec[i] = amax(lubvec[i], 1.01);
rubvec[i] = ubvec[i]*tpwgts[1]/npwgts[ncon+i];
rubvec[i] = amax(rubvec[i], 1.01);
}
SplitGraphPart(ctrl, graph, &lgraph, &rgraph);
}
/* Free the memory of the top level graph */
GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->label, LTERM);
/* Do the recursive call */
if (nparts > 3) {
cut += MCHMlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, lubvec, fpart);
cut += MCHMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, rubvec, fpart+nparts/2);
}
else if (nparts == 3) {
cut += MCHMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, rubvec, fpart+nparts/2);
GKfree(&lgraph.gdata, &lgraph.nvwgt, &lgraph.label, LTERM);
}
GKfree(&lubvec, &rubvec, LTERM);
return cut;
}
/*************************************************************************
* This function performs multilevel bisection
**************************************************************************/
void MCMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
{
GraphType *cgraph;
cgraph = MCCoarsen2Way(ctrl, graph);
MocInit2WayPartition(ctrl, cgraph, tpwgts, ubfactor);
MocRefine2Way(ctrl, graph, cgraph, tpwgts, ubfactor);
}
/*************************************************************************
* This function performs multilevel bisection
**************************************************************************/
void MCHMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
{
int i;
GraphType *cgraph;
/*
for (i=0; i<graph->ncon; i++)
printf("%.4f ", ubvec[i]);
printf("\n");
*/
cgraph = MCCoarsen2Way(ctrl, graph);
MocInit2WayPartition2(ctrl, cgraph, tpwgts, ubvec);
MocRefine2Way2(ctrl, graph, cgraph, tpwgts, ubvec);
}

View File

@ -0,0 +1,219 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* refine.c
*
* This file contains the driving routines for multilevel refinement
*
* Started 7/24/97
* George
*
* $Id: mrefine.c,v 1.1 2003/07/24 18:39:10 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of refinement
**************************************************************************/
void MocRefine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, float ubfactor)
{
int i;
float tubvec[MAXNCON];
for (i=0; i<graph->ncon; i++)
tubvec[i] = 1.0;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
/* Compute the parameters of the coarsest graph */
MocCompute2WayPartitionParams(ctrl, graph);
for (;;) {
ASSERT(CheckBnd(graph));
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
switch (ctrl->RType) {
case RTYPE_FM:
MocBalance2Way(ctrl, graph, tpwgts, 1.03);
MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8);
break;
case 2:
MocBalance2Way(ctrl, graph, tpwgts, 1.03);
MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, tubvec, 8);
break;
default:
errexit("Unknown refinement type: %d\n", ctrl->RType);
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
if (graph == orggraph)
break;
graph = graph->finer;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
MocProject2WayPartition(ctrl, graph);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
}
MocBalance2Way(ctrl, graph, tpwgts, 1.01);
MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
}
/*************************************************************************
* This function allocates memory for 2-way edge refinement
**************************************************************************/
void MocAllocate2WayPartitionMemory(CtrlType *ctrl, GraphType *graph)
{
int nvtxs, ncon;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
graph->rdata = idxmalloc(5*nvtxs, "Allocate2WayPartitionMemory: rdata");
graph->where = graph->rdata;
graph->id = graph->rdata + nvtxs;
graph->ed = graph->rdata + 2*nvtxs;
graph->bndptr = graph->rdata + 3*nvtxs;
graph->bndind = graph->rdata + 4*nvtxs;
graph->npwgts = fmalloc(2*ncon, "npwgts");
}
/*************************************************************************
* This function computes the initial id/ed
**************************************************************************/
void MocCompute2WayPartitionParams(CtrlType *ctrl, GraphType *graph)
{
int i, j, k, l, nvtxs, ncon, nbnd, mincut;
idxtype *xadj, *adjncy, *adjwgt;
float *nvwgt, *npwgts;
idxtype *id, *ed, *where;
idxtype *bndptr, *bndind;
int me, other;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
npwgts = sset(2*ncon, 0.0, graph->npwgts);
id = idxset(nvtxs, 0, graph->id);
ed = idxset(nvtxs, 0, graph->ed);
bndptr = idxset(nvtxs, -1, graph->bndptr);
bndind = graph->bndind;
/*------------------------------------------------------------
/ Compute now the id/ed degrees
/------------------------------------------------------------*/
nbnd = mincut = 0;
for (i=0; i<nvtxs; i++) {
ASSERT(where[i] >= 0 && where[i] <= 1);
me = where[i];
saxpy(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1);
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (me == where[adjncy[j]])
id[i] += adjwgt[j];
else
ed[i] += adjwgt[j];
}
if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
mincut += ed[i];
bndptr[i] = nbnd;
bndind[nbnd++] = i;
}
}
graph->mincut = mincut/2;
graph->nbnd = nbnd;
}
/*************************************************************************
* This function projects a partition, and at the same time computes the
* parameters for refinement.
**************************************************************************/
void MocProject2WayPartition(CtrlType *ctrl, GraphType *graph)
{
int i, j, k, nvtxs, nbnd, me;
idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
idxtype *cmap, *where, *id, *ed, *bndptr, *bndind;
idxtype *cwhere, *cid, *ced, *cbndptr;
GraphType *cgraph;
cgraph = graph->coarser;
cwhere = cgraph->where;
cid = cgraph->id;
ced = cgraph->ed;
cbndptr = cgraph->bndptr;
nvtxs = graph->nvtxs;
cmap = graph->cmap;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
MocAllocate2WayPartitionMemory(ctrl, graph);
where = graph->where;
id = idxset(nvtxs, 0, graph->id);
ed = idxset(nvtxs, 0, graph->ed);
bndptr = idxset(nvtxs, -1, graph->bndptr);
bndind = graph->bndind;
/* Go through and project partition and compute id/ed for the nodes */
for (i=0; i<nvtxs; i++) {
k = cmap[i];
where[i] = cwhere[k];
cmap[i] = cbndptr[k];
}
for (nbnd=0, i=0; i<nvtxs; i++) {
me = where[i];
id[i] = adjwgtsum[i];
if (xadj[i] == xadj[i+1]) {
bndptr[i] = nbnd;
bndind[nbnd++] = i;
}
else {
if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (me != where[adjncy[j]])
ed[i] += adjwgt[j];
}
id[i] -= ed[i];
if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
bndptr[i] = nbnd;
bndind[nbnd++] = i;
}
}
}
}
graph->mincut = cgraph->mincut;
graph->nbnd = nbnd;
scopy(2*graph->ncon, cgraph->npwgts, graph->npwgts);
FreeGraph(graph->coarser);
graph->coarser = NULL;
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* mrefine2.c
*
* This file contains the driving routines for multilevel refinement
*
* Started 7/24/97
* George
*
* $Id: mrefine2.c,v 1.1 2003/07/16 15:55:12 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of refinement
**************************************************************************/
void MocRefine2Way2(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts,
float *ubvec)
{
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
/* Compute the parameters of the coarsest graph */
MocCompute2WayPartitionParams(ctrl, graph);
for (;;) {
ASSERT(CheckBnd(graph));
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
switch (ctrl->RType) {
case RTYPE_FM:
MocBalance2Way2(ctrl, graph, tpwgts, ubvec);
MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 8);
break;
default:
errexit("Unknown refinement type: %d\n", ctrl->RType);
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
if (graph == orggraph)
break;
graph = graph->finer;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
MocProject2WayPartition(ctrl, graph);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
}

View File

@ -0,0 +1,101 @@
/*
* mutil.c
*
* This file contains various utility functions for the MOC portion of the
* code
*
* Started 2/15/98
* George
*
* $Id: mutil.c,v 1.1 2003/07/16 15:55:13 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function checks if the vertex weights of two vertices are below
* a given set of values
**************************************************************************/
int AreAllVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit)
{
int i;
for (i=0; i<ncon; i++)
if (alpha*vwgt1[i] + beta*vwgt2[i] > limit)
return 0;
return 1;
}
/*************************************************************************
* This function checks if the vertex weights of two vertices are below
* a given set of values
**************************************************************************/
int AreAnyVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit)
{
int i;
for (i=0; i<ncon; i++)
if (alpha*vwgt1[i] + beta*vwgt2[i] < limit)
return 1;
return 0;
}
/*************************************************************************
* This function checks if the vertex weights of two vertices are above
* a given set of values
**************************************************************************/
int AreAllVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit)
{
int i;
for (i=0; i<ncon; i++)
if (alpha*vwgt1[i] + beta*vwgt2[i] < limit)
return 0;
return 1;
}
/*************************************************************************
* This function computes the load imbalance over all the constrains
* For now assume that we just want balanced partitionings
**************************************************************************/
float ComputeLoadImbalance(int ncon, int nparts, float *npwgts, float *tpwgts)
{
int i, j;
float max, lb=0.0;
for (i=0; i<ncon; i++) {
max = 0.0;
for (j=0; j<nparts; j++) {
if (npwgts[j*ncon+i] > max)
max = npwgts[j*ncon+i];
}
if (max*nparts > lb)
lb = max*nparts;
}
return lb;
}
/*************************************************************************
* This function checks if the vertex weights of two vertices are below
* a given set of values
**************************************************************************/
int AreAllBelow(int ncon, float *v1, float *v2)
{
int i;
for (i=0; i<ncon; i++)
if (v1[i] > v2[i])
return 0;
return 1;
}

View File

@ -0,0 +1,547 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* myqsort.c
*
* This file contains a fast idxtype increasing qsort algorithm.
* Addopted from TeX
*
* Started 10/18/96
* George
*
* $Id: myqsort.c,v 1.1 2003/07/16 15:55:13 karypis Exp $
*/
#include <metis.h> /* only for type declarations */
#define THRESH 1 /* threshold for insertion */
#define MTHRESH 6 /* threshold for median */
static void siqst(idxtype *, idxtype *);
static void iiqst(int *, int *);
static void keyiqst(KeyValueType *, KeyValueType *);
static void keyvaliqst(KeyValueType *, KeyValueType *);
/*************************************************************************
* Entry point of idxtype increasing sort
**************************************************************************/
void iidxsort(int n, idxtype *base)
{
register idxtype *i;
register idxtype *j;
register idxtype *lo;
register idxtype *hi;
register idxtype *min;
register idxtype c;
idxtype *max;
if (n <= 1)
return;
max = base + n;
if (n >= THRESH) {
siqst(base, max);
hi = base + THRESH;
}
else
hi = max;
for (j = lo = base; lo++ < hi;) {
if (*j > *lo)
j = lo;
}
if (j != base) { /* swap j into place */
c = *base;
*base = *j;
*j = c;
}
for (min = base; (hi = min += 1) < max;) {
while (*(--hi) > *min);
if ((hi += 1) != min) {
for (lo = min + 1; --lo >= min;) {
c = *lo;
for (i = j = lo; (j -= 1) >= hi; i = j)
*i = *j;
*i = c;
}
}
}
}
static void siqst(idxtype *base, idxtype *max)
{
register idxtype *i;
register idxtype *j;
register idxtype *jj;
register idxtype *mid;
register int ii;
register idxtype c;
idxtype *tmp;
int lo;
int hi;
lo = max - base; /* number of elements as idxtype */
do {
mid = base + ((unsigned) lo>>1);
if (lo >= MTHRESH) {
j = (*base > *mid ? base : mid);
tmp = max - 1;
if (*j > *tmp) {
j = (j == base ? mid : base); /* switch to first loser */
if (*j < *tmp)
j = tmp;
}
if (j != mid) { /* SWAP */
c = *mid;
*mid = *j;
*j = c;
}
}
/* Semi-standard quicksort partitioning/swapping */
for (i = base, j = max - 1;;) {
while (i < mid && *i <= *mid)
i++;
while (j > mid) {
if (*mid <= *j) {
j--;
continue;
}
tmp = i + 1; /* value of i after swap */
if (i == mid) /* j <-> mid, new mid is j */
mid = jj = j;
else /* i <-> j */
jj = j--;
goto swap;
}
if (i == mid)
break;
else { /* i <-> mid, new mid is i */
jj = mid;
tmp = mid = i; /* value of i after swap */
j--;
}
swap:
c = *i;
*i = *jj;
*jj = c;
i = tmp;
}
i = (j = mid) + 1;
if ((lo = j - base) <= (hi = max - i)) {
if (lo >= THRESH)
siqst(base, j);
base = i;
lo = hi;
}
else {
if (hi >= THRESH)
siqst(i, max);
max = j;
}
} while (lo >= THRESH);
}
/*************************************************************************
* Entry point of int increasing sort
**************************************************************************/
void iintsort(int n, int *base)
{
register int *i;
register int *j;
register int *lo;
register int *hi;
register int *min;
register int c;
int *max;
if (n <= 1)
return;
max = base + n;
if (n >= THRESH) {
iiqst(base, max);
hi = base + THRESH;
}
else
hi = max;
for (j = lo = base; lo++ < hi;) {
if (*j > *lo)
j = lo;
}
if (j != base) { /* swap j into place */
c = *base;
*base = *j;
*j = c;
}
for (min = base; (hi = min += 1) < max;) {
while (*(--hi) > *min);
if ((hi += 1) != min) {
for (lo = min + 1; --lo >= min;) {
c = *lo;
for (i = j = lo; (j -= 1) >= hi; i = j)
*i = *j;
*i = c;
}
}
}
}
static void iiqst(int *base, int *max)
{
register int *i;
register int *j;
register int *jj;
register int *mid;
register int ii;
register int c;
int *tmp;
int lo;
int hi;
lo = max - base; /* number of elements as ints */
do {
mid = base + ((unsigned) lo>>1);
if (lo >= MTHRESH) {
j = (*base > *mid ? base : mid);
tmp = max - 1;
if (*j > *tmp) {
j = (j == base ? mid : base); /* switch to first loser */
if (*j < *tmp)
j = tmp;
}
if (j != mid) { /* SWAP */
c = *mid;
*mid = *j;
*j = c;
}
}
/* Semi-standard quicksort partitioning/swapping */
for (i = base, j = max - 1;;) {
while (i < mid && *i <= *mid)
i++;
while (j > mid) {
if (*mid <= *j) {
j--;
continue;
}
tmp = i + 1; /* value of i after swap */
if (i == mid) /* j <-> mid, new mid is j */
mid = jj = j;
else /* i <-> j */
jj = j--;
goto swap;
}
if (i == mid)
break;
else { /* i <-> mid, new mid is i */
jj = mid;
tmp = mid = i; /* value of i after swap */
j--;
}
swap:
c = *i;
*i = *jj;
*jj = c;
i = tmp;
}
i = (j = mid) + 1;
if ((lo = j - base) <= (hi = max - i)) {
if (lo >= THRESH)
iiqst(base, j);
base = i;
lo = hi;
}
else {
if (hi >= THRESH)
iiqst(i, max);
max = j;
}
} while (lo >= THRESH);
}
/*************************************************************************
* Entry point of KeyVal increasing sort, ONLY key part
**************************************************************************/
void ikeysort(int n, KeyValueType *base)
{
register KeyValueType *i;
register KeyValueType *j;
register KeyValueType *lo;
register KeyValueType *hi;
register KeyValueType *min;
register KeyValueType c;
KeyValueType *max;
if (n <= 1)
return;
max = base + n;
if (n >= THRESH) {
keyiqst(base, max);
hi = base + THRESH;
}
else
hi = max;
for (j = lo = base; lo++ < hi;) {
if (j->key > lo->key)
j = lo;
}
if (j != base) { /* swap j into place */
c = *base;
*base = *j;
*j = c;
}
for (min = base; (hi = min += 1) < max;) {
while ((--hi)->key > min->key);
if ((hi += 1) != min) {
for (lo = min + 1; --lo >= min;) {
c = *lo;
for (i = j = lo; (j -= 1) >= hi; i = j)
*i = *j;
*i = c;
}
}
}
/* Sanity check */
{
int i;
for (i=0; i<n-1; i++)
if (base[i].key > base[i+1].key)
printf("Something went wrong!\n");
}
}
static void keyiqst(KeyValueType *base, KeyValueType *max)
{
register KeyValueType *i;
register KeyValueType *j;
register KeyValueType *jj;
register KeyValueType *mid;
register KeyValueType c;
KeyValueType *tmp;
int lo;
int hi;
lo = (max - base)>>1; /* number of elements as KeyValueType */
do {
mid = base + ((unsigned) lo>>1);
if (lo >= MTHRESH) {
j = (base->key > mid->key ? base : mid);
tmp = max - 1;
if (j->key > tmp->key) {
j = (j == base ? mid : base); /* switch to first loser */
if (j->key < tmp->key)
j = tmp;
}
if (j != mid) { /* SWAP */
c = *mid;
*mid = *j;
*j = c;
}
}
/* Semi-standard quicksort partitioning/swapping */
for (i = base, j = max - 1;;) {
while (i < mid && i->key <= mid->key)
i++;
while (j > mid) {
if (mid->key <= j->key) {
j--;
continue;
}
tmp = i + 1; /* value of i after swap */
if (i == mid) /* j <-> mid, new mid is j */
mid = jj = j;
else /* i <-> j */
jj = j--;
goto swap;
}
if (i == mid)
break;
else { /* i <-> mid, new mid is i */
jj = mid;
tmp = mid = i; /* value of i after swap */
j--;
}
swap:
c = *i;
*i = *jj;
*jj = c;
i = tmp;
}
i = (j = mid) + 1;
if ((lo = (j - base)>>1) <= (hi = (max - i)>>1)) {
if (lo >= THRESH)
keyiqst(base, j);
base = i;
lo = hi;
}
else {
if (hi >= THRESH)
keyiqst(i, max);
max = j;
}
} while (lo >= THRESH);
}
/*************************************************************************
* Entry point of KeyVal increasing sort, BOTH key and val part
**************************************************************************/
void ikeyvalsort(int n, KeyValueType *base)
{
register KeyValueType *i;
register KeyValueType *j;
register KeyValueType *lo;
register KeyValueType *hi;
register KeyValueType *min;
register KeyValueType c;
KeyValueType *max;
if (n <= 1)
return;
max = base + n;
if (n >= THRESH) {
keyvaliqst(base, max);
hi = base + THRESH;
}
else
hi = max;
for (j = lo = base; lo++ < hi;) {
if ((j->key > lo->key) || (j->key == lo->key && j->val > lo->val))
j = lo;
}
if (j != base) { /* swap j into place */
c = *base;
*base = *j;
*j = c;
}
for (min = base; (hi = min += 1) < max;) {
while ((--hi)->key > min->key || (hi->key == min->key && hi->val > min->val));
if ((hi += 1) != min) {
for (lo = min + 1; --lo >= min;) {
c = *lo;
for (i = j = lo; (j -= 1) >= hi; i = j)
*i = *j;
*i = c;
}
}
}
}
static void keyvaliqst(KeyValueType *base, KeyValueType *max)
{
register KeyValueType *i;
register KeyValueType *j;
register KeyValueType *jj;
register KeyValueType *mid;
register KeyValueType c;
KeyValueType *tmp;
int lo;
int hi;
lo = (max - base)>>1; /* number of elements as KeyValueType */
do {
mid = base + ((unsigned) lo>>1);
if (lo >= MTHRESH) {
j = (base->key > mid->key || (base->key == mid->key && base->val > mid->val) ? base : mid);
tmp = max - 1;
if (j->key > tmp->key || (j->key == tmp->key && j->val > tmp->val)) {
j = (j == base ? mid : base); /* switch to first loser */
if (j->key < tmp->key || (j->key == tmp->key && j->val < tmp->val))
j = tmp;
}
if (j != mid) { /* SWAP */
c = *mid;
*mid = *j;
*j = c;
}
}
/* Semi-standard quicksort partitioning/swapping */
for (i = base, j = max - 1;;) {
while (i < mid && (i->key < mid->key || (i->key == mid->key && i->val <= mid->val)))
i++;
while (j > mid) {
if (mid->key < j->key || (mid->key == j->key && mid->val <= j->val)) {
j--;
continue;
}
tmp = i + 1; /* value of i after swap */
if (i == mid) /* j <-> mid, new mid is j */
mid = jj = j;
else /* i <-> j */
jj = j--;
goto swap;
}
if (i == mid)
break;
else { /* i <-> mid, new mid is i */
jj = mid;
tmp = mid = i; /* value of i after swap */
j--;
}
swap:
c = *i;
*i = *jj;
*jj = c;
i = tmp;
}
i = (j = mid) + 1;
if ((lo = (j - base)>>1) <= (hi = (max - i)>>1)) {
if (lo >= THRESH)
keyvaliqst(base, j);
base = i;
lo = hi;
}
else {
if (hi >= THRESH)
keyvaliqst(i, max);
max = j;
}
} while (lo >= THRESH);
}

View File

@ -0,0 +1,764 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* ometis.c
*
* This file contains the top level routines for the multilevel recursive
* bisection algorithm PMETIS.
*
* Started 7/24/97
* George
*
* $Id: ometis.c,v 1.2 2003/07/31 06:14:01 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point for OEMETIS
**************************************************************************/
void METIS_EdgeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options,
idxtype *perm, idxtype *iperm)
{
int i, j;
GraphType graph;
CtrlType ctrl;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
SetUpGraph(&graph, OP_OEMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = OEMETIS_CTYPE;
ctrl.IType = OEMETIS_ITYPE;
ctrl.RType = OEMETIS_RTYPE;
ctrl.dbglvl = OEMETIS_DBGLVL;
}
else {
ctrl.CType = options[OPTION_CTYPE];
ctrl.IType = options[OPTION_ITYPE];
ctrl.RType = options[OPTION_RTYPE];
ctrl.dbglvl = options[OPTION_DBGLVL];
}
ctrl.oflags = 0;
ctrl.pfactor = -1;
ctrl.nseps = 1;
ctrl.optype = OP_OEMETIS;
ctrl.CoarsenTo = 20;
ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo);
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, 2);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, *nvtxs);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
for (i=0; i<*nvtxs; i++)
perm[iperm[i]] = i;
FreeWorkSpace(&ctrl, &graph);
if (*numflag == 1)
Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm);
}
/*************************************************************************
* This function is the entry point for ONCMETIS
**************************************************************************/
void METIS_NodeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options,
idxtype *perm, idxtype *iperm)
{
int i, ii, j, l, wflag, nflag;
GraphType graph;
CtrlType ctrl;
idxtype *cptr, *cind, *piperm;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = ONMETIS_CTYPE;
ctrl.IType = ONMETIS_ITYPE;
ctrl.RType = ONMETIS_RTYPE;
ctrl.dbglvl = ONMETIS_DBGLVL;
ctrl.oflags = ONMETIS_OFLAGS;
ctrl.pfactor = ONMETIS_PFACTOR;
ctrl.nseps = ONMETIS_NSEPS;
}
else {
ctrl.CType = options[OPTION_CTYPE];
ctrl.IType = options[OPTION_ITYPE];
ctrl.RType = options[OPTION_RTYPE];
ctrl.dbglvl = options[OPTION_DBGLVL];
ctrl.oflags = options[OPTION_OFLAGS];
ctrl.pfactor = options[OPTION_PFACTOR];
ctrl.nseps = options[OPTION_NSEPS];
}
if (ctrl.nseps < 1)
ctrl.nseps = 1;
ctrl.optype = OP_ONMETIS;
ctrl.CoarsenTo = 100;
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
InitRandom(-1);
if (ctrl.pfactor > 0) {
/*============================================================
* Prune the dense columns
==============================================================*/
piperm = idxmalloc(*nvtxs, "ONMETIS: piperm");
PruneGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, piperm, (float)(0.1*ctrl.pfactor));
}
else if (ctrl.oflags&OFLAG_COMPRESS) {
/*============================================================
* Compress the graph
==============================================================*/
cptr = idxmalloc(*nvtxs+1, "ONMETIS: cptr");
cind = idxmalloc(*nvtxs, "ONMETIS: cind");
CompressGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, cptr, cind);
if (graph.nvtxs >= COMPRESSION_FRACTION*(*nvtxs)) {
ctrl.oflags--; /* We actually performed no compression */
GKfree(&cptr, &cind, LTERM);
}
else if (2*graph.nvtxs < *nvtxs && ctrl.nseps == 1)
ctrl.nseps = 2;
}
else {
SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0);
}
/*=============================================================
* Do the nested dissection ordering
--=============================================================*/
ctrl.maxvwgt = 1.5*(idxsum(graph.nvtxs, graph.vwgt)/ctrl.CoarsenTo);
AllocateWorkSpace(&ctrl, &graph, 2);
if (ctrl.oflags&OFLAG_CCMP)
MlevelNestedDissectionCC(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs);
else
MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs);
FreeWorkSpace(&ctrl, &graph);
if (ctrl.pfactor > 0) { /* Order any prunned vertices */
if (graph.nvtxs < *nvtxs) {
idxcopy(graph.nvtxs, iperm, perm); /* Use perm as an auxiliary array */
for (i=0; i<graph.nvtxs; i++)
iperm[piperm[i]] = perm[i];
for (i=graph.nvtxs; i<*nvtxs; i++)
iperm[piperm[i]] = i;
}
GKfree(&piperm, LTERM);
}
else if (ctrl.oflags&OFLAG_COMPRESS) { /* Uncompress the ordering */
if (graph.nvtxs < COMPRESSION_FRACTION*(*nvtxs)) {
/* construct perm from iperm */
for (i=0; i<graph.nvtxs; i++)
perm[iperm[i]] = i;
for (l=ii=0; ii<graph.nvtxs; ii++) {
i = perm[ii];
for (j=cptr[i]; j<cptr[i+1]; j++)
iperm[cind[j]] = l++;
}
}
GKfree(&cptr, &cind, LTERM);
}
for (i=0; i<*nvtxs; i++)
perm[iperm[i]] = i;
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
if (*numflag == 1)
Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm);
}
/*************************************************************************
* This function is the entry point for ONWMETIS. It requires weights on the
* vertices. It is for the case that the matrix has been pre-compressed.
**************************************************************************/
void METIS_NodeWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag,
int *options, idxtype *perm, idxtype *iperm)
{
int i, j, tvwgt;
GraphType graph;
CtrlType ctrl;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, NULL, 2);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = ONMETIS_CTYPE;
ctrl.IType = ONMETIS_ITYPE;
ctrl.RType = ONMETIS_RTYPE;
ctrl.dbglvl = ONMETIS_DBGLVL;
}
else {
ctrl.CType = options[OPTION_CTYPE];
ctrl.IType = options[OPTION_ITYPE];
ctrl.RType = options[OPTION_RTYPE];
ctrl.dbglvl = options[OPTION_DBGLVL];
}
ctrl.oflags = OFLAG_COMPRESS;
ctrl.pfactor = 0;
ctrl.nseps = 2;
ctrl.optype = OP_ONMETIS;
ctrl.CoarsenTo = 100;
ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo);
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, 2);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, *nvtxs);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
for (i=0; i<*nvtxs; i++)
perm[iperm[i]] = i;
FreeWorkSpace(&ctrl, &graph);
if (*numflag == 1)
Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm);
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
void MlevelNestedDissection(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx)
{
int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2];
idxtype *label, *bndind;
GraphType lgraph, rgraph;
nvtxs = graph->nvtxs;
/* Determine the weights of the partitions */
tvwgt = idxsum(nvtxs, graph->vwgt);
tpwgts2[0] = tvwgt/2;
tpwgts2[1] = tvwgt-tpwgts2[0];
switch (ctrl->optype) {
case OP_OEMETIS:
MlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr));
ConstructMinCoverSeparator(ctrl, graph, ubfactor);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr));
break;
case OP_ONMETIS:
MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor);
IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));
break;
}
/* Order the nodes in the separator */
nbnd = graph->nbnd;
bndind = graph->bndind;
label = graph->label;
for (i=0; i<nbnd; i++)
order[label[bndind[i]]] = --lastvtx;
SplitGraphOrder(ctrl, graph, &lgraph, &rgraph);
/* Free the memory of the top level graph */
GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM);
if (rgraph.nvtxs > MMDSWITCH)
MlevelNestedDissection(ctrl, &rgraph, order, ubfactor, lastvtx);
else {
MMDOrder(ctrl, &rgraph, order, lastvtx);
GKfree(&rgraph.gdata, &rgraph.rdata, &rgraph.label, LTERM);
}
if (lgraph.nvtxs > MMDSWITCH)
MlevelNestedDissection(ctrl, &lgraph, order, ubfactor, lastvtx-rgraph.nvtxs);
else {
MMDOrder(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs);
GKfree(&lgraph.gdata, &lgraph.rdata, &lgraph.label, LTERM);
}
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
void MlevelNestedDissectionCC(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx)
{
int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2], nsgraphs, ncmps, rnvtxs;
idxtype *label, *bndind;
idxtype *cptr, *cind;
GraphType *sgraphs;
nvtxs = graph->nvtxs;
/* Determine the weights of the partitions */
tvwgt = idxsum(nvtxs, graph->vwgt);
tpwgts2[0] = tvwgt/2;
tpwgts2[1] = tvwgt-tpwgts2[0];
MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor);
IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));
/* Order the nodes in the separator */
nbnd = graph->nbnd;
bndind = graph->bndind;
label = graph->label;
for (i=0; i<nbnd; i++)
order[label[bndind[i]]] = --lastvtx;
cptr = idxmalloc(nvtxs+1, "MlevelNestedDissectionCC: cptr");
cind = idxmalloc(nvtxs, "MlevelNestedDissectionCC: cind");
ncmps = FindComponents(ctrl, graph, cptr, cind);
/*
if (ncmps > 2)
printf("[%5d] has %3d components\n", nvtxs, ncmps);
*/
sgraphs = (GraphType *)GKmalloc(ncmps*sizeof(GraphType), "MlevelNestedDissectionCC: sgraphs");
nsgraphs = SplitGraphOrderCC(ctrl, graph, sgraphs, ncmps, cptr, cind);
GKfree(&cptr, &cind, LTERM);
/* Free the memory of the top level graph */
GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM);
/* Go and process the subgraphs */
for (rnvtxs=i=0; i<nsgraphs; i++) {
if (sgraphs[i].adjwgt == NULL) {
MMDOrder(ctrl, sgraphs+i, order, lastvtx-rnvtxs);
GKfree(&sgraphs[i].gdata, &sgraphs[i].label, LTERM);
}
else {
MlevelNestedDissectionCC(ctrl, sgraphs+i, order, ubfactor, lastvtx-rnvtxs);
}
rnvtxs += sgraphs[i].nvtxs;
}
free(sgraphs);
}
/*************************************************************************
* This function performs multilevel bisection. It performs multiple
* bisections and selects the best.
**************************************************************************/
void MlevelNodeBisectionMultiple(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
{
int i, nvtxs, cnvtxs, mincut, tmp;
GraphType *cgraph;
idxtype *bestwhere;
if (ctrl->nseps == 1 || graph->nvtxs < (ctrl->oflags&OFLAG_COMPRESS ? 1000 : 2000)) {
MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor);
return;
}
nvtxs = graph->nvtxs;
if (ctrl->oflags&OFLAG_COMPRESS) { /* Multiple separators at the original graph */
bestwhere = idxmalloc(nvtxs, "MlevelNodeBisection2: bestwhere");
mincut = nvtxs;
for (i=ctrl->nseps; i>0; i--) {
MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor);
/* printf("%5d ", cgraph->mincut); */
if (graph->mincut < mincut) {
mincut = graph->mincut;
idxcopy(nvtxs, graph->where, bestwhere);
}
GKfree(&graph->rdata, LTERM);
if (mincut == 0)
break;
}
/* printf("[%5d]\n", mincut); */
Allocate2WayNodePartitionMemory(ctrl, graph);
idxcopy(nvtxs, bestwhere, graph->where);
free(bestwhere);
Compute2WayNodePartitionParams(ctrl, graph);
}
else { /* Coarsen it a bit */
ctrl->CoarsenTo = nvtxs-1;
cgraph = Coarsen2Way(ctrl, graph);
cnvtxs = cgraph->nvtxs;
bestwhere = idxmalloc(cnvtxs, "MlevelNodeBisection2: bestwhere");
mincut = nvtxs;
for (i=ctrl->nseps; i>0; i--) {
ctrl->CType += 20; /* This is a hack. Look at coarsen.c */
MlevelNodeBisection(ctrl, cgraph, tpwgts, ubfactor);
/* printf("%5d ", cgraph->mincut); */
if (cgraph->mincut < mincut) {
mincut = cgraph->mincut;
idxcopy(cnvtxs, cgraph->where, bestwhere);
}
GKfree(&cgraph->rdata, LTERM);
if (mincut == 0)
break;
}
/* printf("[%5d]\n", mincut); */
Allocate2WayNodePartitionMemory(ctrl, cgraph);
idxcopy(cnvtxs, bestwhere, cgraph->where);
free(bestwhere);
Compute2WayNodePartitionParams(ctrl, cgraph);
Refine2WayNode(ctrl, graph, cgraph, ubfactor);
}
}
/*************************************************************************
* This function performs multilevel bisection
**************************************************************************/
void MlevelNodeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
{
GraphType *cgraph;
ctrl->CoarsenTo = graph->nvtxs/8;
if (ctrl->CoarsenTo > 100)
ctrl->CoarsenTo = 100;
else if (ctrl->CoarsenTo < 40)
ctrl->CoarsenTo = 40;
ctrl->maxvwgt = 1.5*((tpwgts[0]+tpwgts[1])/ctrl->CoarsenTo);
cgraph = Coarsen2Way(ctrl, graph);
switch (ctrl->IType) {
case IPART_GGPKL:
Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor);
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr));
Compute2WayPartitionParams(ctrl, cgraph);
ConstructSeparator(ctrl, cgraph, ubfactor);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr));
break;
case IPART_GGPKLNODE:
InitSeparator(ctrl, cgraph, ubfactor);
break;
}
Refine2WayNode(ctrl, graph, cgraph, ubfactor);
}
/*************************************************************************
* This function takes a graph and a bisection and splits it into two graphs.
* This function relies on the fact that adjwgt is all equal to 1.
**************************************************************************/
void SplitGraphOrder(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph)
{
int i, ii, j, k, l, istart, iend, mypart, nvtxs, snvtxs[3], snedges[3];
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr, *bndind;
idxtype *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *sadjwgtsum[2], *slabel[2];
idxtype *rename;
idxtype *auxadjncy, *auxadjwgt;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr));
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
label = graph->label;
where = graph->where;
bndptr = graph->bndptr;
bndind = graph->bndind;
ASSERT(bndptr != NULL);
rename = idxwspacemalloc(ctrl, nvtxs);
snvtxs[0] = snvtxs[1] = snvtxs[2] = snedges[0] = snedges[1] = snedges[2] = 0;
for (i=0; i<nvtxs; i++) {
k = where[i];
rename[i] = snvtxs[k]++;
snedges[k] += xadj[i+1]-xadj[i];
}
SetUpSplitGraph(graph, lgraph, snvtxs[0], snedges[0]);
sxadj[0] = lgraph->xadj;
svwgt[0] = lgraph->vwgt;
sadjwgtsum[0] = lgraph->adjwgtsum;
sadjncy[0] = lgraph->adjncy;
sadjwgt[0] = lgraph->adjwgt;
slabel[0] = lgraph->label;
SetUpSplitGraph(graph, rgraph, snvtxs[1], snedges[1]);
sxadj[1] = rgraph->xadj;
svwgt[1] = rgraph->vwgt;
sadjwgtsum[1] = rgraph->adjwgtsum;
sadjncy[1] = rgraph->adjncy;
sadjwgt[1] = rgraph->adjwgt;
slabel[1] = rgraph->label;
/* Go and use bndptr to also mark the boundary nodes in the two partitions */
for (ii=0; ii<graph->nbnd; ii++) {
i = bndind[ii];
for (j=xadj[i]; j<xadj[i+1]; j++)
bndptr[adjncy[j]] = 1;
}
snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;
sxadj[0][0] = sxadj[1][0] = 0;
for (i=0; i<nvtxs; i++) {
if ((mypart = where[i]) == 2)
continue;
istart = xadj[i];
iend = xadj[i+1];
if (bndptr[i] == -1) { /* This is an interior vertex */
auxadjncy = sadjncy[mypart] + snedges[mypart] - istart;
for(j=istart; j<iend; j++)
auxadjncy[j] = adjncy[j];
snedges[mypart] += iend-istart;
}
else {
auxadjncy = sadjncy[mypart];
l = snedges[mypart];
for (j=istart; j<iend; j++) {
k = adjncy[j];
if (where[k] == mypart)
auxadjncy[l++] = k;
}
snedges[mypart] = l;
}
svwgt[mypart][snvtxs[mypart]] = vwgt[i];
sadjwgtsum[mypart][snvtxs[mypart]] = snedges[mypart]-sxadj[mypart][snvtxs[mypart]];
slabel[mypart][snvtxs[mypart]] = label[i];
sxadj[mypart][++snvtxs[mypart]] = snedges[mypart];
}
for (mypart=0; mypart<2; mypart++) {
iend = snedges[mypart];
idxset(iend, 1, sadjwgt[mypart]);
auxadjncy = sadjncy[mypart];
for (i=0; i<iend; i++)
auxadjncy[i] = rename[auxadjncy[i]];
}
lgraph->nvtxs = snvtxs[0];
lgraph->nedges = snedges[0];
rgraph->nvtxs = snvtxs[1];
rgraph->nedges = snedges[1];
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr));
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* This function uses MMD to order the graph. The vertices are numbered
* from lastvtx downwards
**************************************************************************/
void MMDOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx)
{
int i, j, k, nvtxs, nofsub, firstvtx;
idxtype *xadj, *adjncy, *label;
idxtype *perm, *iperm, *head, *qsize, *list, *marker;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
/* Relabel the vertices so that it starts from 1 */
k = xadj[nvtxs];
for (i=0; i<k; i++)
adjncy[i]++;
for (i=0; i<nvtxs+1; i++)
xadj[i]++;
perm = idxmalloc(6*(nvtxs+5), "MMDOrder: perm");
iperm = perm + nvtxs + 5;
head = iperm + nvtxs + 5;
qsize = head + nvtxs + 5;
list = qsize + nvtxs + 5;
marker = list + nvtxs + 5;
genmmd(nvtxs, xadj, adjncy, iperm, perm, 1, head, qsize, list, marker, MAXIDX, &nofsub);
label = graph->label;
firstvtx = lastvtx-nvtxs;
for (i=0; i<nvtxs; i++)
order[label[i]] = firstvtx+iperm[i]-1;
free(perm);
/* Relabel the vertices so that it starts from 0 */
for (i=0; i<nvtxs+1; i++)
xadj[i]--;
k = xadj[nvtxs];
for (i=0; i<k; i++)
adjncy[i]--;
}
/*************************************************************************
* This function takes a graph and a bisection and splits it into two graphs.
* It relies on the fact that adjwgt is all set to 1.
**************************************************************************/
int SplitGraphOrderCC(CtrlType *ctrl, GraphType *graph, GraphType *sgraphs, int ncmps, idxtype *cptr, idxtype *cind)
{
int i, ii, iii, j, k, l, istart, iend, mypart, nvtxs, snvtxs, snedges;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr, *bndind;
idxtype *sxadj, *svwgt, *sadjncy, *sadjwgt, *sadjwgtsum, *slabel;
idxtype *rename;
idxtype *auxadjncy, *auxadjwgt;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr));
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
label = graph->label;
where = graph->where;
bndptr = graph->bndptr;
bndind = graph->bndind;
ASSERT(bndptr != NULL);
/* Go and use bndptr to also mark the boundary nodes in the two partitions */
for (ii=0; ii<graph->nbnd; ii++) {
i = bndind[ii];
for (j=xadj[i]; j<xadj[i+1]; j++)
bndptr[adjncy[j]] = 1;
}
rename = idxwspacemalloc(ctrl, nvtxs);
/* Go and split the graph a component at a time */
for (iii=0; iii<ncmps; iii++) {
RandomPermute(cptr[iii+1]-cptr[iii], cind+cptr[iii], 0);
snvtxs = snedges = 0;
for (j=cptr[iii]; j<cptr[iii+1]; j++) {
i = cind[j];
rename[i] = snvtxs++;
snedges += xadj[i+1]-xadj[i];
}
SetUpSplitGraph(graph, sgraphs+iii, snvtxs, snedges);
sxadj = sgraphs[iii].xadj;
svwgt = sgraphs[iii].vwgt;
sadjwgtsum = sgraphs[iii].adjwgtsum;
sadjncy = sgraphs[iii].adjncy;
sadjwgt = sgraphs[iii].adjwgt;
slabel = sgraphs[iii].label;
snvtxs = snedges = sxadj[0] = 0;
for (ii=cptr[iii]; ii<cptr[iii+1]; ii++) {
i = cind[ii];
istart = xadj[i];
iend = xadj[i+1];
if (bndptr[i] == -1) { /* This is an interior vertex */
auxadjncy = sadjncy + snedges - istart;
auxadjwgt = sadjwgt + snedges - istart;
for(j=istart; j<iend; j++)
auxadjncy[j] = adjncy[j];
snedges += iend-istart;
}
else {
l = snedges;
for (j=istart; j<iend; j++) {
k = adjncy[j];
if (where[k] != 2)
sadjncy[l++] = k;
}
snedges = l;
}
svwgt[snvtxs] = vwgt[i];
sadjwgtsum[snvtxs] = snedges-sxadj[snvtxs];
slabel[snvtxs] = label[i];
sxadj[++snvtxs] = snedges;
}
idxset(snedges, 1, sadjwgt);
for (i=0; i<snedges; i++)
sadjncy[i] = rename[sadjncy[i]];
sgraphs[iii].nvtxs = snvtxs;
sgraphs[iii].nedges = snedges;
sgraphs[iii].ncon = 1;
if (snvtxs < MMDSWITCH)
sgraphs[iii].adjwgt = NULL; /* A marker to call MMD on the driver */
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr));
idxwspacefree(ctrl, nvtxs);
return ncmps;
}

View File

@ -0,0 +1,512 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* parmetis.c
*
* This file contains top level routines that are used by ParMETIS
*
* Started 10/14/97
* George
*
* $Id: parmetis.c,v 1.2 2003/07/24 18:39:11 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point for KMETIS with seed specification
* in options[7]
**************************************************************************/
void METIS_PartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
int *options, int *edgecut, idxtype *part)
{
int i;
float *tpwgts;
tpwgts = fmalloc(*nparts, "KMETIS: tpwgts");
for (i=0; i<*nparts; i++)
tpwgts[i] = 1.0/(1.0*(*nparts));
METIS_WPartGraphKway2(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts,
tpwgts, options, edgecut, part);
free(tpwgts);
}
/*************************************************************************
* This function is the entry point for KWMETIS with seed specification
* in options[7]
**************************************************************************/
void METIS_WPartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
float *tpwgts, int *options, int *edgecut, idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
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 = 20*(*nparts);
ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo);
InitRandom(options[7]);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
*edgecut = MlevelKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.000);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
if (*numflag == 1)
Change2FNumbering(*nvtxs, xadj, adjncy, part);
}
/*************************************************************************
* This function is the entry point for the node ND code for ParMETIS
**************************************************************************/
void METIS_NodeNDP(int nvtxs, idxtype *xadj, idxtype *adjncy, int npes,
int *options, idxtype *perm, idxtype *iperm, idxtype *sizes)
{
int i, ii, j, l, wflag, nflag;
GraphType graph;
CtrlType ctrl;
idxtype *cptr, *cind;
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = ONMETIS_CTYPE;
ctrl.IType = ONMETIS_ITYPE;
ctrl.RType = ONMETIS_RTYPE;
ctrl.dbglvl = ONMETIS_DBGLVL;
ctrl.oflags = ONMETIS_OFLAGS;
ctrl.pfactor = ONMETIS_PFACTOR;
ctrl.nseps = ONMETIS_NSEPS;
}
else {
ctrl.CType = options[OPTION_CTYPE];
ctrl.IType = options[OPTION_ITYPE];
ctrl.RType = options[OPTION_RTYPE];
ctrl.dbglvl = options[OPTION_DBGLVL];
ctrl.oflags = options[OPTION_OFLAGS];
ctrl.pfactor = options[OPTION_PFACTOR];
ctrl.nseps = options[OPTION_NSEPS];
}
if (ctrl.nseps < 1)
ctrl.nseps = 1;
ctrl.optype = OP_ONMETIS;
ctrl.CoarsenTo = 100;
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
InitRandom(-1);
if (ctrl.oflags&OFLAG_COMPRESS) {
/*============================================================
* Compress the graph
==============================================================*/
cptr = idxmalloc(nvtxs+1, "ONMETIS: cptr");
cind = idxmalloc(nvtxs, "ONMETIS: cind");
CompressGraph(&ctrl, &graph, nvtxs, xadj, adjncy, cptr, cind);
if (graph.nvtxs >= COMPRESSION_FRACTION*(nvtxs)) {
ctrl.oflags--; /* We actually performed no compression */
GKfree(&cptr, &cind, LTERM);
}
else if (2*graph.nvtxs < nvtxs && ctrl.nseps == 1)
ctrl.nseps = 2;
}
else {
SetUpGraph(&graph, OP_ONMETIS, nvtxs, 1, xadj, adjncy, NULL, NULL, 0);
}
/*=============================================================
* Do the nested dissection ordering
--=============================================================*/
ctrl.maxvwgt = 1.5*(idxsum(graph.nvtxs, graph.vwgt)/ctrl.CoarsenTo);
AllocateWorkSpace(&ctrl, &graph, 2);
idxset(2*npes-1, 0, sizes);
MlevelNestedDissectionP(&ctrl, &graph, iperm, graph.nvtxs, npes, 0, sizes);
FreeWorkSpace(&ctrl, &graph);
if (ctrl.oflags&OFLAG_COMPRESS) { /* Uncompress the ordering */
if (graph.nvtxs < COMPRESSION_FRACTION*(nvtxs)) {
/* construct perm from iperm */
for (i=0; i<graph.nvtxs; i++)
perm[iperm[i]] = i;
for (l=ii=0; ii<graph.nvtxs; ii++) {
i = perm[ii];
for (j=cptr[i]; j<cptr[i+1]; j++)
iperm[cind[j]] = l++;
}
}
GKfree(&cptr, &cind, LTERM);
}
for (i=0; i<nvtxs; i++)
perm[iperm[i]] = i;
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
void MlevelNestedDissectionP(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx,
int npes, int cpos, idxtype *sizes)
{
int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2];
idxtype *label, *bndind;
GraphType lgraph, rgraph;
float ubfactor;
nvtxs = graph->nvtxs;
if (nvtxs == 0) {
GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM);
return;
}
/* Determine the weights of the partitions */
tvwgt = idxsum(nvtxs, graph->vwgt);
tpwgts2[0] = tvwgt/2;
tpwgts2[1] = tvwgt-tpwgts2[0];
if (cpos >= npes-1)
ubfactor = ORDER_UNBALANCE_FRACTION;
else
ubfactor = 1.05;
MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor);
IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));
if (cpos < npes-1) {
sizes[2*npes-2-cpos] = graph->pwgts[2];
sizes[2*npes-2-(2*cpos+1)] = graph->pwgts[1];
sizes[2*npes-2-(2*cpos+2)] = graph->pwgts[0];
}
/* Order the nodes in the separator */
nbnd = graph->nbnd;
bndind = graph->bndind;
label = graph->label;
for (i=0; i<nbnd; i++)
order[label[bndind[i]]] = --lastvtx;
SplitGraphOrder(ctrl, graph, &lgraph, &rgraph);
/* Free the memory of the top level graph */
GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM);
if (rgraph.nvtxs > MMDSWITCH || 2*cpos+1 < npes-1)
MlevelNestedDissectionP(ctrl, &rgraph, order, lastvtx, npes, 2*cpos+1, sizes);
else {
MMDOrder(ctrl, &rgraph, order, lastvtx);
GKfree(&rgraph.gdata, &rgraph.rdata, &rgraph.label, LTERM);
}
if (lgraph.nvtxs > MMDSWITCH || 2*cpos+2 < npes-1)
MlevelNestedDissectionP(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs, npes, 2*cpos+2, sizes);
else {
MMDOrder(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs);
GKfree(&lgraph.gdata, &lgraph.rdata, &lgraph.label, LTERM);
}
}
/*************************************************************************
* This function is the entry point for ONWMETIS. It requires weights on the
* vertices. It is for the case that the matrix has been pre-compressed.
**************************************************************************/
void METIS_NodeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *adjwgt, int *options, int *sepsize, idxtype *part)
{
int i, j, tvwgt, tpwgts[2];
GraphType graph;
CtrlType ctrl;
SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3);
tvwgt = idxsum(*nvtxs, graph.vwgt);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = ONMETIS_CTYPE;
ctrl.IType = ONMETIS_ITYPE;
ctrl.RType = ONMETIS_RTYPE;
ctrl.dbglvl = ONMETIS_DBGLVL;
}
else {
ctrl.CType = options[OPTION_CTYPE];
ctrl.IType = options[OPTION_ITYPE];
ctrl.RType = options[OPTION_RTYPE];
ctrl.dbglvl = options[OPTION_DBGLVL];
}
ctrl.oflags = 0;
ctrl.pfactor = 0;
ctrl.nseps = 1;
ctrl.optype = OP_ONMETIS;
ctrl.CoarsenTo = amin(100, *nvtxs-1);
ctrl.maxvwgt = 1.5*tvwgt/ctrl.CoarsenTo;
InitRandom(options[7]);
AllocateWorkSpace(&ctrl, &graph, 2);
/*============================================================
* Perform the bisection
*============================================================*/
tpwgts[0] = tvwgt/2;
tpwgts[1] = tvwgt-tpwgts[0];
MlevelNodeBisectionMultiple(&ctrl, &graph, tpwgts, 1.05);
*sepsize = graph.pwgts[2];
idxcopy(*nvtxs, graph.where, part);
GKfree(&graph.gdata, &graph.rdata, &graph.label, LTERM);
FreeWorkSpace(&ctrl, &graph);
}
/*************************************************************************
* This function is the entry point for ONWMETIS. It requires weights on the
* vertices. It is for the case that the matrix has been pre-compressed.
**************************************************************************/
void METIS_EdgeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *adjwgt, int *options, int *sepsize, idxtype *part)
{
int i, j, tvwgt, tpwgts[2];
GraphType graph;
CtrlType ctrl;
SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3);
tvwgt = idxsum(*nvtxs, graph.vwgt);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = ONMETIS_CTYPE;
ctrl.IType = ONMETIS_ITYPE;
ctrl.RType = ONMETIS_RTYPE;
ctrl.dbglvl = ONMETIS_DBGLVL;
}
else {
ctrl.CType = options[OPTION_CTYPE];
ctrl.IType = options[OPTION_ITYPE];
ctrl.RType = options[OPTION_RTYPE];
ctrl.dbglvl = options[OPTION_DBGLVL];
}
ctrl.oflags = 0;
ctrl.pfactor = 0;
ctrl.nseps = 1;
ctrl.optype = OP_OEMETIS;
ctrl.CoarsenTo = amin(100, *nvtxs-1);
ctrl.maxvwgt = 1.5*tvwgt/ctrl.CoarsenTo;
InitRandom(options[7]);
AllocateWorkSpace(&ctrl, &graph, 2);
/*============================================================
* Perform the bisection
*============================================================*/
tpwgts[0] = tvwgt/2;
tpwgts[1] = tvwgt-tpwgts[0];
MlevelEdgeBisection(&ctrl, &graph, tpwgts, 1.05);
ConstructMinCoverSeparator(&ctrl, &graph, 1.05);
*sepsize = graph.pwgts[2];
idxcopy(*nvtxs, graph.where, part);
GKfree(&graph.gdata, &graph.rdata, &graph.label, LTERM);
FreeWorkSpace(&ctrl, &graph);
}
/*************************************************************************
* This function is the entry point for PWMETIS that accepts exact weights
* for the target partitions
**************************************************************************/
void METIS_mCPartGraphRecursive2(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
float *tpwgts, int *options, int *edgecut, idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
float *mytpwgts;
float avgwgt;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag);
graph.npwgts = NULL;
mytpwgts = fmalloc(*nparts, "mytpwgts");
scopy(*nparts, tpwgts, mytpwgts);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = McPMETIS_CTYPE;
ctrl.IType = McPMETIS_ITYPE;
ctrl.RType = McPMETIS_RTYPE;
ctrl.dbglvl = McPMETIS_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_PMETIS;
ctrl.CoarsenTo = 100;
ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
InitRandom(options[7]);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
ASSERT(CheckGraph(&graph));
*edgecut = MCMlevelRecursiveBisection2(&ctrl, &graph, *nparts, mytpwgts, part, 1.000, 0);
/*
{
idxtype wgt[2048], minwgt, maxwgt, sumwgt;
printf("nvtxs: %d, nparts: %d, ncon: %d\n", graph.nvtxs, *nparts, *ncon);
for (i=0; i<(*nparts)*(*ncon); i++)
wgt[i] = 0;
for (i=0; i<graph.nvtxs; i++)
for (j=0; j<*ncon; j++)
wgt[part[i]*(*ncon)+j] += vwgt[i*(*ncon)+j];
for (j=0; j<*ncon; j++) {
minwgt = maxwgt = sumwgt = 0;
for (i=0; i<(*nparts); i++) {
minwgt = (wgt[i*(*ncon)+j] < wgt[minwgt*(*ncon)+j]) ? i : minwgt;
maxwgt = (wgt[i*(*ncon)+j] > wgt[maxwgt*(*ncon)+j]) ? i : maxwgt;
sumwgt += wgt[i*(*ncon)+j];
}
avgwgt = (float)sumwgt / (float)*nparts;
printf("min: %5d, max: %5d, avg: %5.2f, balance: %6.3f\n", wgt[minwgt*(*ncon)+j], wgt[maxwgt*(*ncon)+j], avgwgt, (float)wgt[maxwgt*(*ncon)+j] / avgwgt);
}
printf("\n");
}
*/
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
GKfree((void *)&mytpwgts, LTERM);
if (*numflag == 1)
Change2FNumbering(*nvtxs, xadj, adjncy, part);
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
int MCMlevelRecursiveBisection2(CtrlType *ctrl, GraphType *graph, int nparts,
float *tpwgts, idxtype *part, float ubfactor, int fpart)
{
int i, nvtxs, cut;
float wsum, tpwgts2[2];
idxtype *label, *where;
GraphType lgraph, rgraph;
nvtxs = graph->nvtxs;
if (nvtxs == 0)
return 0;
/* Determine the weights of the partitions */
tpwgts2[0] = ssum(nparts/2, tpwgts);
tpwgts2[1] = 1.0-tpwgts2[0];
MCMlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor);
cut = graph->mincut;
label = graph->label;
where = graph->where;
for (i=0; i<nvtxs; i++)
part[label[i]] = where[i] + fpart;
if (nparts > 2)
SplitGraphPart(ctrl, graph, &lgraph, &rgraph);
/* Free the memory of the top level graph */
GKfree(&graph->gdata, &graph->nvwgt, &graph->rdata, &graph->label, &graph->npwgts, LTERM);
/* Scale the fractions in the tpwgts according to the true weight */
wsum = ssum(nparts/2, tpwgts);
sscale(nparts/2, 1.0/wsum, tpwgts);
sscale(nparts-nparts/2, 1.0/(1.0-wsum), tpwgts+nparts/2);
/* Do the recursive call */
if (nparts > 3) {
cut += MCMlevelRecursiveBisection2(ctrl, &lgraph, nparts/2, tpwgts, part, ubfactor, fpart);
cut += MCMlevelRecursiveBisection2(ctrl, &rgraph, nparts-nparts/2, tpwgts+nparts/2, part, ubfactor, fpart+nparts/2);
}
else if (nparts == 3) {
cut += MCMlevelRecursiveBisection2(ctrl, &rgraph, nparts-nparts/2, tpwgts+nparts/2, part, ubfactor, fpart+nparts/2);
GKfree(&lgraph.gdata, &lgraph.nvwgt, &lgraph.label, LTERM);
}
return cut;
}

View File

@ -0,0 +1,341 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* pmetis.c
*
* This file contains the top level routines for the multilevel recursive
* bisection algorithm PMETIS.
*
* Started 7/24/97
* George
*
* $Id: pmetis.c,v 1.1 2003/07/16 15:55:16 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point for PMETIS
**************************************************************************/
void METIS_PartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
int *options, int *edgecut, idxtype *part)
{
int i;
float *tpwgts;
tpwgts = fmalloc(*nparts, "KMETIS: tpwgts");
for (i=0; i<*nparts; i++)
tpwgts[i] = 1.0/(1.0*(*nparts));
METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts,
tpwgts, options, edgecut, part);
free(tpwgts);
}
/*************************************************************************
* This function is the entry point for PWMETIS that accepts exact weights
* for the target partitions
**************************************************************************/
void METIS_WPartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
float *tpwgts, int *options, int *edgecut, idxtype *part)
{
int i, j;
GraphType graph;
CtrlType ctrl;
float *mytpwgts;
if (*numflag == 1)
Change2CNumbering(*nvtxs, xadj, adjncy);
SetUpGraph(&graph, OP_PMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag);
if (options[0] == 0) { /* Use the default parameters */
ctrl.CType = PMETIS_CTYPE;
ctrl.IType = PMETIS_ITYPE;
ctrl.RType = PMETIS_RTYPE;
ctrl.dbglvl = PMETIS_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_PMETIS;
ctrl.CoarsenTo = 20;
ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo);
mytpwgts = fmalloc(*nparts, "PWMETIS: mytpwgts");
for (i=0; i<*nparts; i++)
mytpwgts[i] = tpwgts[i];
InitRandom(-1);
AllocateWorkSpace(&ctrl, &graph, *nparts);
IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
*edgecut = MlevelRecursiveBisection(&ctrl, &graph, *nparts, part, mytpwgts, 1.000, 0);
IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
FreeWorkSpace(&ctrl, &graph);
free(mytpwgts);
if (*numflag == 1)
Change2FNumbering(*nvtxs, xadj, adjncy, part);
}
/*************************************************************************
* This function takes a graph and produces a bisection of it
**************************************************************************/
int MlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor, int fpart)
{
int i, j, nvtxs, cut, tvwgt, tpwgts2[2];
idxtype *label, *where;
GraphType lgraph, rgraph;
float wsum;
nvtxs = graph->nvtxs;
if (nvtxs == 0) {
printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n");
return 0;
}
/* Determine the weights of the partitions */
tvwgt = idxsum(nvtxs, graph->vwgt);
tpwgts2[0] = tvwgt*ssum(nparts/2, tpwgts);
tpwgts2[1] = tvwgt-tpwgts2[0];
MlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor);
cut = graph->mincut;
/* printf("%5d %5d %5d [%5d %f]\n", tpwgts2[0], tpwgts2[1], cut, tvwgt, ssum(nparts/2, tpwgts));*/
label = graph->label;
where = graph->where;
for (i=0; i<nvtxs; i++)
part[label[i]] = where[i] + fpart;
if (nparts > 2) {
SplitGraphPart(ctrl, graph, &lgraph, &rgraph);
/* printf("%d %d\n", lgraph.nvtxs, rgraph.nvtxs); */
}
/* Free the memory of the top level graph */
GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM);
/* Scale the fractions in the tpwgts according to the true weight */
wsum = ssum(nparts/2, tpwgts);
sscale(nparts/2, 1.0/wsum, tpwgts);
sscale(nparts-nparts/2, 1.0/(1.0-wsum), tpwgts+nparts/2);
/*
for (i=0; i<nparts; i++)
printf("%5.3f ", tpwgts[i]);
printf("[%5.3f]\n", wsum);
*/
/* Do the recursive call */
if (nparts > 3) {
cut += MlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, tpwgts, ubfactor, fpart);
cut += MlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, tpwgts+nparts/2, ubfactor, fpart+nparts/2);
}
else if (nparts == 3) {
cut += MlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, tpwgts+nparts/2, ubfactor, fpart+nparts/2);
GKfree(&lgraph.gdata, &lgraph.label, LTERM);
}
return cut;
}
/*************************************************************************
* This function performs multilevel bisection
**************************************************************************/
void MlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
{
GraphType *cgraph;
cgraph = Coarsen2Way(ctrl, graph);
Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor);
Refine2Way(ctrl, graph, cgraph, tpwgts, ubfactor);
/*
IsConnectedSubdomain(ctrl, graph, 0);
IsConnectedSubdomain(ctrl, graph, 1);
*/
}
/*************************************************************************
* This function takes a graph and a bisection and splits it into two graphs.
**************************************************************************/
void SplitGraphPart(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph)
{
int i, j, k, kk, l, istart, iend, mypart, nvtxs, ncon, snvtxs[2], snedges[2], sum;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr;
idxtype *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *sadjwgtsum[2], *slabel[2];
idxtype *rename;
idxtype *auxadjncy, *auxadjwgt;
float *nvwgt, *snvwgt[2], *npwgts;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr));
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
vwgt = graph->vwgt;
nvwgt = graph->nvwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
label = graph->label;
where = graph->where;
bndptr = graph->bndptr;
npwgts = graph->npwgts;
ASSERT(bndptr != NULL);
rename = idxwspacemalloc(ctrl, nvtxs);
snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;
for (i=0; i<nvtxs; i++) {
k = where[i];
rename[i] = snvtxs[k]++;
snedges[k] += xadj[i+1]-xadj[i];
}
SetUpSplitGraph(graph, lgraph, snvtxs[0], snedges[0]);
sxadj[0] = lgraph->xadj;
svwgt[0] = lgraph->vwgt;
snvwgt[0] = lgraph->nvwgt;
sadjwgtsum[0] = lgraph->adjwgtsum;
sadjncy[0] = lgraph->adjncy;
sadjwgt[0] = lgraph->adjwgt;
slabel[0] = lgraph->label;
SetUpSplitGraph(graph, rgraph, snvtxs[1], snedges[1]);
sxadj[1] = rgraph->xadj;
svwgt[1] = rgraph->vwgt;
snvwgt[1] = rgraph->nvwgt;
sadjwgtsum[1] = rgraph->adjwgtsum;
sadjncy[1] = rgraph->adjncy;
sadjwgt[1] = rgraph->adjwgt;
slabel[1] = rgraph->label;
snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;
sxadj[0][0] = sxadj[1][0] = 0;
for (i=0; i<nvtxs; i++) {
mypart = where[i];
sum = adjwgtsum[i];
istart = xadj[i];
iend = xadj[i+1];
if (bndptr[i] == -1) { /* This is an interior vertex */
auxadjncy = sadjncy[mypart] + snedges[mypart] - istart;
auxadjwgt = sadjwgt[mypart] + snedges[mypart] - istart;
for(j=istart; j<iend; j++) {
auxadjncy[j] = adjncy[j];
auxadjwgt[j] = adjwgt[j];
}
snedges[mypart] += iend-istart;
}
else {
auxadjncy = sadjncy[mypart];
auxadjwgt = sadjwgt[mypart];
l = snedges[mypart];
for (j=istart; j<iend; j++) {
k = adjncy[j];
if (where[k] == mypart) {
auxadjncy[l] = k;
auxadjwgt[l++] = adjwgt[j];
}
else {
sum -= adjwgt[j];
}
}
snedges[mypart] = l;
}
if (ncon == 1)
svwgt[mypart][snvtxs[mypart]] = vwgt[i];
else {
for (kk=0; kk<ncon; kk++)
snvwgt[mypart][snvtxs[mypart]*ncon+kk] = nvwgt[i*ncon+kk]/npwgts[mypart*ncon+kk];
}
sadjwgtsum[mypart][snvtxs[mypart]] = sum;
slabel[mypart][snvtxs[mypart]] = label[i];
sxadj[mypart][++snvtxs[mypart]] = snedges[mypart];
}
for (mypart=0; mypart<2; mypart++) {
iend = sxadj[mypart][snvtxs[mypart]];
auxadjncy = sadjncy[mypart];
for (i=0; i<iend; i++)
auxadjncy[i] = rename[auxadjncy[i]];
}
lgraph->nedges = snedges[0];
rgraph->nedges = snedges[1];
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr));
idxwspacefree(ctrl, nvtxs);
}
/*************************************************************************
* Setup the various arrays for the splitted graph
**************************************************************************/
void SetUpSplitGraph(GraphType *graph, GraphType *sgraph, int snvtxs, int snedges)
{
InitGraph(sgraph);
sgraph->nvtxs = snvtxs;
sgraph->nedges = snedges;
sgraph->ncon = graph->ncon;
/* Allocate memory for the splitted graph */
if (graph->ncon == 1) {
sgraph->gdata = idxmalloc(4*snvtxs+1 + 2*snedges, "SetUpSplitGraph: gdata");
sgraph->xadj = sgraph->gdata;
sgraph->vwgt = sgraph->gdata + snvtxs+1;
sgraph->adjwgtsum = sgraph->gdata + 2*snvtxs+1;
sgraph->cmap = sgraph->gdata + 3*snvtxs+1;
sgraph->adjncy = sgraph->gdata + 4*snvtxs+1;
sgraph->adjwgt = sgraph->gdata + 4*snvtxs+1 + snedges;
}
else {
sgraph->gdata = idxmalloc(3*snvtxs+1 + 2*snedges, "SetUpSplitGraph: gdata");
sgraph->xadj = sgraph->gdata;
sgraph->adjwgtsum = sgraph->gdata + snvtxs+1;
sgraph->cmap = sgraph->gdata + 2*snvtxs+1;
sgraph->adjncy = sgraph->gdata + 3*snvtxs+1;
sgraph->adjwgt = sgraph->gdata + 3*snvtxs+1 + snedges;
sgraph->nvwgt = fmalloc(graph->ncon*snvtxs, "SetUpSplitGraph: nvwgt");
}
sgraph->label = idxmalloc(snvtxs, "SetUpSplitGraph: sgraph->label");
}

View File

@ -0,0 +1,579 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* pqueue.c
*
* This file contains functions for manipulating the bucket list
* representation of the gains associated with each vertex in a graph.
* These functions are used by the refinement algorithms
*
* Started 9/2/94
* George
*
* $Id: pqueue.c,v 1.1 2003/07/16 15:55:16 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function initializes the data structures of the priority queue
**************************************************************************/
void PQueueInit(CtrlType *ctrl, PQueueType *queue, int maxnodes, int maxgain)
{
int i, j, ncore;
queue->nnodes = 0;
queue->maxnodes = maxnodes;
queue->buckets = NULL;
queue->nodes = NULL;
queue->heap = NULL;
queue->locator = NULL;
if (maxgain > PLUS_GAINSPAN || maxnodes < 500)
queue->type = 2;
else
queue->type = 1;
if (queue->type == 1) {
queue->pgainspan = amin(PLUS_GAINSPAN, maxgain);
queue->ngainspan = amin(NEG_GAINSPAN, maxgain);
j = queue->ngainspan+queue->pgainspan+1;
ncore = 2 + (sizeof(ListNodeType)/sizeof(idxtype))*maxnodes + (sizeof(ListNodeType *)/sizeof(idxtype))*j;
if (WspaceAvail(ctrl) > ncore) {
queue->nodes = (ListNodeType *)idxwspacemalloc(ctrl, (sizeof(ListNodeType)/sizeof(idxtype))*maxnodes);
queue->buckets = (ListNodeType **)idxwspacemalloc(ctrl, (sizeof(ListNodeType *)/sizeof(idxtype))*j);
queue->mustfree = 0;
}
else { /* Not enough memory in the wspace, allocate it */
queue->nodes = (ListNodeType *)idxmalloc((sizeof(ListNodeType)/sizeof(idxtype))*maxnodes, "PQueueInit: queue->nodes");
queue->buckets = (ListNodeType **)idxmalloc((sizeof(ListNodeType *)/sizeof(idxtype))*j, "PQueueInit: queue->buckets");
queue->mustfree = 1;
}
for (i=0; i<maxnodes; i++)
queue->nodes[i].id = i;
for (i=0; i<j; i++)
queue->buckets[i] = NULL;
queue->buckets += queue->ngainspan; /* Advance buckets by the ngainspan proper indexing */
queue->maxgain = -queue->ngainspan;
}
else {
queue->heap = (KeyValueType *)idxwspacemalloc(ctrl, (sizeof(KeyValueType)/sizeof(idxtype))*maxnodes);
queue->locator = idxwspacemalloc(ctrl, maxnodes);
idxset(maxnodes, -1, queue->locator);
}
}
/*************************************************************************
* This function resets the buckets
**************************************************************************/
void PQueueReset(PQueueType *queue)
{
int i, j;
queue->nnodes = 0;
if (queue->type == 1) {
queue->maxgain = -queue->ngainspan;
j = queue->ngainspan+queue->pgainspan+1;
queue->buckets -= queue->ngainspan;
for (i=0; i<j; i++)
queue->buckets[i] = NULL;
queue->buckets += queue->ngainspan;
}
else {
idxset(queue->maxnodes, -1, queue->locator);
}
}
/*************************************************************************
* This function frees the buckets
**************************************************************************/
void PQueueFree(CtrlType *ctrl, PQueueType *queue)
{
if (queue->type == 1) {
if (queue->mustfree) {
queue->buckets -= queue->ngainspan;
GKfree(&queue->nodes, &queue->buckets, LTERM);
}
else {
idxwspacefree(ctrl, sizeof(ListNodeType *)*(queue->ngainspan+queue->pgainspan+1)/sizeof(idxtype));
idxwspacefree(ctrl, sizeof(ListNodeType)*queue->maxnodes/sizeof(idxtype));
}
}
else {
idxwspacefree(ctrl, sizeof(KeyValueType)*queue->maxnodes/sizeof(idxtype));
idxwspacefree(ctrl, queue->maxnodes);
}
queue->maxnodes = 0;
}
/*************************************************************************
* This function returns the number of nodes in the queue
**************************************************************************/
int PQueueGetSize(PQueueType *queue)
{
return queue->nnodes;
}
/*************************************************************************
* This function adds a node of certain gain into a partition
**************************************************************************/
int PQueueInsert(PQueueType *queue, int node, int gain)
{
int i, j, k;
idxtype *locator;
ListNodeType *newnode;
KeyValueType *heap;
if (queue->type == 1) {
ASSERT(gain >= -queue->ngainspan && gain <= queue->pgainspan);
/* Allocate and add the node */
queue->nnodes++;
newnode = queue->nodes + node;
/* Attach this node in the doubly-linked list */
newnode->next = queue->buckets[gain];
newnode->prev = NULL;
if (newnode->next != NULL)
newnode->next->prev = newnode;
queue->buckets[gain] = newnode;
if (queue->maxgain < gain)
queue->maxgain = gain;
}
else {
ASSERT(CheckHeap(queue));
heap = queue->heap;
locator = queue->locator;
ASSERT(locator[node] == -1);
i = queue->nnodes++;
while (i > 0) {
j = (i-1)/2;
if (heap[j].key < gain) {
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else
break;
}
ASSERT(i >= 0);
heap[i].key = gain;
heap[i].val = node;
locator[node] = i;
ASSERT(CheckHeap(queue));
}
return 0;
}
/*************************************************************************
* This function deletes a node from a partition and reinserts it with
* an updated gain
**************************************************************************/
int PQueueDelete(PQueueType *queue, int node, int gain)
{
int i, j, newgain, oldgain;
idxtype *locator;
ListNodeType *newnode, **buckets;
KeyValueType *heap;
if (queue->type == 1) {
ASSERT(gain >= -queue->ngainspan && gain <= queue->pgainspan);
ASSERT(queue->nnodes > 0);
buckets = queue->buckets;
queue->nnodes--;
newnode = queue->nodes+node;
/* Remove newnode from the doubly-linked list */
if (newnode->prev != NULL)
newnode->prev->next = newnode->next;
else
buckets[gain] = newnode->next;
if (newnode->next != NULL)
newnode->next->prev = newnode->prev;
if (buckets[gain] == NULL && gain == queue->maxgain) {
if (queue->nnodes == 0)
queue->maxgain = -queue->ngainspan;
else
for (; buckets[queue->maxgain]==NULL; queue->maxgain--);
}
}
else { /* Heap Priority Queue */
heap = queue->heap;
locator = queue->locator;
ASSERT(locator[node] != -1);
ASSERT(heap[locator[node]].val == node);
ASSERT(CheckHeap(queue));
i = locator[node];
locator[node] = -1;
if (--queue->nnodes > 0 && heap[queue->nnodes].val != node) {
node = heap[queue->nnodes].val;
newgain = heap[queue->nnodes].key;
oldgain = heap[i].key;
if (oldgain < newgain) { /* Filter-up */
while (i > 0) {
j = (i-1)>>1;
if (heap[j].key < newgain) {
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else
break;
}
}
else { /* Filter down */
while ((j=2*i+1) < queue->nnodes) {
if (heap[j].key > newgain) {
if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key)
j = j+1;
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else if (j+1 < queue->nnodes && heap[j+1].key > newgain) {
j = j+1;
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else
break;
}
}
heap[i].key = newgain;
heap[i].val = node;
locator[node] = i;
}
ASSERT(CheckHeap(queue));
}
return 0;
}
/*************************************************************************
* This function deletes a node from a partition and reinserts it with
* an updated gain
**************************************************************************/
int PQueueUpdate(PQueueType *queue, int node, int oldgain, int newgain)
{
int i, j;
idxtype *locator;
ListNodeType *newnode;
KeyValueType *heap;
if (oldgain == newgain)
return 0;
if (queue->type == 1) {
/* First delete the node and then insert it */
PQueueDelete(queue, node, oldgain);
return PQueueInsert(queue, node, newgain);
}
else { /* Heap Priority Queue */
heap = queue->heap;
locator = queue->locator;
ASSERT(locator[node] != -1);
ASSERT(heap[locator[node]].val == node);
ASSERT(heap[locator[node]].key == oldgain);
ASSERT(CheckHeap(queue));
i = locator[node];
if (oldgain < newgain) { /* Filter-up */
while (i > 0) {
j = (i-1)>>1;
if (heap[j].key < newgain) {
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else
break;
}
}
else { /* Filter down */
while ((j=2*i+1) < queue->nnodes) {
if (heap[j].key > newgain) {
if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key)
j = j+1;
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else if (j+1 < queue->nnodes && heap[j+1].key > newgain) {
j = j+1;
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else
break;
}
}
heap[i].key = newgain;
heap[i].val = node;
locator[node] = i;
ASSERT(CheckHeap(queue));
}
return 0;
}
/*************************************************************************
* This function deletes a node from a partition and reinserts it with
* an updated gain
**************************************************************************/
void PQueueUpdateUp(PQueueType *queue, int node, int oldgain, int newgain)
{
int i, j;
idxtype *locator;
ListNodeType *newnode, **buckets;
KeyValueType *heap;
if (oldgain == newgain)
return;
if (queue->type == 1) {
ASSERT(oldgain >= -queue->ngainspan && oldgain <= queue->pgainspan);
ASSERT(newgain >= -queue->ngainspan && newgain <= queue->pgainspan);
ASSERT(queue->nnodes > 0);
buckets = queue->buckets;
newnode = queue->nodes+node;
/* First delete the node */
if (newnode->prev != NULL)
newnode->prev->next = newnode->next;
else
buckets[oldgain] = newnode->next;
if (newnode->next != NULL)
newnode->next->prev = newnode->prev;
/* Attach this node in the doubly-linked list */
newnode->next = buckets[newgain];
newnode->prev = NULL;
if (newnode->next != NULL)
newnode->next->prev = newnode;
buckets[newgain] = newnode;
if (queue->maxgain < newgain)
queue->maxgain = newgain;
}
else { /* Heap Priority Queue */
heap = queue->heap;
locator = queue->locator;
ASSERT(locator[node] != -1);
ASSERT(heap[locator[node]].val == node);
ASSERT(heap[locator[node]].key == oldgain);
ASSERT(CheckHeap(queue));
/* Here we are just filtering up since the newgain is greater than the oldgain */
i = locator[node];
while (i > 0) {
j = (i-1)>>1;
if (heap[j].key < newgain) {
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else
break;
}
heap[i].key = newgain;
heap[i].val = node;
locator[node] = i;
ASSERT(CheckHeap(queue));
}
}
/*************************************************************************
* This function returns the vertex with the largest gain from a partition
* and removes the node from the bucket list
**************************************************************************/
int PQueueGetMax(PQueueType *queue)
{
int vtx, i, j, gain, node;
idxtype *locator;
ListNodeType *tptr;
KeyValueType *heap;
if (queue->nnodes == 0)
return -1;
queue->nnodes--;
if (queue->type == 1) {
tptr = queue->buckets[queue->maxgain];
queue->buckets[queue->maxgain] = tptr->next;
if (tptr->next != NULL) {
tptr->next->prev = NULL;
}
else {
if (queue->nnodes == 0) {
queue->maxgain = -queue->ngainspan;
}
else
for (; queue->buckets[queue->maxgain]==NULL; queue->maxgain--);
}
return tptr->id;
}
else {
heap = queue->heap;
locator = queue->locator;
vtx = heap[0].val;
locator[vtx] = -1;
if ((i = queue->nnodes) > 0) {
gain = heap[i].key;
node = heap[i].val;
i = 0;
while ((j=2*i+1) < queue->nnodes) {
if (heap[j].key > gain) {
if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key)
j = j+1;
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else if (j+1 < queue->nnodes && heap[j+1].key > gain) {
j = j+1;
heap[i] = heap[j];
locator[heap[i].val] = i;
i = j;
}
else
break;
}
heap[i].key = gain;
heap[i].val = node;
locator[node] = i;
}
ASSERT(CheckHeap(queue));
return vtx;
}
}
/*************************************************************************
* This function returns the vertex with the largest gain from a partition
**************************************************************************/
int PQueueSeeMax(PQueueType *queue)
{
int vtx;
if (queue->nnodes == 0)
return -1;
if (queue->type == 1)
vtx = queue->buckets[queue->maxgain]->id;
else
vtx = queue->heap[0].val;
return vtx;
}
/*************************************************************************
* This function returns the vertex with the largest gain from a partition
**************************************************************************/
int PQueueGetKey(PQueueType *queue)
{
int key;
if (queue->nnodes == 0)
return -1;
if (queue->type == 1)
key = queue->maxgain;
else
key = queue->heap[0].key;
return key;
}
/*************************************************************************
* This functions checks the consistency of the heap
**************************************************************************/
int CheckHeap(PQueueType *queue)
{
int i, j, nnodes;
idxtype *locator;
KeyValueType *heap;
heap = queue->heap;
locator = queue->locator;
nnodes = queue->nnodes;
if (nnodes == 0)
return 1;
ASSERT(locator[heap[0].val] == 0);
for (i=1; i<nnodes; i++) {
ASSERTP(locator[heap[i].val] == i, ("%d %d %d %d\n", nnodes, i, heap[i].val, locator[heap[i].val]));
ASSERTP(heap[i].key <= heap[(i-1)/2].key, ("%d %d %d %d %d\n", i, (i-1)/2, nnodes, heap[i].key, heap[(i-1)/2].key));
}
for (i=1; i<nnodes; i++)
ASSERT(heap[i].key <= heap[0].key);
for (j=i=0; i<queue->maxnodes; i++) {
if (locator[i] != -1)
j++;
}
ASSERTP(j == nnodes, ("%d %d\n", j, nnodes));
return 1;
}

View File

@ -0,0 +1,511 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* proto.h
*
* This file contains header files
*
* Started 10/19/95
* George
*
* $Id: proto.h,v 1.3 2003/07/24 18:39:11 karypis Exp $
*
*/
/* balance.c */
void Balance2Way(CtrlType *, GraphType *, int *, float);
void Bnd2WayBalance(CtrlType *, GraphType *, int *);
void General2WayBalance(CtrlType *, GraphType *, int *);
/* bucketsort.c */
void BucketSortKeysInc(int, int, idxtype *, idxtype *, idxtype *);
/* ccgraph.c */
void CreateCoarseGraph(CtrlType *, GraphType *, int, idxtype *, idxtype *);
void CreateCoarseGraphNoMask(CtrlType *, GraphType *, int, idxtype *, idxtype *);
void CreateCoarseGraph_NVW(CtrlType *, GraphType *, int, idxtype *, idxtype *);
GraphType *SetUpCoarseGraph(GraphType *, int, int);
void ReAdjustMemory(GraphType *, GraphType *, int);
/* checkgraph.c */
int CheckGraph(GraphType *);
/* coarsen.c */
GraphType *Coarsen2Way(CtrlType *, GraphType *);
/* compress.c */
void CompressGraph(CtrlType *, GraphType *, int, idxtype *, idxtype *, idxtype *, idxtype *);
void PruneGraph(CtrlType *, GraphType *, int, idxtype *, idxtype *, idxtype *, float);
/* debug.c */
int ComputeCut(GraphType *, idxtype *);
int CheckBnd(GraphType *);
int CheckBnd2(GraphType *);
int CheckNodeBnd(GraphType *, int);
int CheckRInfo(RInfoType *);
int CheckNodePartitionParams(GraphType *);
int IsSeparable(GraphType *);
/* estmem.c */
void METIS_EstimateMemory(int *, idxtype *, idxtype *, int *, int *, int *);
void EstimateCFraction(int, idxtype *, idxtype *, float *, float *);
int ComputeCoarseGraphSize(int, idxtype *, idxtype *, int, idxtype *, idxtype *, idxtype *);
/* fm.c */
void FM_2WayEdgeRefine(CtrlType *, GraphType *, int *, int);
/* fortran.c */
void Change2CNumbering(int, idxtype *, idxtype *);
void Change2FNumbering(int, idxtype *, idxtype *, idxtype *);
void Change2FNumbering2(int, idxtype *, idxtype *);
void Change2FNumberingOrder(int, idxtype *, idxtype *, idxtype *, idxtype *);
void ChangeMesh2CNumbering(int, idxtype *);
void ChangeMesh2FNumbering(int, idxtype *, int, idxtype *, idxtype *);
void ChangeMesh2FNumbering2(int, idxtype *, int, int, idxtype *, idxtype *);
/* frename.c */
void METIS_PARTGRAPHRECURSIVE(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_partgraphrecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_partgraphrecursive_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_partgraphrecursive__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void METIS_WPARTGRAPHRECURSIVE(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_wpartgraphrecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_wpartgraphrecursive_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_wpartgraphrecursive__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void METIS_PARTGRAPHKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_partgraphkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_partgraphkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_partgraphkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void METIS_WPARTGRAPHKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_wpartgraphkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_wpartgraphkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_wpartgraphkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void METIS_EDGEND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_edgend(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_edgend_(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_edgend__(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void METIS_NODEND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_nodend(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_nodend_(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_nodend__(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void METIS_NODEWND(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_nodewnd(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_nodewnd_(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_nodewnd__(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void METIS_PARTMESHNODAL(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
void metis_partmeshnodal(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
void metis_partmeshnodal_(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
void metis_partmeshnodal__(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
void METIS_PARTMESHDUAL(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
void metis_partmeshdual(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
void metis_partmeshdual_(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
void metis_partmeshdual__(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
void METIS_MESHTONODAL(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_meshtonodal(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_meshtonodal_(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_meshtonodal__(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void METIS_MESHTODUAL(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_meshtodual(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_meshtodual_(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void metis_meshtodual__(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void METIS_ESTIMATEMEMORY(int *, idxtype *, idxtype *, int *, int *, int *);
void metis_estimatememory(int *, idxtype *, idxtype *, int *, int *, int *);
void metis_estimatememory_(int *, idxtype *, idxtype *, int *, int *, int *);
void metis_estimatememory__(int *, idxtype *, idxtype *, int *, int *, int *);
void METIS_MCPARTGRAPHRECURSIVE(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_mcpartgraphrecursive(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_mcpartgraphrecursive_(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_mcpartgraphrecursive__(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void METIS_MCPARTGRAPHKWAY(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_mcpartgraphkway(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_mcpartgraphkway_(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_mcpartgraphkway__(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void METIS_PARTGRAPHVKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_partgraphvkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_partgraphvkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void metis_partgraphvkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void METIS_WPARTGRAPHVKWAY(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_wpartgraphvkway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_wpartgraphvkway_(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void metis_wpartgraphvkway__(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
/* graph.c */
void SetUpGraph(GraphType *, int, int, int, idxtype *, idxtype *, idxtype *, idxtype *, int);
void SetUpGraphKway(GraphType *, int, idxtype *, idxtype *);
void SetUpGraph2(GraphType *, int, int, idxtype *, idxtype *, float *, idxtype *);
void VolSetUpGraph(GraphType *, int, int, int, idxtype *, idxtype *, idxtype *, idxtype *, int);
void RandomizeGraph(GraphType *);
int IsConnectedSubdomain(CtrlType *, GraphType *, int, int);
int IsConnected(CtrlType *, GraphType *, int);
int IsConnected2(GraphType *, int);
int FindComponents(CtrlType *, GraphType *, idxtype *, idxtype *);
/* initpart.c */
void Init2WayPartition(CtrlType *, GraphType *, int *, float);
void InitSeparator(CtrlType *, GraphType *, float);
void GrowBisection(CtrlType *, GraphType *, int *, float);
void GrowBisectionNode(CtrlType *, GraphType *, float);
void RandomBisection(CtrlType *, GraphType *, int *, float);
/* kmetis.c */
void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void METIS_WPartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
int MlevelKWayPartitioning(CtrlType *, GraphType *, int, idxtype *, float *, float);
/* kvmetis.c */
void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void METIS_WPartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
int MlevelVolKWayPartitioning(CtrlType *, GraphType *, int, idxtype *, float *, float);
/* kwayfm.c */
void Random_KWayEdgeRefine(CtrlType *, GraphType *, int, float *, float, int, int);
void Greedy_KWayEdgeRefine(CtrlType *, GraphType *, int, float *, float, int);
void Greedy_KWayEdgeBalance(CtrlType *, GraphType *, int, float *, float, int);
/* kwayrefine.c */
void RefineKWay(CtrlType *, GraphType *, GraphType *, int, float *, float);
void AllocateKWayPartitionMemory(CtrlType *, GraphType *, int);
void ComputeKWayPartitionParams(CtrlType *, GraphType *, int);
void ProjectKWayPartition(CtrlType *, GraphType *, int);
int IsBalanced(idxtype *, int, float *, float);
void ComputeKWayBoundary(CtrlType *, GraphType *, int);
void ComputeKWayBalanceBoundary(CtrlType *, GraphType *, int);
/* kwayvolfm.c */
void Random_KWayVolRefine(CtrlType *, GraphType *, int, float *, float, int, int);
void Random_KWayVolRefineMConn(CtrlType *, GraphType *, int, float *, float, int, int);
void Greedy_KWayVolBalance(CtrlType *, GraphType *, int, float *, float, int);
void Greedy_KWayVolBalanceMConn(CtrlType *, GraphType *, int, float *, float, int);
void KWayVolUpdate(CtrlType *, GraphType *, int, int, int, idxtype *, idxtype *, idxtype *);
void ComputeKWayVolume(GraphType *, int, idxtype *, idxtype *, idxtype *);
int ComputeVolume(GraphType *, idxtype *);
void CheckVolKWayPartitionParams(CtrlType *, GraphType *, int);
void ComputeVolSubDomainGraph(GraphType *, int, idxtype *, idxtype *);
void EliminateVolSubDomainEdges(CtrlType *, GraphType *, int, float *);
void EliminateVolComponents(CtrlType *, GraphType *, int, float *, float);
/* kwayvolrefine.c */
void RefineVolKWay(CtrlType *, GraphType *, GraphType *, int, float *, float);
void AllocateVolKWayPartitionMemory(CtrlType *, GraphType *, int);
void ComputeVolKWayPartitionParams(CtrlType *, GraphType *, int);
void ComputeKWayVolGains(CtrlType *, GraphType *, int);
void ProjectVolKWayPartition(CtrlType *, GraphType *, int);
void ComputeVolKWayBoundary(CtrlType *, GraphType *, int);
void ComputeVolKWayBalanceBoundary(CtrlType *, GraphType *, int);
/* match.c */
void Match_RM(CtrlType *, GraphType *);
void Match_RM_NVW(CtrlType *, GraphType *);
void Match_HEM(CtrlType *, GraphType *);
void Match_SHEM(CtrlType *, GraphType *);
/* mbalance.c */
void MocBalance2Way(CtrlType *, GraphType *, float *, float);
void MocGeneral2WayBalance(CtrlType *, GraphType *, float *, float);
/* mbalance2.c */
void MocBalance2Way2(CtrlType *, GraphType *, float *, float *);
void MocGeneral2WayBalance2(CtrlType *, GraphType *, float *, float *);
void SelectQueue3(int, float *, float *, int *, int *, PQueueType [MAXNCON][2], float *);
/* mcoarsen.c */
GraphType *MCCoarsen2Way(CtrlType *, GraphType *);
/* memory.c */
void AllocateWorkSpace(CtrlType *, GraphType *, int);
void FreeWorkSpace(CtrlType *, GraphType *);
int WspaceAvail(CtrlType *);
idxtype *idxwspacemalloc(CtrlType *, int);
void idxwspacefree(CtrlType *, int);
float *fwspacemalloc(CtrlType *, int);
void fwspacefree(CtrlType *, int);
GraphType *CreateGraph(void);
void InitGraph(GraphType *);
void FreeGraph(GraphType *);
/* mesh.c */
void METIS_MeshToDual(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void METIS_MeshToNodal(int *, int *, idxtype *, int *, int *, idxtype *, idxtype *);
void GENDUALMETIS(int, int, int, idxtype *, idxtype *, idxtype *adjncy);
void TRINODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy);
void TETNODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy);
void HEXNODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy);
void QUADNODALMETIS(int, int, idxtype *, idxtype *, idxtype *adjncy);
/* meshpart.c */
void METIS_PartMeshNodal(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
void METIS_PartMeshDual(int *, int *, idxtype *, int *, int *, int *, int *, idxtype *, idxtype *);
/* mfm.c */
void MocFM_2WayEdgeRefine(CtrlType *, GraphType *, float *, int);
void SelectQueue(int, float *, float *, int *, int *, PQueueType [MAXNCON][2]);
int BetterBalance(int, float *, float *, float *);
float Compute2WayHLoadImbalance(int, float *, float *);
void Compute2WayHLoadImbalanceVec(int, float *, float *, float *);
/* mfm2.c */
void MocFM_2WayEdgeRefine2(CtrlType *, GraphType *, float *, float *, int);
void SelectQueue2(int, float *, float *, int *, int *, PQueueType [MAXNCON][2], float *);
int IsBetter2wayBalance(int, float *, float *, float *);
/* mincover.o */
void MinCover(idxtype *, idxtype *, int, int, idxtype *, int *);
int MinCover_Augment(idxtype *, idxtype *, int, idxtype *, idxtype *, idxtype *, int);
void MinCover_Decompose(idxtype *, idxtype *, int, int, idxtype *, idxtype *, int *);
void MinCover_ColDFS(idxtype *, idxtype *, int, idxtype *, idxtype *, int);
void MinCover_RowDFS(idxtype *, idxtype *, int, idxtype *, idxtype *, int);
/* minitpart.c */
void MocInit2WayPartition(CtrlType *, GraphType *, float *, float);
void MocGrowBisection(CtrlType *, GraphType *, float *, float);
void MocRandomBisection(CtrlType *, GraphType *, float *, float);
void MocInit2WayBalance(CtrlType *, GraphType *, float *);
int SelectQueueoneWay(int, float *, float *, int, PQueueType [MAXNCON][2]);
/* minitpart2.c */
void MocInit2WayPartition2(CtrlType *, GraphType *, float *, float *);
void MocGrowBisection2(CtrlType *, GraphType *, float *, float *);
void MocGrowBisectionNew2(CtrlType *, GraphType *, float *, float *);
void MocInit2WayBalance2(CtrlType *, GraphType *, float *, float *);
int SelectQueueOneWay2(int, float *, PQueueType [MAXNCON][2], float *);
/* mkmetis.c */
void METIS_mCPartGraphKway(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
int MCMlevelKWayPartitioning(CtrlType *, GraphType *, int, idxtype *, float *);
/* mkwayfmh.c */
void MCRandom_KWayEdgeRefineHorizontal(CtrlType *, GraphType *, int, float *, int);
void MCGreedy_KWayEdgeBalanceHorizontal(CtrlType *, GraphType *, int, float *, int);
int AreAllHVwgtsBelow(int, float, float *, float, float *, float *);
int AreAllHVwgtsAbove(int, float, float *, float, float *, float *);
void ComputeHKWayLoadImbalance(int, int, float *, float *);
int MocIsHBalanced(int, int, float *, float *);
int IsHBalanceBetterFT(int, int, float *, float *, float *, float *);
int IsHBalanceBetterTT(int, int, float *, float *, float *, float *);
/* mkwayrefine.c */
void MocRefineKWayHorizontal(CtrlType *, GraphType *, GraphType *, int, float *);
void MocAllocateKWayPartitionMemory(CtrlType *, GraphType *, int);
void MocComputeKWayPartitionParams(CtrlType *, GraphType *, int);
void MocProjectKWayPartition(CtrlType *, GraphType *, int);
void MocComputeKWayBalanceBoundary(CtrlType *, GraphType *, int);
/* mmatch.c */
void MCMatch_RM(CtrlType *, GraphType *);
void MCMatch_HEM(CtrlType *, GraphType *);
void MCMatch_SHEM(CtrlType *, GraphType *);
void MCMatch_SHEBM(CtrlType *, GraphType *, int);
void MCMatch_SBHEM(CtrlType *, GraphType *, int);
float BetterVBalance(int, int, float *, float *, float *);
int AreAllVwgtsBelowFast(int, float *, float *, float);
/* mmd.c */
void genmmd(int, idxtype *, idxtype *, idxtype *, idxtype *, int , idxtype *, idxtype *, idxtype *, idxtype *, int, int *);
void mmdelm(int, idxtype *xadj, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int, int);
int mmdint(int, idxtype *xadj, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *);
void mmdnum(int, idxtype *, idxtype *, idxtype *);
void mmdupd(int, int, idxtype *, idxtype *, int, int *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int, int *tag);
/* mpmetis.c */
void METIS_mCPartGraphRecursive(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void METIS_mCHPartGraphRecursive(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void METIS_mCPartGraphRecursiveInternal(int *, int *, idxtype *, idxtype *, float *, idxtype *, int *, int *, int *, idxtype *);
void METIS_mCHPartGraphRecursiveInternal(int *, int *, idxtype *, idxtype *, float *, idxtype *, int *, float *, int *, int *, idxtype *);
int MCMlevelRecursiveBisection(CtrlType *, GraphType *, int, idxtype *, float, int);
int MCHMlevelRecursiveBisection(CtrlType *, GraphType *, int, idxtype *, float *, int);
void MCMlevelEdgeBisection(CtrlType *, GraphType *, float *, float);
void MCHMlevelEdgeBisection(CtrlType *, GraphType *, float *, float *);
/* mrefine.c */
void MocRefine2Way(CtrlType *, GraphType *, GraphType *, float *, float);
void MocAllocate2WayPartitionMemory(CtrlType *, GraphType *);
void MocCompute2WayPartitionParams(CtrlType *, GraphType *);
void MocProject2WayPartition(CtrlType *, GraphType *);
/* mrefine2.c */
void MocRefine2Way2(CtrlType *, GraphType *, GraphType *, float *, float *);
/* mutil.c */
int AreAllVwgtsBelow(int, float, float *, float, float *, float);
int AreAnyVwgtsBelow(int, float, float *, float, float *, float);
int AreAllVwgtsAbove(int, float, float *, float, float *, float);
float ComputeLoadImbalance(int, int, float *, float *);
int AreAllBelow(int, float *, float *);
/* myqsort.c */
void iidxsort(int, idxtype *);
void iintsort(int, int *);
void ikeysort(int, KeyValueType *);
void ikeyvalsort(int, KeyValueType *);
/* ometis.c */
void METIS_EdgeND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void METIS_NodeND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void METIS_NodeWND(int *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
void MlevelNestedDissection(CtrlType *, GraphType *, idxtype *, float, int);
void MlevelNestedDissectionCC(CtrlType *, GraphType *, idxtype *, float, int);
void MlevelNodeBisectionMultiple(CtrlType *, GraphType *, int *, float);
void MlevelNodeBisection(CtrlType *, GraphType *, int *, float);
void SplitGraphOrder(CtrlType *, GraphType *, GraphType *, GraphType *);
void MMDOrder(CtrlType *, GraphType *, idxtype *, int);
int SplitGraphOrderCC(CtrlType *, GraphType *, GraphType *, int, idxtype *, idxtype *);
/* parmetis.c */
void METIS_PartGraphKway2(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void METIS_WPartGraphKway2(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
void METIS_NodeNDP(int, idxtype *, idxtype *, int, int *, idxtype *, idxtype *, idxtype *);
void MlevelNestedDissectionP(CtrlType *, GraphType *, idxtype *, int, int, int, idxtype *);
void METIS_NodeComputeSeparator(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *);
void METIS_EdgeComputeSeparator(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *);
void METIS_mCPartGraphRecursive2(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part);
int MCMlevelRecursiveBisection2(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, idxtype *part, float ubfactor, int fpart);
/* pmetis.c */
void METIS_PartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *);
void METIS_WPartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
int MlevelRecursiveBisection(CtrlType *, GraphType *, int, idxtype *, float *, float, int);
void MlevelEdgeBisection(CtrlType *, GraphType *, int *, float);
void SplitGraphPart(CtrlType *, GraphType *, GraphType *, GraphType *);
void SetUpSplitGraph(GraphType *, GraphType *, int, int);
/* pqueue.c */
void PQueueInit(CtrlType *ctrl, PQueueType *, int, int);
void PQueueReset(PQueueType *);
void PQueueFree(CtrlType *ctrl, PQueueType *);
int PQueueGetSize(PQueueType *);
int PQueueInsert(PQueueType *, int, int);
int PQueueDelete(PQueueType *, int, int);
int PQueueUpdate(PQueueType *, int, int, int);
void PQueueUpdateUp(PQueueType *, int, int, int);
int PQueueGetMax(PQueueType *);
int PQueueSeeMax(PQueueType *);
int PQueueGetKey(PQueueType *);
int CheckHeap(PQueueType *);
/* refine.c */
void Refine2Way(CtrlType *, GraphType *, GraphType *, int *, float ubfactor);
void Allocate2WayPartitionMemory(CtrlType *, GraphType *);
void Compute2WayPartitionParams(CtrlType *, GraphType *);
void Project2WayPartition(CtrlType *, GraphType *);
/* separator.c */
void ConstructSeparator(CtrlType *, GraphType *, float);
void ConstructMinCoverSeparator0(CtrlType *, GraphType *, float);
void ConstructMinCoverSeparator(CtrlType *, GraphType *, float);
/* sfm.c */
void FM_2WayNodeRefine(CtrlType *, GraphType *, float, int);
void FM_2WayNodeRefineEqWgt(CtrlType *, GraphType *, int);
void FM_2WayNodeRefine_OneSided(CtrlType *, GraphType *, float, int);
void FM_2WayNodeBalance(CtrlType *, GraphType *, float);
int ComputeMaxNodeGain(int, idxtype *, idxtype *, idxtype *);
/* srefine.c */
void Refine2WayNode(CtrlType *, GraphType *, GraphType *, float);
void Allocate2WayNodePartitionMemory(CtrlType *, GraphType *);
void Compute2WayNodePartitionParams(CtrlType *, GraphType *);
void Project2WayNodePartition(CtrlType *, GraphType *);
/* stat.c */
void ComputePartitionInfo(GraphType *, int, idxtype *);
void ComputePartitionInfoBipartite(GraphType *, int, idxtype *);
void ComputePartitionBalance(GraphType *, int, idxtype *, float *);
float ComputeElementBalance(int, int, idxtype *);
void Moc_ComputePartitionBalance(GraphType *graph, int nparts, idxtype *where, float *ubvec);
/* subdomains.c */
void Random_KWayEdgeRefineMConn(CtrlType *, GraphType *, int, float *, float, int, int);
void Greedy_KWayEdgeBalanceMConn(CtrlType *, GraphType *, int, float *, float, int);
void PrintSubDomainGraph(GraphType *, int, idxtype *);
void ComputeSubDomainGraph(GraphType *, int, idxtype *, idxtype *);
void EliminateSubDomainEdges(CtrlType *, GraphType *, int, float *);
void MoveGroupMConn(CtrlType *, GraphType *, idxtype *, idxtype *, int, int, int, idxtype *);
void EliminateComponents(CtrlType *, GraphType *, int, float *, float);
void MoveGroup(CtrlType *, GraphType *, int, int, int, idxtype *, idxtype *);
/* timing.c */
void InitTimers(CtrlType *);
void PrintTimers(CtrlType *);
double seconds(void);
/* util.c */
void errexit(char *,...);
#ifndef DMALLOC
int *imalloc(int, char *);
idxtype *idxmalloc(int, char *);
float *fmalloc(int, char *);
int *ismalloc(int, int, char *);
idxtype *idxsmalloc(int, idxtype, char *);
void *GKmalloc(int, char *);
#endif
/*void GKfree(void **,...); */
int *iset(int n, int val, int *x);
idxtype *idxset(int n, idxtype val, idxtype *x);
float *sset(int n, float val, float *x);
int iamax(int, int *);
int idxamax(int, idxtype *);
int idxamax_strd(int, idxtype *, int);
int samax(int, float *);
int samax2(int, float *);
int idxamin(int, idxtype *);
int samin(int, float *);
int idxsum(int, idxtype *);
int idxsum_strd(int, idxtype *, int);
void idxadd(int, idxtype *, idxtype *);
int charsum(int, char *);
int isum(int, int *);
float ssum(int, float *);
float ssum_strd(int n, float *x, int);
void sscale(int n, float, float *x);
float snorm2(int, float *);
float sdot(int n, float *, float *);
void saxpy(int, float, float *, int, float *, int);
void RandomPermute(int, idxtype *, int);
int ispow2(int);
void InitRandom(int);
int log2Int(int);
/***************************************************************
* Programs Directory
****************************************************************/
/* io.c */
void ReadGraph(GraphType *, char *, int *);
void WritePartition(char *, idxtype *, int, int);
void WriteMeshPartition(char *, int, int, idxtype *, int, idxtype *);
void WritePermutation(char *, idxtype *, int);
int CheckGraph(GraphType *);
idxtype *ReadMesh(char *, int *, int *, int *);
void WriteGraph(char *, int, idxtype *, idxtype *);
/* smbfactor.c */
void ComputeFillIn(GraphType *, idxtype *);
idxtype ComputeFillIn2(GraphType *, idxtype *);
int smbfct(int, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int *, idxtype *, idxtype *, int *);
/***************************************************************
* Test Directory
****************************************************************/
void Test_PartGraph(int, idxtype *, idxtype *);
int VerifyPart(int, idxtype *, idxtype *, idxtype *, idxtype *, int, int, idxtype *);
int VerifyWPart(int, idxtype *, idxtype *, idxtype *, idxtype *, int, float *, int, idxtype *);
void Test_PartGraphV(int, idxtype *, idxtype *);
int VerifyPartV(int, idxtype *, idxtype *, idxtype *, idxtype *, int, int, idxtype *);
int VerifyWPartV(int, idxtype *, idxtype *, idxtype *, idxtype *, int, float *, int, idxtype *);
void Test_PartGraphmC(int, idxtype *, idxtype *);
int VerifyPartmC(int, int, idxtype *, idxtype *, idxtype *, idxtype *, int, float *, int, idxtype *);
void Test_ND(int, idxtype *, idxtype *);
int VerifyND(int, idxtype *, idxtype *);

View File

@ -0,0 +1,204 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* refine.c
*
* This file contains the driving routines for multilevel refinement
*
* Started 7/24/97
* George
*
* $Id: refine.c,v 1.1 2003/07/16 15:55:17 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of refinement
**************************************************************************/
void Refine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int *tpwgts, float ubfactor)
{
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
/* Compute the parameters of the coarsest graph */
Compute2WayPartitionParams(ctrl, graph);
for (;;) {
ASSERT(CheckBnd(graph));
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
switch (ctrl->RType) {
case 1:
Balance2Way(ctrl, graph, tpwgts, ubfactor);
FM_2WayEdgeRefine(ctrl, graph, tpwgts, 8);
break;
default:
errexit("Unknown refinement type: %d\n", ctrl->RType);
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
if (graph == orggraph)
break;
graph = graph->finer;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
Project2WayPartition(ctrl, graph);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
}
/*************************************************************************
* This function allocates memory for 2-way edge refinement
**************************************************************************/
void Allocate2WayPartitionMemory(CtrlType *ctrl, GraphType *graph)
{
int nvtxs;
nvtxs = graph->nvtxs;
graph->rdata = idxmalloc(5*nvtxs+2, "Allocate2WayPartitionMemory: rdata");
graph->pwgts = graph->rdata;
graph->where = graph->rdata + 2;
graph->id = graph->rdata + nvtxs + 2;
graph->ed = graph->rdata + 2*nvtxs + 2;
graph->bndptr = graph->rdata + 3*nvtxs + 2;
graph->bndind = graph->rdata + 4*nvtxs + 2;
}
/*************************************************************************
* This function computes the initial id/ed
**************************************************************************/
void Compute2WayPartitionParams(CtrlType *ctrl, GraphType *graph)
{
int i, j, k, l, nvtxs, nbnd, mincut;
idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts;
idxtype *id, *ed, *where;
idxtype *bndptr, *bndind;
int me, other;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
pwgts = idxset(2, 0, graph->pwgts);
id = idxset(nvtxs, 0, graph->id);
ed = idxset(nvtxs, 0, graph->ed);
bndptr = idxset(nvtxs, -1, graph->bndptr);
bndind = graph->bndind;
/*------------------------------------------------------------
/ Compute now the id/ed degrees
/------------------------------------------------------------*/
nbnd = mincut = 0;
for (i=0; i<nvtxs; i++) {
ASSERT(where[i] >= 0 && where[i] <= 1);
me = where[i];
pwgts[me] += vwgt[i];
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (me == where[adjncy[j]])
id[i] += adjwgt[j];
else
ed[i] += adjwgt[j];
}
if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
mincut += ed[i];
bndptr[i] = nbnd;
bndind[nbnd++] = i;
}
}
graph->mincut = mincut/2;
graph->nbnd = nbnd;
ASSERT(pwgts[0]+pwgts[1] == idxsum(nvtxs, vwgt));
}
/*************************************************************************
* This function projects a partition, and at the same time computes the
* parameters for refinement.
**************************************************************************/
void Project2WayPartition(CtrlType *ctrl, GraphType *graph)
{
int i, j, k, nvtxs, nbnd, me;
idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
idxtype *cmap, *where, *id, *ed, *bndptr, *bndind;
idxtype *cwhere, *cid, *ced, *cbndptr;
GraphType *cgraph;
cgraph = graph->coarser;
cwhere = cgraph->where;
cid = cgraph->id;
ced = cgraph->ed;
cbndptr = cgraph->bndptr;
nvtxs = graph->nvtxs;
cmap = graph->cmap;
xadj = graph->xadj;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
adjwgtsum = graph->adjwgtsum;
Allocate2WayPartitionMemory(ctrl, graph);
where = graph->where;
id = idxset(nvtxs, 0, graph->id);
ed = idxset(nvtxs, 0, graph->ed);
bndptr = idxset(nvtxs, -1, graph->bndptr);
bndind = graph->bndind;
/* Go through and project partition and compute id/ed for the nodes */
for (i=0; i<nvtxs; i++) {
k = cmap[i];
where[i] = cwhere[k];
cmap[i] = cbndptr[k];
}
for (nbnd=0, i=0; i<nvtxs; i++) {
me = where[i];
id[i] = adjwgtsum[i];
if (xadj[i] == xadj[i+1]) {
bndptr[i] = nbnd;
bndind[nbnd++] = i;
}
else {
if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (me != where[adjncy[j]])
ed[i] += adjwgt[j];
}
id[i] -= ed[i];
if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
bndptr[i] = nbnd;
bndind[nbnd++] = i;
}
}
}
}
graph->mincut = cgraph->mincut;
graph->nbnd = nbnd;
idxcopy(2, cgraph->pwgts, graph->pwgts);
FreeGraph(graph->coarser);
graph->coarser = NULL;
}

View File

@ -0,0 +1,424 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* rename.h
*
* This file contains header files
*
* Started 10/2/97
* George
*
* $Id: rename.h,v 1.2 2003/07/24 18:39:12 karypis Exp $
*
*/
/* balance.c */
#define Balance2Way __Balance2Way
#define Bnd2WayBalance __Bnd2WayBalance
#define General2WayBalance __General2WayBalance
/* bucketsort.c */
#define BucketSortKeysInc __BucketSortKeysInc
/* ccgraph.c */
#define CreateCoarseGraph __CreateCoarseGraph
#define CreateCoarseGraphNoMask __CreateCoarseGraphNoMask
#define CreateCoarseGraph_NVW __CreateCoarseGraph_NVW
#define SetUpCoarseGraph __SetUpCoarseGraph
#define ReAdjustMemory __ReAdjustMemory
/* checkgraph.c */
#define CheckGraph __CheckGraph
/* coarsen.c */
#define Coarsen2Way __Coarsen2Way
/* compress.c */
#define CompressGraph __CompressGraph
#define PruneGraph __PruneGraph
/* debug.c */
#define ComputeCut __ComputeCut
#define CheckBnd __CheckBnd
#define CheckBnd2 __CheckBnd2
#define CheckNodeBnd __CheckNodeBnd
#define CheckRInfo __CheckRInfo
#define CheckNodePartitionParams __CheckNodePartitionParams
#define IsSeparable __IsSeparable
/* estmem.c */
#define EstimateCFraction __EstimateCFraction
#define ComputeCoarseGraphSize __ComputeCoarseGraphSize
/* fm.c */
#define FM_2WayEdgeRefine __FM_2WayEdgeRefine
/* fortran.c */
#define Change2CNumbering __Change2CNumbering
#define Change2FNumbering __Change2FNumbering
#define Change2FNumbering2 __Change2FNumbering2
#define Change2FNumberingOrder __Change2FNumberingOrder
#define ChangeMesh2CNumbering __ChangeMesh2CNumbering
#define ChangeMesh2FNumbering __ChangeMesh2FNumbering
#define ChangeMesh2FNumbering2 __ChangeMesh2FNumbering2
/* graph.c */
#define SetUpGraph __SetUpGraph
#define SetUpGraphKway __SetUpGraphKway
#define SetUpGraph2 __SetUpGraph2
#define VolSetUpGraph __VolSetUpGraph
#define RandomizeGraph __RandomizeGraph
#define IsConnectedSubdomain __IsConnectedSubdomain
#define IsConnected __IsConnected
#define IsConnected2 __IsConnected2
#define FindComponents __FindComponents
/* initpart.c */
#define Init2WayPartition __Init2WayPartition
#define InitSeparator __InitSeparator
#define GrowBisection __GrowBisection
#define GrowBisectionNode __GrowBisectionNode
#define RandomBisection __RandomBisection
/* kmetis.c */
#define MlevelKWayPartitioning __MlevelKWayPartitioning
/* kvmetis.c */
#define MlevelVolKWayPartitioning __MlevelVolKWayPartitioning
/* kwayfm.c */
#define Random_KWayEdgeRefine __Random_KWayEdgeRefine
#define Greedy_KWayEdgeRefine __Greedy_KWayEdgeRefine
#define Greedy_KWayEdgeBalance __Greedy_KWayEdgeBalance
/* kwayrefine.c */
#define RefineKWay __RefineKWay
#define AllocateKWayPartitionMemory __AllocateKWayPartitionMemory
#define ComputeKWayPartitionParams __ComputeKWayPartitionParams
#define ProjectKWayPartition __ProjectKWayPartition
#define IsBalanced __IsBalanced
#define ComputeKWayBoundary __ComputeKWayBoundary
#define ComputeKWayBalanceBoundary __ComputeKWayBalanceBoundary
/* kwayvolfm.c */
#define Random_KWayVolRefine __Random_KWayVolRefine
#define Random_KWayVolRefineMConn __Random_KWayVolRefineMConn
#define Greedy_KWayVolBalance __Greedy_KWayVolBalance
#define Greedy_KWayVolBalanceMConn __Greedy_KWayVolBalanceMConn
#define KWayVolUpdate __KWayVolUpdate
#define ComputeKWayVolume __ComputeKWayVolume
#define ComputeVolume __ComputeVolume
#define CheckVolKWayPartitionParams __CheckVolKWayPartitionParams
#define ComputeVolSubDomainGraph __ComputeVolSubDomainGraph
#define EliminateVolSubDomainEdges __EliminateVolSubDomainEdges
/* kwayvolrefine.c */
#define RefineVolKWay __RefineVolKWay
#define AllocateVolKWayPartitionMemory __AllocateVolKWayPartitionMemory
#define ComputeVolKWayPartitionParams __ComputeVolKWayPartitionParams
#define ComputeKWayVolGains __ComputeKWayVolGains
#define ProjectVolKWayPartition __ProjectVolKWayPartition
#define ComputeVolKWayBoundary __ComputeVolKWayBoundary
#define ComputeVolKWayBalanceBoundary __ComputeVolKWayBalanceBoundary
/* match.c */
#define Match_RM __Match_RM
#define Match_RM_NVW __Match_RM_NVW
#define Match_HEM __Match_HEM
#define Match_SHEM __Match_SHEM
/* mbalance.c */
#define MocBalance2Way __MocBalance2Way
#define MocGeneral2WayBalance __MocGeneral2WayBalance
/* mbalance2.c */
#define MocBalance2Way2 __MocBalance2Way2
#define MocGeneral2WayBalance2 __MocGeneral2WayBalance2
#define SelectQueue3 __SelectQueue3
/* mcoarsen.c */
#define MCCoarsen2Way __MCCoarsen2Way
/* memory.c */
#define AllocateWorkSpace __AllocateWorkSpace
#define FreeWorkSpace __FreeWorkSpace
#define WspaceAvail __WspaceAvail
#define idxwspacemalloc __idxwspacemalloc
#define idxwspacefree __idxwspacefree
#define fwspacemalloc __fwspacemalloc
#define CreateGraph __CreateGraph
#define InitGraph __InitGraph
#define FreeGraph __FreeGraph
/* mesh.c */
#define TRIDUALMETIS __TRIDUALMETIS
#define TETDUALMETIS __TETDUALMETIS
#define HEXDUALMETIS __HEXDUALMETIS
#define TRINODALMETIS __TRINODALMETIS
#define TETNODALMETIS __TETNODALMETIS
#define HEXNODALMETIS __HEXNODALMETIS
/* mfm.c */
#define MocFM_2WayEdgeRefine __MocFM_2WayEdgeRefine
#define SelectQueue __SelectQueue
#define BetterBalance __BetterBalance
#define Compute2WayHLoadImbalance __Compute2WayHLoadImbalance
#define Compute2WayHLoadImbalanceVec __Compute2WayHLoadImbalanceVec
/* mfm2.c */
#define MocFM_2WayEdgeRefine2 __MocFM_2WayEdgeRefine2
#define SelectQueue2 __SelectQueue2
#define IsBetter2wayBalance __IsBetter2wayBalance
/* mincover.c */
#define MinCover __MinCover
#define MinCover_Augment __MinCover_Augment
#define MinCover_Decompose __MinCover_Decompose
#define MinCover_ColDFS __MinCover_ColDFS
#define MinCover_RowDFS __MinCover_RowDFS
/* minitpart.c */
#define MocInit2WayPartition __MocInit2WayPartition
#define MocGrowBisection __MocGrowBisection
#define MocRandomBisection __MocRandomBisection
#define MocInit2WayBalance __MocInit2WayBalance
#define SelectQueueoneWay __SelectQueueoneWay
/* minitpart2.c */
#define MocInit2WayPartition2 __MocInit2WayPartition2
#define MocGrowBisection2 __MocGrowBisection2
#define MocGrowBisectionNew2 __MocGrowBisectionNew2
#define MocInit2WayBalance2 __MocInit2WayBalance2
#define SelectQueueOneWay2 __SelectQueueOneWay2
/* mkmetis.c */
#define MCMlevelKWayPartitioning __MCMlevelKWayPartitioning
/* mkwayfmh.c */
#define MCRandom_KWayEdgeRefineHorizontal __MCRandom_KWayEdgeRefineHorizontal
#define MCGreedy_KWayEdgeBalanceHorizontal __MCGreedy_KWayEdgeBalanceHorizontal
#define AreAllHVwgtsBelow __AreAllHVwgtsBelow
#define AreAllHVwgtsAbove __AreAllHVwgtsAbove
#define ComputeHKWayLoadImbalance __ComputeHKWayLoadImbalance
#define MocIsHBalanced __MocIsHBalanced
#define IsHBalanceBetterFT __IsHBalanceBetterFT
#define IsHBalanceBetterTT __IsHBalanceBetterTT
/* mkwayrefine.c */
#define MocRefineKWayHorizontal __MocRefineKWayHorizontal
#define MocAllocateKWayPartitionMemory __MocAllocateKWayPartitionMemory
#define MocComputeKWayPartitionParams __MocComputeKWayPartitionParams
#define MocProjectKWayPartition __MocProjectKWayPartition
#define MocComputeKWayBalanceBoundary __MocComputeKWayBalanceBoundary
/* mmatch.c */
#define MCMatch_RM __MCMatch_RM
#define MCMatch_HEM __MCMatch_HEM
#define MCMatch_SHEM __MCMatch_SHEM
#define MCMatch_SHEBM __MCMatch_SHEBM
#define MCMatch_SBHEM __MCMatch_SBHEM
#define BetterVBalance __BetterVBalance
#define AreAllVwgtsBelowFast __AreAllVwgtsBelowFast
/* mmd.c */
#define genmmd __genmmd
#define mmdelm __mmdelm
#define mmdint __mmdint
#define mmdnum __mmdnum
#define mmdupd __mmdupd
/* mpmetis.c */
#define MCMlevelRecursiveBisection __MCMlevelRecursiveBisection
#define MCHMlevelRecursiveBisection __MCHMlevelRecursiveBisection
#define MCMlevelEdgeBisection __MCMlevelEdgeBisection
#define MCHMlevelEdgeBisection __MCHMlevelEdgeBisection
/* mrefine.c */
#define MocRefine2Way __MocRefine2Way
#define MocAllocate2WayPartitionMemory __MocAllocate2WayPartitionMemory
#define MocCompute2WayPartitionParams __MocCompute2WayPartitionParams
#define MocProject2WayPartition __MocProject2WayPartition
/* mrefine2.c */
#define MocRefine2Way2 __MocRefine2Way2
/* mutil.c */
#define AreAllVwgtsBelow __AreAllVwgtsBelow
#define AreAnyVwgtsBelow __AreAnyVwgtsBelow
#define AreAllVwgtsAbove __AreAllVwgtsAbove
#define ComputeLoadImbalance __ComputeLoadImbalance
#define AreAllBelow __AreAllBelow
/* myqsort.c */
#define iidxsort __iidxsort
#define iintsort __iintsort
#define ikeysort __ikeysort
#define ikeyvalsort __ikeyvalsort
/* ometis.c */
#define MlevelNestedDissection __MlevelNestedDissection
#define MlevelNestedDissectionCC __MlevelNestedDissectionCC
#define MlevelNodeBisectionMultiple __MlevelNodeBisectionMultiple
#define MlevelNodeBisection __MlevelNodeBisection
#define SplitGraphOrder __SplitGraphOrder
#define MMDOrder __MMDOrder
#define SplitGraphOrderCC __SplitGraphOrderCC
/* parmetis.c */
#define MlevelNestedDissectionP __MlevelNestedDissectionP
#define MCMlevelRecursiveBisection2 __MCMlevelRecursiveBisection2
/* pmetis.c */
#define MlevelRecursiveBisection __MlevelRecursiveBisection
#define MlevelEdgeBisection __MlevelEdgeBisection
#define SplitGraphPart __SplitGraphPart
#define SetUpSplitGraph __SetUpSplitGraph
/* pqueue.c */
#define PQueueInit __PQueueInit
#define PQueueReset __PQueueReset
#define PQueueFree __PQueueFree
#define PQueueInsert __PQueueInsert
#define PQueueDelete __PQueueDelete
#define PQueueUpdate __PQueueUpdate
#define PQueueUpdateUp __PQueueUpdateUp
#define PQueueGetMax __PQueueGetMax
#define PQueueSeeMax __PQueueSeeMax
#define CheckHeap __CheckHeap
/* refine.c */
#define Refine2Way __Refine2Way
#define Allocate2WayPartitionMemory __Allocate2WayPartitionMemory
#define Compute2WayPartitionParams __Compute2WayPartitionParams
#define Project2WayPartition __Project2WayPartition
/* separator.c */
#define ConstructSeparator __ConstructSeparator
#define ConstructMinCoverSeparator0 __ConstructMinCoverSeparator0
#define ConstructMinCoverSeparator __ConstructMinCoverSeparator
/* sfm.c */
#define FM_2WayNodeRefine __FM_2WayNodeRefine
#define FM_2WayNodeRefineEqWgt __FM_2WayNodeRefineEqWgt
#define FM_2WayNodeRefine_OneSided __FM_2WayNodeRefine_OneSided
#define FM_2WayNodeBalance __FM_2WayNodeBalance
#define ComputeMaxNodeGain __ComputeMaxNodeGain
/* srefine.c */
#define Refine2WayNode __Refine2WayNode
#define Allocate2WayNodePartitionMemory __Allocate2WayNodePartitionMemory
#define Compute2WayNodePartitionParams __Compute2WayNodePartitionParams
#define Project2WayNodePartition __Project2WayNodePartition
/* stat.c */
#define ComputePartitionInfo __ComputePartitionInfo
#define ComputePartitionBalance __ComputePartitionBalance
#define ComputeElementBalance __ComputeElementBalance
#define Moc_ComputePartitionBalance __Moc_ComputePartitionBalance
/* subdomains.c */
#define Random_KWayEdgeRefineMConn __Random_KWayEdgeRefineMConn
#define Greedy_KWayEdgeBalanceMConn __Greedy_KWayEdgeBalanceMConn
#define PrintSubDomainGraph __PrintSubDomainGraph
#define ComputeSubDomainGraph __ComputeSubDomainGraph
#define EliminateSubDomainEdges __EliminateSubDomainEdges
#define MoveGroupMConn __MoveGroupMConn
#define EliminateComponents __EliminateComponents
#define MoveGroup __MoveGroup
/* timing.c */
#define InitTimers __InitTimers
#define PrintTimers __PrintTimers
#define seconds __seconds
/* util.c */
#define errexit __errexit
#define GKfree __GKfree
#ifndef DMALLOC
#define imalloc __imalloc
#define idxmalloc __idxmalloc
#define fmalloc __fmalloc
#define ismalloc __ismalloc
#define idxsmalloc __idxsmalloc
#define GKmalloc __GKmalloc
#endif
#define iset __iset
#define idxset __idxset
#define sset __sset
#define iamax __iamax
#define idxamax __idxamax
#define idxamax_strd __idxamax_strd
#define samax __samax
#define samax2 __samax2
#define idxamin __idxamin
#define samin __samin
#define idxsum __idxsum
#define idxsum_strd __idxsum_strd
#define idxadd __idxadd
#define charsum __charsum
#define isum __isum
#define ssum __ssum
#define ssum_strd __ssum_strd
#define sscale __sscale
#define snorm2 __snorm2
#define sdot __sdot
#define saxpy __saxpy
#define RandomPermute __RandomPermute
#define ispow2 __ispow2
#define InitRandom __InitRandom
#define log2Int __log2Int

View File

@ -0,0 +1,284 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* separator.c
*
* This file contains code for separator extraction
*
* Started 8/1/97
* George
*
* $Id: separator.c,v 1.1 2003/07/16 15:55:17 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function takes a bisection and constructs a minimum weight vertex
* separator out of it. It uses the node-based separator refinement for it.
**************************************************************************/
void ConstructSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor)
{
int i, j, k, nvtxs, nbnd;
idxtype *xadj, *where, *bndind;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
nbnd = graph->nbnd;
bndind = graph->bndind;
where = idxcopy(nvtxs, graph->where, idxwspacemalloc(ctrl, nvtxs));
/* Put the nodes in the boundary into the separator */
for (i=0; i<nbnd; i++) {
j = bndind[i];
if (xadj[j+1]-xadj[j] > 0) /* Ignore islands */
where[j] = 2;
}
GKfree(&graph->rdata, LTERM);
Allocate2WayNodePartitionMemory(ctrl, graph);
idxcopy(nvtxs, where, graph->where);
idxwspacefree(ctrl, nvtxs);
ASSERT(IsSeparable(graph));
Compute2WayNodePartitionParams(ctrl, graph);
ASSERT(CheckNodePartitionParams(graph));
FM_2WayNodeRefine(ctrl, graph, ubfactor, 8);
ASSERT(IsSeparable(graph));
}
/*************************************************************************
* This function takes a bisection and constructs a minimum weight vertex
* separator out of it. It uses an unweighted minimum-cover algorithm
* followed by node-based separator refinement.
**************************************************************************/
void ConstructMinCoverSeparator0(CtrlType *ctrl, GraphType *graph, float ubfactor)
{
int i, ii, j, jj, k, l, nvtxs, nbnd, bnvtxs[3], bnedges[2], csize;
idxtype *xadj, *adjncy, *bxadj, *badjncy;
idxtype *where, *bndind, *bndptr, *vmap, *ivmap, *cover;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
nbnd = graph->nbnd;
bndind = graph->bndind;
bndptr = graph->bndptr;
where = graph->where;
vmap = idxwspacemalloc(ctrl, nvtxs);
ivmap = idxwspacemalloc(ctrl, nbnd);
cover = idxwspacemalloc(ctrl, nbnd);
if (nbnd > 0) {
/* Go through the boundary and determine the sizes of the bipartite graph */
bnvtxs[0] = bnvtxs[1] = bnedges[0] = bnedges[1] = 0;
for (i=0; i<nbnd; i++) {
j = bndind[i];
k = where[j];
if (xadj[j+1]-xadj[j] > 0) {
bnvtxs[k]++;
bnedges[k] += xadj[j+1]-xadj[j];
}
}
bnvtxs[2] = bnvtxs[0]+bnvtxs[1];
bnvtxs[1] = bnvtxs[0];
bnvtxs[0] = 0;
bxadj = idxmalloc(bnvtxs[2]+1, "ConstructMinCoverSeparator: bxadj");
badjncy = idxmalloc(bnedges[0]+bnedges[1]+1, "ConstructMinCoverSeparator: badjncy");
/* Construct the ivmap and vmap */
ASSERT(idxset(nvtxs, -1, vmap) == vmap);
for (i=0; i<nbnd; i++) {
j = bndind[i];
k = where[j];
if (xadj[j+1]-xadj[j] > 0) {
vmap[j] = bnvtxs[k];
ivmap[bnvtxs[k]++] = j;
}
}
/* OK, go through and put the vertices of each part starting from 0 */
bnvtxs[1] = bnvtxs[0];
bnvtxs[0] = 0;
bxadj[0] = l = 0;
for (k=0; k<2; k++) {
for (ii=0; ii<nbnd; ii++) {
i = bndind[ii];
if (where[i] == k && xadj[i] < xadj[i+1]) {
for (j=xadj[i]; j<xadj[i+1]; j++) {
jj = adjncy[j];
if (where[jj] != k) {
ASSERT(bndptr[jj] != -1);
ASSERTP(vmap[jj] != -1, ("%d %d %d\n", jj, vmap[jj], graph->bndptr[jj]));
badjncy[l++] = vmap[jj];
}
}
bxadj[++bnvtxs[k]] = l;
}
}
}
ASSERT(l <= bnedges[0]+bnedges[1]);
MinCover(bxadj, badjncy, bnvtxs[0], bnvtxs[1], cover, &csize);
IFSET(ctrl->dbglvl, DBG_SEPINFO,
printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, bnvtxs[0], bnvtxs[1]-bnvtxs[0], csize));
for (i=0; i<csize; i++) {
j = ivmap[cover[i]];
where[j] = 2;
}
GKfree(&bxadj, &badjncy, LTERM);
for (i=0; i<nbnd; i++)
bndptr[bndind[i]] = -1;
for (nbnd=i=0; i<nvtxs; i++) {
if (where[i] == 2) {
bndind[nbnd] = i;
bndptr[i] = nbnd++;
}
}
}
else {
IFSET(ctrl->dbglvl, DBG_SEPINFO,
printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, 0, 0, 0));
}
idxwspacefree(ctrl, nvtxs);
idxwspacefree(ctrl, graph->nbnd);
idxwspacefree(ctrl, graph->nbnd);
graph->nbnd = nbnd;
ASSERT(IsSeparable(graph));
}
/*************************************************************************
* This function takes a bisection and constructs a minimum weight vertex
* separator out of it. It uses an unweighted minimum-cover algorithm
* followed by node-based separator refinement.
**************************************************************************/
void ConstructMinCoverSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor)
{
int i, ii, j, jj, k, l, nvtxs, nbnd, bnvtxs[3], bnedges[2], csize;
idxtype *xadj, *adjncy, *bxadj, *badjncy;
idxtype *where, *bndind, *bndptr, *vmap, *ivmap, *cover;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
adjncy = graph->adjncy;
nbnd = graph->nbnd;
bndind = graph->bndind;
bndptr = graph->bndptr;
where = graph->where;
vmap = idxwspacemalloc(ctrl, nvtxs);
ivmap = idxwspacemalloc(ctrl, nbnd);
cover = idxwspacemalloc(ctrl, nbnd);
if (nbnd > 0) {
/* Go through the boundary and determine the sizes of the bipartite graph */
bnvtxs[0] = bnvtxs[1] = bnedges[0] = bnedges[1] = 0;
for (i=0; i<nbnd; i++) {
j = bndind[i];
k = where[j];
if (xadj[j+1]-xadj[j] > 0) {
bnvtxs[k]++;
bnedges[k] += xadj[j+1]-xadj[j];
}
}
bnvtxs[2] = bnvtxs[0]+bnvtxs[1];
bnvtxs[1] = bnvtxs[0];
bnvtxs[0] = 0;
bxadj = idxmalloc(bnvtxs[2]+1, "ConstructMinCoverSeparator: bxadj");
badjncy = idxmalloc(bnedges[0]+bnedges[1]+1, "ConstructMinCoverSeparator: badjncy");
/* Construct the ivmap and vmap */
ASSERT(idxset(nvtxs, -1, vmap) == vmap);
for (i=0; i<nbnd; i++) {
j = bndind[i];
k = where[j];
if (xadj[j+1]-xadj[j] > 0) {
vmap[j] = bnvtxs[k];
ivmap[bnvtxs[k]++] = j;
}
}
/* OK, go through and put the vertices of each part starting from 0 */
bnvtxs[1] = bnvtxs[0];
bnvtxs[0] = 0;
bxadj[0] = l = 0;
for (k=0; k<2; k++) {
for (ii=0; ii<nbnd; ii++) {
i = bndind[ii];
if (where[i] == k && xadj[i] < xadj[i+1]) {
for (j=xadj[i]; j<xadj[i+1]; j++) {
jj = adjncy[j];
if (where[jj] != k) {
ASSERT(bndptr[jj] != -1);
ASSERTP(vmap[jj] != -1, ("%d %d %d\n", jj, vmap[jj], graph->bndptr[jj]));
badjncy[l++] = vmap[jj];
}
}
bxadj[++bnvtxs[k]] = l;
}
}
}
ASSERT(l <= bnedges[0]+bnedges[1]);
MinCover(bxadj, badjncy, bnvtxs[0], bnvtxs[1], cover, &csize);
IFSET(ctrl->dbglvl, DBG_SEPINFO,
printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, bnvtxs[0], bnvtxs[1]-bnvtxs[0], csize));
for (i=0; i<csize; i++) {
j = ivmap[cover[i]];
where[j] = 2;
}
GKfree(&bxadj, &badjncy, LTERM);
}
else {
IFSET(ctrl->dbglvl, DBG_SEPINFO,
printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, 0, 0, 0));
}
/* Prepare to refine the vertex separator */
idxcopy(nvtxs, graph->where, vmap);
GKfree(&graph->rdata, LTERM);
Allocate2WayNodePartitionMemory(ctrl, graph);
idxcopy(nvtxs, vmap, graph->where);
idxwspacefree(ctrl, nvtxs+2*graph->nbnd);
Compute2WayNodePartitionParams(ctrl, graph);
ASSERT(CheckNodePartitionParams(graph));
FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 6);
ASSERT(IsSeparable(graph));
}

View File

@ -0,0 +1,169 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* srefine.c
*
* This file contains code for the separator refinement algortihms
*
* Started 8/1/97
* George
*
* $Id: srefine.c,v 1.1 2003/07/16 15:55:18 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function is the entry point of the separator refinement
**************************************************************************/
void Refine2WayNode(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float ubfactor)
{
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
for (;;) {
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
if (ctrl->RType != 15)
FM_2WayNodeBalance(ctrl, graph, ubfactor);
switch (ctrl->RType) {
case 1:
FM_2WayNodeRefine(ctrl, graph, ubfactor, 8);
break;
case 2:
FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8);
break;
case 3:
FM_2WayNodeRefine(ctrl, graph, ubfactor, 8);
FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8);
break;
case 4:
FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8);
FM_2WayNodeRefine(ctrl, graph, ubfactor, 8);
break;
case 5:
FM_2WayNodeRefineEqWgt(ctrl, graph, 8);
break;
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
if (graph == orggraph)
break;
graph = graph->finer;
IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
Project2WayNodePartition(ctrl, graph);
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
}
IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
}
/*************************************************************************
* This function allocates memory for 2-way edge refinement
**************************************************************************/
void Allocate2WayNodePartitionMemory(CtrlType *ctrl, GraphType *graph)
{
int nvtxs, pad64;
nvtxs = graph->nvtxs;
pad64 = (3*nvtxs+3)%2;
graph->rdata = idxmalloc(3*nvtxs+3+(sizeof(NRInfoType)/sizeof(idxtype))*nvtxs+pad64, "Allocate2WayPartitionMemory: rdata");
graph->pwgts = graph->rdata;
graph->where = graph->rdata + 3;
graph->bndptr = graph->rdata + nvtxs + 3;
graph->bndind = graph->rdata + 2*nvtxs + 3;
graph->nrinfo = (NRInfoType *)(graph->rdata + 3*nvtxs + 3 + pad64);
}
/*************************************************************************
* This function computes the initial id/ed
**************************************************************************/
void Compute2WayNodePartitionParams(CtrlType *ctrl, GraphType *graph)
{
int i, j, k, l, nvtxs, nbnd;
idxtype *xadj, *adjncy, *adjwgt, *vwgt;
idxtype *where, *pwgts, *bndind, *bndptr, *edegrees;
NRInfoType *rinfo;
int me, other;
nvtxs = graph->nvtxs;
xadj = graph->xadj;
vwgt = graph->vwgt;
adjncy = graph->adjncy;
adjwgt = graph->adjwgt;
where = graph->where;
rinfo = graph->nrinfo;
pwgts = idxset(3, 0, graph->pwgts);
bndind = graph->bndind;
bndptr = idxset(nvtxs, -1, graph->bndptr);
/*------------------------------------------------------------
/ Compute now the separator external degrees
/------------------------------------------------------------*/
nbnd = 0;
for (i=0; i<nvtxs; i++) {
me = where[i];
pwgts[me] += vwgt[i];
ASSERT(me >=0 && me <= 2);
if (me == 2) { /* If it is on the separator do some computations */
BNDInsert(nbnd, bndind, bndptr, i);
edegrees = rinfo[i].edegrees;
edegrees[0] = edegrees[1] = 0;
for (j=xadj[i]; j<xadj[i+1]; j++) {
other = where[adjncy[j]];
if (other != 2)
edegrees[other] += vwgt[adjncy[j]];
}
}
}
ASSERT(CheckNodeBnd(graph, nbnd));
graph->mincut = pwgts[2];
graph->nbnd = nbnd;
}
/*************************************************************************
* This function computes the initial id/ed
**************************************************************************/
void Project2WayNodePartition(CtrlType *ctrl, GraphType *graph)
{
int i, j, nvtxs;
idxtype *cmap, *where, *cwhere;
GraphType *cgraph;
cgraph = graph->coarser;
cwhere = cgraph->where;
nvtxs = graph->nvtxs;
cmap = graph->cmap;
Allocate2WayNodePartitionMemory(ctrl, graph);
where = graph->where;
/* Project the partition */
for (i=0; i<nvtxs; i++) {
where[i] = cwhere[cmap[i]];
ASSERTP(where[i] >= 0 && where[i] <= 2, ("%d %d %d %d\n", i, cmap[i], where[i], cwhere[cmap[i]]));
}
FreeGraph(graph->coarser);
graph->coarser = NULL;
Compute2WayNodePartitionParams(ctrl, graph);
}

View File

@ -0,0 +1,316 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* stat.c
*
* This file computes various statistics
*
* Started 7/25/97
* George
*
* $Id: stat.c,v 1.2 2003/07/24 18:39:12 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function computes cuts and balance information
**************************************************************************/
void ComputePartitionInfo(GraphType *graph, int nparts, idxtype *where)
{
int i, j, k, nvtxs, ncon, mustfree=0;
idxtype *xadj, *adjncy, *vwgt, *adjwgt, *kpwgts, *tmpptr;
idxtype *padjncy, *padjwgt, *padjcut;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
adjncy = graph->adjncy;
vwgt = graph->vwgt;
adjwgt = graph->adjwgt;
if (vwgt == NULL) {
vwgt = graph->vwgt = idxsmalloc(nvtxs, 1, "vwgt");
mustfree = 1;
}
if (adjwgt == NULL) {
adjwgt = graph->adjwgt = idxsmalloc(xadj[nvtxs], 1, "adjwgt");
mustfree += 2;
}
printf("%d-way Cut: %5d, Vol: %5d, ", nparts, ComputeCut(graph, where), ComputeVolume(graph, where));
/* Compute balance information */
kpwgts = idxsmalloc(ncon*nparts, 0, "ComputePartitionInfo: kpwgts");
for (i=0; i<nvtxs; i++) {
for (j=0; j<ncon; j++)
kpwgts[where[i]*ncon+j] += vwgt[i*ncon+j];
}
if (ncon == 1) {
printf("\tBalance: %5.3f out of %5.3f\n",
1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)),
1.0*nparts*vwgt[idxamax(nvtxs, vwgt)]/(1.0*idxsum(nparts, kpwgts)));
}
else {
printf("\tBalance:");
for (j=0; j<ncon; j++)
printf(" (%5.3f out of %5.3f)",
1.0*nparts*kpwgts[ncon*idxamax_strd(nparts, kpwgts+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)),
1.0*nparts*vwgt[ncon*idxamax_strd(nvtxs, vwgt+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)));
printf("\n");
}
/* Compute p-adjncy information */
padjncy = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjncy");
padjwgt = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt");
padjcut = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt");
idxset(nparts, 0, kpwgts);
for (i=0; i<nvtxs; i++) {
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (where[i] != where[adjncy[j]]) {
padjncy[where[i]*nparts+where[adjncy[j]]] = 1;
padjcut[where[i]*nparts+where[adjncy[j]]] += adjwgt[j];
if (kpwgts[where[adjncy[j]]] == 0) {
padjwgt[where[i]*nparts+where[adjncy[j]]]++;
kpwgts[where[adjncy[j]]] = 1;
}
}
}
for (j=xadj[i]; j<xadj[i+1]; j++)
kpwgts[where[adjncy[j]]] = 0;
}
for (i=0; i<nparts; i++)
kpwgts[i] = idxsum(nparts, padjncy+i*nparts);
printf("Min/Max/Avg/Bal # of adjacent subdomains: %5d %5d %5.2f %7.3f\n",
kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)],
1.0*idxsum(nparts, kpwgts)/(1.0*nparts),
1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)));
for (i=0; i<nparts; i++)
kpwgts[i] = idxsum(nparts, padjcut+i*nparts);
printf("Min/Max/Avg/Bal # of adjacent subdomain cuts: %5d %5d %5d %7.3f\n",
kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)));
for (i=0; i<nparts; i++)
kpwgts[i] = idxsum(nparts, padjwgt+i*nparts);
printf("Min/Max/Avg/Bal/Frac # of interface nodes: %5d %5d %5d %7.3f %7.3f\n",
kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), 1.0*idxsum(nparts, kpwgts)/(1.0*nvtxs));
tmpptr = graph->where;
graph->where = where;
for (i=0; i<nparts; i++)
IsConnectedSubdomain(NULL, graph, i, 1);
graph->where = tmpptr;
if (mustfree == 1 || mustfree == 3) {
free(vwgt);
graph->vwgt = NULL;
}
if (mustfree == 2 || mustfree == 3) {
free(adjwgt);
graph->adjwgt = NULL;
}
GKfree(&kpwgts, &padjncy, &padjwgt, &padjcut, LTERM);
}
/*************************************************************************
* This function computes cuts and balance information
**************************************************************************/
void ComputePartitionInfoBipartite(GraphType *graph, int nparts, idxtype *where)
{
int i, j, k, nvtxs, ncon, mustfree=0;
idxtype *xadj, *adjncy, *vwgt, *vsize, *adjwgt, *kpwgts, *tmpptr;
idxtype *padjncy, *padjwgt, *padjcut;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
xadj = graph->xadj;
adjncy = graph->adjncy;
vwgt = graph->vwgt;
vsize = graph->vsize;
adjwgt = graph->adjwgt;
if (vwgt == NULL) {
vwgt = graph->vwgt = idxsmalloc(nvtxs, 1, "vwgt");
mustfree = 1;
}
if (adjwgt == NULL) {
adjwgt = graph->adjwgt = idxsmalloc(xadj[nvtxs], 1, "adjwgt");
mustfree += 2;
}
printf("%d-way Cut: %5d, Vol: %5d, ", nparts, ComputeCut(graph, where), ComputeVolume(graph, where));
/* Compute balance information */
kpwgts = idxsmalloc(ncon*nparts, 0, "ComputePartitionInfo: kpwgts");
for (i=0; i<nvtxs; i++) {
for (j=0; j<ncon; j++)
kpwgts[where[i]*ncon+j] += vwgt[i*ncon+j];
}
if (ncon == 1) {
printf("\tBalance: %5.3f out of %5.3f\n",
1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)),
1.0*nparts*vwgt[idxamax(nvtxs, vwgt)]/(1.0*idxsum(nparts, kpwgts)));
}
else {
printf("\tBalance:");
for (j=0; j<ncon; j++)
printf(" (%5.3f out of %5.3f)",
1.0*nparts*kpwgts[ncon*idxamax_strd(nparts, kpwgts+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)),
1.0*nparts*vwgt[ncon*idxamax_strd(nvtxs, vwgt+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)));
printf("\n");
}
/* Compute p-adjncy information */
padjncy = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjncy");
padjwgt = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt");
padjcut = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt");
idxset(nparts, 0, kpwgts);
for (i=0; i<nvtxs; i++) {
for (j=xadj[i]; j<xadj[i+1]; j++) {
if (where[i] != where[adjncy[j]]) {
padjncy[where[i]*nparts+where[adjncy[j]]] = 1;
padjcut[where[i]*nparts+where[adjncy[j]]] += adjwgt[j];
if (kpwgts[where[adjncy[j]]] == 0) {
padjwgt[where[i]*nparts+where[adjncy[j]]] += vsize[i];
kpwgts[where[adjncy[j]]] = 1;
}
}
}
for (j=xadj[i]; j<xadj[i+1]; j++)
kpwgts[where[adjncy[j]]] = 0;
}
for (i=0; i<nparts; i++)
kpwgts[i] = idxsum(nparts, padjncy+i*nparts);
printf("Min/Max/Avg/Bal # of adjacent subdomains: %5d %5d %5d %7.3f\n",
kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)));
for (i=0; i<nparts; i++)
kpwgts[i] = idxsum(nparts, padjcut+i*nparts);
printf("Min/Max/Avg/Bal # of adjacent subdomain cuts: %5d %5d %5d %7.3f\n",
kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)));
for (i=0; i<nparts; i++)
kpwgts[i] = idxsum(nparts, padjwgt+i*nparts);
printf("Min/Max/Avg/Bal/Frac # of interface nodes: %5d %5d %5d %7.3f %7.3f\n",
kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), 1.0*idxsum(nparts, kpwgts)/(1.0*nvtxs));
if (mustfree == 1 || mustfree == 3) {
free(vwgt);
graph->vwgt = NULL;
}
if (mustfree == 2 || mustfree == 3) {
free(adjwgt);
graph->adjwgt = NULL;
}
GKfree(&kpwgts, &padjncy, &padjwgt, &padjcut, LTERM);
}
/*************************************************************************
* This function computes the balance of the partitioning
**************************************************************************/
void ComputePartitionBalance(GraphType *graph, int nparts, idxtype *where, float *ubvec)
{
int i, j, nvtxs, ncon;
idxtype *kpwgts, *vwgt;
float balance;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
vwgt = graph->vwgt;
kpwgts = idxsmalloc(nparts, 0, "ComputePartitionInfo: kpwgts");
if (vwgt == NULL && ncon == 1) {
for (i=0; i<nvtxs; i++)
kpwgts[where[i]]++;
ubvec[0] = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*nvtxs);
}
else {
for (j=0; j<ncon; j++) {
idxset(nparts, 0, kpwgts);
for (i=0; i<graph->nvtxs; i++)
kpwgts[where[i]] += vwgt[i*ncon+j];
ubvec[j] = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts));
}
}
free(kpwgts);
}
/*************************************************************************
* This function computes the balance of the element partitioning
**************************************************************************/
float ComputeElementBalance(int ne, int nparts, idxtype *where)
{
int i;
idxtype *kpwgts;
float balance;
kpwgts = idxsmalloc(nparts, 0, "ComputeElementBalance: kpwgts");
for (i=0; i<ne; i++)
kpwgts[where[i]]++;
balance = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts));
free(kpwgts);
return balance;
}
/*************************************************************************
* This function computes the balance of the partitioning
**************************************************************************/
void Moc_ComputePartitionBalance(GraphType *graph, int nparts, idxtype *where, float *ubvec)
{
int i, j, nvtxs, ncon;
float *kpwgts, *nvwgt;
float balance;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
nvwgt = graph->nvwgt;
kpwgts = fmalloc(nparts, "ComputePartitionInfo: kpwgts");
for (j=0; j<ncon; j++) {
sset(nparts, 0.0, kpwgts);
for (i=0; i<graph->nvtxs; i++)
kpwgts[where[i]] += nvwgt[i*ncon+j];
ubvec[j] = (float)nparts*kpwgts[samax(nparts, kpwgts)]/ssum(nparts, kpwgts);
}
free(kpwgts);
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* stat.c
*
* This file computes various statistics
*
* Started 7/25/97
* George
*
* $Id: stats.c,v 1.1 2003/03/13 06:33:20 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function computes the balance of the partitioning
**************************************************************************/
void Moc_ComputePartitionBalance(GraphType *graph, int nparts, idxtype *where, float *ubvec)
{
int i, j, nvtxs, ncon;
float *kpwgts, *nvwgt;
float balance;
nvtxs = graph->nvtxs;
ncon = graph->ncon;
nvwgt = graph->nvwgt;
kpwgts = fmalloc(nparts, "ComputePartitionInfo: kpwgts");
for (j=0; j<ncon; j++) {
sset(nparts, 0.0, kpwgts);
for (i=0; i<graph->nvtxs; i++)
kpwgts[where[i]] += nvwgt[i*ncon+j];
ubvec[j] = (float)nparts*kpwgts[samax(nparts, kpwgts)]/ssum(nparts, kpwgts);
}
free(kpwgts);
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* stdheaders.h
*
* This file includes all necessary header files
*
* Started 8/27/94
* George
*
* $Id: stdheaders.h,v 1.2 2003/07/25 14:31:45 karypis Exp $
*/
#include <stdio.h>
#ifdef __STDC__
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdarg.h>
#include <time.h>

View File

@ -0,0 +1,253 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* struct.h
*
* This file contains data structures for ILU routines.
*
* Started 9/26/95
* George
*
* $Id: struct.h,v 1.2 2003/07/25 13:52:01 karypis Exp $
*/
#ifndef __parmetis_h__
/* Undefine the following #define in order to use short int as the idxtype */
#define IDXTYPE_INT
/* Indexes are as long as integers for now */
#ifdef IDXTYPE_INT
typedef int idxtype;
#else
typedef short idxtype;
#endif
#endif
#define MAXIDX (1<<8*sizeof(idxtype)-2)
/*************************************************************************
* The following data structure stores key-value pair
**************************************************************************/
struct KeyValueType {
idxtype key;
idxtype val;
};
typedef struct KeyValueType KeyValueType;
/*************************************************************************
* The following data structure will hold a node of a doubly-linked list.
**************************************************************************/
struct ListNodeType {
int id; /* The id value of the node */
struct ListNodeType *prev, *next; /* It's a doubly-linked list */
};
typedef struct ListNodeType ListNodeType;
/*************************************************************************
* The following data structure is used to store the buckets for the
* refinment algorithms
**************************************************************************/
struct PQueueType {
int type; /* The type of the representation used */
int nnodes;
int maxnodes;
int mustfree;
/* Linear array version of the data structures */
int pgainspan, ngainspan; /* plus and negative gain span */
int maxgain;
ListNodeType *nodes;
ListNodeType **buckets;
/* Heap version of the data structure */
KeyValueType *heap;
idxtype *locator;
};
typedef struct PQueueType PQueueType;
/*************************************************************************
* The following data structure stores an edge
**************************************************************************/
struct edegreedef {
idxtype pid;
idxtype ed;
};
typedef struct edegreedef EDegreeType;
/*************************************************************************
* The following data structure stores an edge for vol
**************************************************************************/
struct vedegreedef {
idxtype pid;
idxtype ed, ned;
idxtype gv;
};
typedef struct vedegreedef VEDegreeType;
/*************************************************************************
* This data structure holds various working space data
**************************************************************************/
struct workspacedef {
idxtype *core; /* Where pairs, indices, and degrees are coming from */
int maxcore, ccore;
EDegreeType *edegrees;
VEDegreeType *vedegrees;
int cdegree;
idxtype *auxcore; /* This points to the memory of the edegrees */
idxtype *pmat; /* An array of k^2 used for eliminating domain
connectivity in k-way refinement */
};
typedef struct workspacedef WorkSpaceType;
/*************************************************************************
* The following data structure holds information on degrees for k-way
* partition
**************************************************************************/
struct rinfodef {
int id, ed; /* ID/ED of nodes */
int ndegrees; /* The number of different ext-degrees */
EDegreeType *edegrees; /* List of edges */
};
typedef struct rinfodef RInfoType;
/*************************************************************************
* The following data structure holds information on degrees for k-way
* vol-based partition
**************************************************************************/
struct vrinfodef {
int id, ed, nid; /* ID/ED of nodes */
int gv; /* IV/EV of nodes */
int ndegrees; /* The number of different ext-degrees */
VEDegreeType *edegrees; /* List of edges */
};
typedef struct vrinfodef VRInfoType;
/*************************************************************************
* The following data structure holds information on degrees for k-way
* partition
**************************************************************************/
struct nrinfodef {
idxtype edegrees[2];
};
typedef struct nrinfodef NRInfoType;
/*************************************************************************
* This data structure holds the input graph
**************************************************************************/
struct graphdef {
idxtype *gdata, *rdata; /* Memory pools for graph and refinement data.
This is where memory is allocated and used
the rest of the fields in this structure */
int nvtxs, nedges; /* The # of vertices and edges in the graph */
idxtype *xadj; /* Pointers to the locally stored vertices */
idxtype *vwgt; /* Vertex weights */
idxtype *vsize; /* Vertex sizes for min-volume formulation */
idxtype *adjncy; /* Array that stores the adjacency lists of nvtxs */
idxtype *adjwgt; /* Array that stores the weights of the adjacency lists */
idxtype *adjwgtsum; /* The sum of the adjacency weight of each vertex */
idxtype *label;
idxtype *cmap;
/* Partition parameters */
int mincut, minvol;
idxtype *where, *pwgts;
int nbnd;
idxtype *bndptr, *bndind;
/* Bisection refinement parameters */
idxtype *id, *ed;
/* K-way refinement parameters */
RInfoType *rinfo;
/* K-way volume refinement parameters */
VRInfoType *vrinfo;
/* Node refinement information */
NRInfoType *nrinfo;
/* Additional info needed by the MOC routines */
int ncon; /* The # of constrains */
float *nvwgt; /* Normalized vertex weights */
float *npwgts; /* The normalized partition weights */
struct graphdef *coarser, *finer;
};
typedef struct graphdef GraphType;
/*************************************************************************
* The following data type implements a timer
**************************************************************************/
typedef double timer;
/*************************************************************************
* The following structure stores information used by Metis
**************************************************************************/
struct controldef {
int CoarsenTo; /* The # of vertices in the coarsest graph */
int dbglvl; /* Controls the debuging output of the program */
int CType; /* The type of coarsening */
int IType; /* The type of initial partitioning */
int RType; /* The type of refinement */
int maxvwgt; /* The maximum allowed weight for a vertex */
float nmaxvwgt; /* The maximum allowed weight for a vertex for each constrain */
int optype; /* Type of operation */
int pfactor; /* .1*prunning factor */
int nseps; /* The number of separators to be found during multiple bisections */
int oflags;
WorkSpaceType wspace; /* Work Space Informations */
/* Various Timers */
timer TotalTmr, InitPartTmr, MatchTmr, ContractTmr, CoarsenTmr, UncoarsenTmr,
SepTmr, RefTmr, ProjectTmr, SplitTmr, AuxTmr1, AuxTmr2, AuxTmr3, AuxTmr4, AuxTmr5, AuxTmr6;
};
typedef struct controldef CtrlType;
/*************************************************************************
* The following data structure stores max-partition weight info for
* Vertical MOC k-way refinement
**************************************************************************/
struct vpwgtdef {
float max[2][MAXNCON];
int imax[2][MAXNCON];
};
typedef struct vpwgtdef VPInfoType;

View File

@ -0,0 +1,74 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* timing.c
*
* This file contains routines that deal with timing Metis
*
* Started 7/24/97
* George
*
* $Id: timing.c,v 1.1 2003/07/16 15:55:20 karypis Exp $
*
*/
#include <metis.h>
/*************************************************************************
* This function clears the timers
**************************************************************************/
void InitTimers(CtrlType *ctrl)
{
cleartimer(ctrl->TotalTmr);
cleartimer(ctrl->InitPartTmr);
cleartimer(ctrl->MatchTmr);
cleartimer(ctrl->ContractTmr);
cleartimer(ctrl->CoarsenTmr);
cleartimer(ctrl->UncoarsenTmr);
cleartimer(ctrl->RefTmr);
cleartimer(ctrl->ProjectTmr);
cleartimer(ctrl->SplitTmr);
cleartimer(ctrl->SepTmr);
cleartimer(ctrl->AuxTmr1);
cleartimer(ctrl->AuxTmr2);
cleartimer(ctrl->AuxTmr3);
cleartimer(ctrl->AuxTmr4);
cleartimer(ctrl->AuxTmr5);
cleartimer(ctrl->AuxTmr6);
}
/*************************************************************************
* This function prints the various timers
**************************************************************************/
void PrintTimers(CtrlType *ctrl)
{
printf("\nTiming Information -------------------------------------------------");
printf("\n Multilevel: \t\t %7.3f", gettimer(ctrl->TotalTmr));
printf("\n Coarsening: \t\t %7.3f", gettimer(ctrl->CoarsenTmr));
printf("\n Matching: \t\t\t %7.3f", gettimer(ctrl->MatchTmr));
printf("\n Contract: \t\t\t %7.3f", gettimer(ctrl->ContractTmr));
printf("\n Initial Partition: \t %7.3f", gettimer(ctrl->InitPartTmr));
printf("\n Construct Separator: \t %7.3f", gettimer(ctrl->SepTmr));
printf("\n Uncoarsening: \t\t %7.3f", gettimer(ctrl->UncoarsenTmr));
printf("\n Refinement: \t\t\t %7.3f", gettimer(ctrl->RefTmr));
printf("\n Projection: \t\t\t %7.3f", gettimer(ctrl->ProjectTmr));
printf("\n Splitting: \t\t %7.3f", gettimer(ctrl->SplitTmr));
printf("\n AUX1: \t\t %7.3f", gettimer(ctrl->AuxTmr1));
printf("\n AUX2: \t\t %7.3f", gettimer(ctrl->AuxTmr2));
printf("\n AUX3: \t\t %7.3f", gettimer(ctrl->AuxTmr3));
printf("\n********************************************************************\n");
}
/*************************************************************************
* This function returns the seconds
**************************************************************************/
double seconds(void)
{
return((double) clock()/CLOCKS_PER_SEC);
}

View File

@ -0,0 +1,511 @@
/*
* Copyright 1997, Regents of the University of Minnesota
*
* util.c
*
* This function contains various utility routines
*
* Started 9/28/95
* George
*
* $Id: util.c,v 1.2 2003/07/21 18:53:41 karypis Exp $
*/
#include <metis.h>
/*************************************************************************
* This function prints an error message and exits
**************************************************************************/
void errexit(char *f_str,...)
{
va_list argp;
char out1[256], out2[256];
va_start(argp, f_str);
vsprintf(out1, f_str, argp);
va_end(argp);
sprintf(out2, "Error! %s", out1);
fprintf(stdout, out2);
fflush(stdout);
abort();
}
#ifndef DMALLOC
/*************************************************************************
* The following function allocates an array of integers
**************************************************************************/
int *imalloc(int n, char *msg)
{
if (n == 0)
return NULL;
return (int *)GKmalloc(sizeof(int)*n, msg);
}
/*************************************************************************
* The following function allocates an array of integers
**************************************************************************/
idxtype *idxmalloc(int n, char *msg)
{
if (n == 0)
return NULL;
return (idxtype *)GKmalloc(sizeof(idxtype)*n, msg);
}
/*************************************************************************
* The following function allocates an array of float
**************************************************************************/
float *fmalloc(int n, char *msg)
{
if (n == 0)
return NULL;
return (float *)GKmalloc(sizeof(float)*n, msg);
}
/*************************************************************************
* The follwoing function allocates an array of integers
**************************************************************************/
int *ismalloc(int n, int ival, char *msg)
{
if (n == 0)
return NULL;
return iset(n, ival, (int *)GKmalloc(sizeof(int)*n, msg));
}
/*************************************************************************
* The follwoing function allocates an array of integers
**************************************************************************/
idxtype *idxsmalloc(int n, idxtype ival, char *msg)
{
if (n == 0)
return NULL;
return idxset(n, ival, (idxtype *)GKmalloc(sizeof(idxtype)*n, msg));
}
/*************************************************************************
* This function is my wrapper around malloc
**************************************************************************/
void *GKmalloc(int nbytes, char *msg)
{
void *ptr;
if (nbytes == 0)
return NULL;
ptr = (void *)malloc(nbytes);
if (ptr == NULL)
errexit("***Memory allocation failed for %s. Requested size: %d bytes", msg, nbytes);
return ptr;
}
#endif
/*************************************************************************
* This function is my wrapper around free, allows multiple pointers
**************************************************************************/
void GKfree(void **ptr1,...)
{
va_list plist;
void **ptr;
if (*ptr1 != NULL)
free(*ptr1);
*ptr1 = NULL;
va_start(plist, ptr1);
/* while ((int)(ptr = va_arg(plist, void **)) != -1) { */
while ((ptr = va_arg(plist, void **)) != LTERM) {
if (*ptr != NULL)
free(*ptr);
*ptr = NULL;
}
va_end(plist);
}
/*************************************************************************
* These functions set the values of a vector
**************************************************************************/
int *iset(int n, int val, int *x)
{
int i;
for (i=0; i<n; i++)
x[i] = val;
return x;
}
/*************************************************************************
* These functions set the values of a vector
**************************************************************************/
idxtype *idxset(int n, idxtype val, idxtype *x)
{
int i;
for (i=0; i<n; i++)
x[i] = val;
return x;
}
/*************************************************************************
* These functions set the values of a vector
**************************************************************************/
float *sset(int n, float val, float *x)
{
int i;
for (i=0; i<n; i++)
x[i] = val;
return x;
}
/*************************************************************************
* These functions return the index of the maximum element in a vector
**************************************************************************/
int iamax(int n, int *x)
{
int i, max=0;
for (i=1; i<n; i++)
max = (x[i] > x[max] ? i : max);
return max;
}
/*************************************************************************
* These functions return the index of the maximum element in a vector
**************************************************************************/
int idxamax(int n, idxtype *x)
{
int i, max=0;
for (i=1; i<n; i++)
max = (x[i] > x[max] ? i : max);
return max;
}
/*************************************************************************
* These functions return the index of the maximum element in a vector
**************************************************************************/
int idxamax_strd(int n, idxtype *x, int incx)
{
int i, max=0;
n *= incx;
for (i=incx; i<n; i+=incx)
max = (x[i] > x[max] ? i : max);
return max/incx;
}
/*************************************************************************
* These functions return the index of the maximum element in a vector
**************************************************************************/
int samax(int n, float *x)
{
int i, max=0;
for (i=1; i<n; i++)
max = (x[i] > x[max] ? i : max);
return max;
}
/*************************************************************************
* These functions return the index of the almost maximum element in a vector
**************************************************************************/
int samax2(int n, float *x)
{
int i, max1, max2;
if (x[0] > x[1]) {
max1 = 0;
max2 = 1;
}
else {
max1 = 1;
max2 = 0;
}
for (i=2; i<n; i++) {
if (x[i] > x[max1]) {
max2 = max1;
max1 = i;
}
else if (x[i] > x[max2])
max2 = i;
}
return max2;
}
/*************************************************************************
* These functions return the index of the minimum element in a vector
**************************************************************************/
int idxamin(int n, idxtype *x)
{
int i, min=0;
for (i=1; i<n; i++)
min = (x[i] < x[min] ? i : min);
return min;
}
/*************************************************************************
* These functions return the index of the minimum element in a vector
**************************************************************************/
int samin(int n, float *x)
{
int i, min=0;
for (i=1; i<n; i++)
min = (x[i] < x[min] ? i : min);
return min;
}
/*************************************************************************
* This function sums the entries in an array
**************************************************************************/
int idxsum(int n, idxtype *x)
{
int i, sum = 0;
for (i=0; i<n; i++)
sum += x[i];
return sum;
}
/*************************************************************************
* This function sums the entries in an array
**************************************************************************/
int idxsum_strd(int n, idxtype *x, int incx)
{
int i, sum = 0;
for (i=0; i<n; i++, x+=incx) {
sum += *x;
}
return sum;
}
/*************************************************************************
* This function sums the entries in an array
**************************************************************************/
void idxadd(int n, idxtype *x, idxtype *y)
{
for (n--; n>=0; n--)
y[n] += x[n];
}
/*************************************************************************
* This function sums the entries in an array
**************************************************************************/
int charsum(int n, char *x)
{
int i, sum = 0;
for (i=0; i<n; i++)
sum += x[i];
return sum;
}
/*************************************************************************
* This function sums the entries in an array
**************************************************************************/
int isum(int n, int *x)
{
int i, sum = 0;
for (i=0; i<n; i++)
sum += x[i];
return sum;
}
/*************************************************************************
* This function sums the entries in an array
**************************************************************************/
float ssum(int n, float *x)
{
int i;
float sum = 0.0;
for (i=0; i<n; i++)
sum += x[i];
return sum;
}
/*************************************************************************
* This function sums the entries in an array
**************************************************************************/
float ssum_strd(int n, float *x, int incx)
{
int i;
float sum = 0.0;
for (i=0; i<n; i++, x+=incx)
sum += *x;
return sum;
}
/*************************************************************************
* This function sums the entries in an array
**************************************************************************/
void sscale(int n, float alpha, float *x)
{
int i;
for (i=0; i<n; i++)
x[i] *= alpha;
}
/*************************************************************************
* This function computes a 2-norm
**************************************************************************/
float snorm2(int n, float *v)
{
int i;
float partial = 0;
for (i = 0; i<n; i++)
partial += v[i] * v[i];
return sqrt(partial);
}
/*************************************************************************
* This function computes a 2-norm
**************************************************************************/
float sdot(int n, float *x, float *y)
{
int i;
float partial = 0;
for (i = 0; i<n; i++)
partial += x[i] * y[i];
return partial;
}
/*************************************************************************
* This function computes a 2-norm
**************************************************************************/
void saxpy(int n, float alpha, float *x, int incx, float *y, int incy)
{
int i;
for (i=0; i<n; i++, x+=incx, y+=incy)
*y += alpha*(*x);
}
/*************************************************************************
* This file randomly permutes the contents of an array.
* flag == 0, don't initialize perm
* flag == 1, set p[i] = i
**************************************************************************/
void RandomPermute(int n, idxtype *p, int flag)
{
int i, u, v;
idxtype tmp;
if (flag == 1) {
for (i=0; i<n; i++)
p[i] = i;
}
if (n <= 4)
return;
for (i=0; i<n; i+=16) {
u = RandomInRange(n-4);
v = RandomInRange(n-4);
SWAP(p[v], p[u], tmp);
SWAP(p[v+1], p[u+1], tmp);
SWAP(p[v+2], p[u+2], tmp);
SWAP(p[v+3], p[u+3], tmp);
}
}
/*************************************************************************
* This function returns true if the a is a power of 2
**************************************************************************/
int ispow2(int a)
{
for (; a%2 != 1; a = a>>1);
return (a > 1 ? 0 : 1);
}
/*************************************************************************
* This function initializes the random number generator
**************************************************************************/
void InitRandom(int seed)
{
if (seed == -1)
srand(4321);
else
srand(seed);
}
/*************************************************************************
* This function returns the log2(x)
**************************************************************************/
int log2Int(int a)
{
int i;
for (i=1; a > 1; i++, a = a>>1);
return i-1;
}