mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
Creation of OpenFOAM-dev repository 15/04/2008
This commit is contained in:
@ -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
|
||||
@ -0,0 +1,4 @@
|
||||
include $(RULES)/mplib$(WM_MPLIB)
|
||||
|
||||
EXE_INC = $(PFLAGS) $(PINC)
|
||||
LIB_LIBS = $(PLIBS)
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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 */
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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]++;
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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); */
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
@ -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);
|
||||
|
||||
}
|
||||
@ -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"
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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 *);
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user