summaryrefslogtreecommitdiff
path: root/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib
diff options
context:
space:
mode:
Diffstat (limited to 'benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib')
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/Makefile45
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_checkgraph.c127
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_memory.c208
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_mfm.c341
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_mrefine.c219
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_parmetis.c155
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_stats.c44
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/balance.c278
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/bucketsort.c43
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/ccgraph.c599
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/checkgraph.c127
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/coarsen.c86
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/compress.c256
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/debug.c239
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/defs.h161
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/estmem.c157
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/fm.c194
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/fortran.c141
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/frename.c312
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/graph.c616
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/initpart.c425
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kmetis.c129
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kvmetis.c130
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayfm.c672
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayrefine.c392
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayvolfm.c1778
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayvolrefine.c468
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/macros.h138
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/match.c267
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mbalance.c260
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mbalance2.c328
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mcoarsen.c106
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/memory.c208
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mesh.c399
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/meshpart.c204
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/metis.h31
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mfm.c341
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mfm2.c349
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mincover.c259
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/minitpart.c358
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/minitpart2.c368
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkmetis.c124
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkwayfmh.c677
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkwayrefine.c296
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mmatch.c501
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mmd.c593
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mpmetis.c402
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mrefine.c219
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mrefine2.c55
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mutil.c101
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/myqsort.c547
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/ometis.c764
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/parmetis.c512
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/pmetis.c341
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/pqueue.c579
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/proto.h511
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/refine.c204
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/rename.h424
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/separator.c284
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/sfm.c1069
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/srefine.c169
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stat.c316
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stats.c44
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stdheaders.h26
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/struct.h253
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/subdomains.c1295
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/timing.c74
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/util.c511
68 files changed, 22849 insertions, 0 deletions
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/Makefile b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/Makefile
new file mode 100644
index 0000000..eafd97a
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/Makefile
@@ -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
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_checkgraph.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_checkgraph.c
new file mode 100644
index 0000000..aea0094
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_checkgraph.c
@@ -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);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_memory.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_memory.c
new file mode 100644
index 0000000..aa03b9d
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_memory.c
@@ -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);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_mfm.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_mfm.c
new file mode 100644
index 0000000..9f37848
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_mfm.c
@@ -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];
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_mrefine.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_mrefine.c
new file mode 100644
index 0000000..9cea995
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_mrefine.c
@@ -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;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_parmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_parmetis.c
new file mode 100644
index 0000000..bd97917
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_parmetis.c
@@ -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;
+
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_stats.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_stats.c
new file mode 100644
index 0000000..9e04b23
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/NEW_stats.c
@@ -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);
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/balance.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/balance.c
new file mode 100644
index 0000000..ac951da
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/balance.c
@@ -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);
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/bucketsort.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/bucketsort.c
new file mode 100644
index 0000000..14aa213
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/bucketsort.c
@@ -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);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/ccgraph.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/ccgraph.c
new file mode 100644
index 0000000..3485ab0
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/ccgraph.c
@@ -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;
+ }
+ }
+ }
+
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/checkgraph.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/checkgraph.c
new file mode 100644
index 0000000..0134ec1
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/checkgraph.c
@@ -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);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/coarsen.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/coarsen.c
new file mode 100644
index 0000000..15f06d3
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/coarsen.c
@@ -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;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/compress.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/compress.c
new file mode 100644
index 0000000..6b1cf13
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/compress.c
@@ -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);
+
+}
+
+
+
+
+
+
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/debug.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/debug.c
new file mode 100644
index 0000000..b71fe2f
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/debug.c
@@ -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;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/defs.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/defs.h
new file mode 100644
index 0000000..8df42c7
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/defs.h
@@ -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 */
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/estmem.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/estmem.c
new file mode 100644
index 0000000..82b9ac9
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/estmem.c
@@ -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;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/fm.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/fm.c
new file mode 100644
index 0000000..2fc08d2
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/fm.c
@@ -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);
+
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/fortran.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/fortran.c
new file mode 100644
index 0000000..46ebefd
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/fortran.c
@@ -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]++;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/frename.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/frename.c
new file mode 100644
index 0000000..5cde8b6
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/frename.c
@@ -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);
+}
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/graph.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/graph.c
new file mode 100644
index 0000000..9a93784
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/graph.c
@@ -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;
+}
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/initpart.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/initpart.c
new file mode 100644
index 0000000..075cfb9
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/initpart.c
@@ -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);
+}
+
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kmetis.c
new file mode 100644
index 0000000..87c3a59
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kmetis.c
@@ -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;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kvmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kvmetis.c
new file mode 100644
index 0000000..5bc0a67
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kvmetis.c
@@ -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;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayfm.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayfm.c
new file mode 100644
index 0000000..170dcf3
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayfm.c
@@ -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);
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayrefine.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayrefine.c
new file mode 100644
index 0000000..a6d58f7
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayrefine.c
@@ -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;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayvolfm.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayvolfm.c
new file mode 100644
index 0000000..4e1112d
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayvolfm.c
@@ -0,0 +1,1778 @@
+/*
+ * kwayvolfm.c
+ *
+ * This file contains code that implements the multilevel k-way refinement
+ *
+ * Started 7/8/98
+ * George
+ *
+ * $Id: kwayvolfm.c,v 1.2 2003/07/31 06:14:01 karypis Exp $
+ *
+ */
+
+#include <metis.h>
+
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void Random_KWayVolRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts,
+ float ubfactor, int npasses, int ffactor)
+{
+ int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain;
+ int from, me, to, oldcut, oldvol, vwgt;
+ idxtype *xadj, *adjncy, *adjwgt;
+ idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable;
+ VEDegreeType *myedegrees;
+ VRInfoType *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));
+
+ updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind");
+ marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker");
+ phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable");
+
+ 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("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d\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, graph->minvol));
+
+ for (pass=0; pass<npasses; pass++) {
+ ASSERT(ComputeCut(graph, where) == graph->mincut);
+
+ oldcut = graph->mincut;
+ oldvol = graph->minvol;
+
+ RandomPermute(graph->nbnd, perm, 1);
+ for (nmoves=iii=0; iii<graph->nbnd; iii++) {
+ ii = perm[iii];
+ if (ii >= graph->nbnd)
+ continue;
+ i = bndind[ii];
+ myrinfo = graph->vrinfo+i;
+
+ if (myrinfo->gv >= 0) { /* Total volume gain is too high */
+ from = where[i];
+ vwgt = graph->vwgt[i];
+
+ if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from])
+ continue; /* This cannot be moved! */
+
+ xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0);
+
+ myedegrees = myrinfo->edegrees;
+ myndegrees = myrinfo->ndegrees;
+
+ for (k=0; k<myndegrees; k++) {
+ to = myedegrees[k].pid;
+ if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*myedegrees[k].gv && xgain+myedegrees[k].gv >= 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 (pwgts[to]+vwgt > maxwgt[to])
+ continue;
+ if (myedegrees[j].gv > myedegrees[k].gv ||
+ (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed > myedegrees[k].ed) ||
+ (myedegrees[j].gv == myedegrees[k].gv && 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 (xgain+myedegrees[k].gv > 0 || myedegrees[k].ed-myrinfo->id > 0)
+ j = 1;
+ else if (myedegrees[k].ed-myrinfo->id == 0) {
+ if ((iii&5) == 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'
+ *======================================================================*/
+ INC_DEC(pwgts[to], pwgts[from], vwgt);
+ graph->mincut -= myedegrees[k].ed-myrinfo->id;
+ graph->minvol -= (xgain+myedegrees[k].gv);
+ where[i] = to;
+
+ IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n",
+ i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol));
+
+ KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind);
+
+ nmoves++;
+
+ /* CheckVolKWayPartitionParams(ctrl, graph, nparts); */
+ }
+ }
+
+ 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,
+ graph->minvol));
+
+ if (graph->minvol == oldvol && graph->mincut == oldcut)
+ break;
+ }
+
+ GKfree(&marker, &updind, &phtable, LTERM);
+
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nvtxs);
+}
+
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void Random_KWayVolRefineMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts,
+ float ubfactor, int npasses, int ffactor)
+{
+ int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain;
+ int from, me, to, oldcut, oldvol, vwgt, nadd, maxndoms;
+ idxtype *xadj, *adjncy, *adjwgt;
+ idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable;
+ idxtype *pmat, *pmatptr, *ndoms;
+ VEDegreeType *myedegrees;
+ VRInfoType *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));
+
+ updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind");
+ marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker");
+ phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable");
+
+ pmat = ctrl->wspace.pmat;
+ ndoms = idxwspacemalloc(ctrl, nparts);
+
+ ComputeVolSubDomainGraph(graph, nparts, pmat, ndoms);
+
+ 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("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d\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, graph->minvol));
+
+ for (pass=0; pass<npasses; pass++) {
+ ASSERT(ComputeCut(graph, where) == graph->mincut);
+
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+
+ oldcut = graph->mincut;
+ oldvol = graph->minvol;
+
+ RandomPermute(graph->nbnd, perm, 1);
+ for (nmoves=iii=0; iii<graph->nbnd; iii++) {
+ ii = perm[iii];
+ if (ii >= graph->nbnd)
+ continue;
+ i = bndind[ii];
+ myrinfo = graph->vrinfo+i;
+
+ if (myrinfo->gv >= 0) { /* Total volume gain is too high */
+ from = where[i];
+ vwgt = graph->vwgt[i];
+
+ if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from])
+ continue; /* This cannot be moved! */
+
+ xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0);
+
+ myedegrees = myrinfo->edegrees;
+ myndegrees = myrinfo->ndegrees;
+
+ /* Determine the valid domains */
+ for (j=0; j<myndegrees; j++) {
+ to = myedegrees[j].pid;
+ phtable[to] = 1;
+ pmatptr = pmat + to*nparts;
+ for (nadd=0, k=0; k<myndegrees; k++) {
+ if (k == j)
+ continue;
+
+ l = myedegrees[k].pid;
+ if (pmatptr[l] == 0) {
+ if (ndoms[l] > maxndoms-1) {
+ phtable[to] = 0;
+ nadd = maxndoms;
+ break;
+ }
+ nadd++;
+ }
+ }
+ if (ndoms[to]+nadd > maxndoms)
+ phtable[to] = 0;
+ if (nadd == 0)
+ phtable[to] = 2;
+ }
+
+ for (k=0; k<myndegrees; k++) {
+ to = myedegrees[k].pid;
+ if (!phtable[to])
+ continue;
+ if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*myedegrees[k].gv && xgain+myedegrees[k].gv >= 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 (!phtable[to] || pwgts[to]+vwgt > maxwgt[to])
+ continue;
+ if (myedegrees[j].gv > myedegrees[k].gv ||
+ (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed > myedegrees[k].ed) ||
+ (myedegrees[j].gv == myedegrees[k].gv && 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 (xgain+myedegrees[k].gv > 0 || myedegrees[k].ed-myrinfo->id > 0)
+ j = 1;
+ else if (myedegrees[k].ed-myrinfo->id == 0) {
+ if ((iii&5) == 0 || phtable[myedegrees[k].pid] == 2 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])
+ j = 1;
+ }
+
+ if (j == 0)
+ continue;
+
+ for (j=0; j<myndegrees; j++)
+ phtable[myedegrees[j].pid] = -1;
+
+
+ /*=====================================================================
+ * If we got here, we can now move the vertex from 'from' to 'to'
+ *======================================================================*/
+ INC_DEC(pwgts[to], pwgts[from], vwgt);
+ graph->mincut -= myedegrees[k].ed-myrinfo->id;
+ graph->minvol -= (xgain+myedegrees[k].gv);
+ where[i] = to;
+
+ IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n",
+ i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol));
+
+ /* Update pmat to reflect the move of 'i' */
+ pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
+ pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
+ if (pmat[from*nparts+to] == 0) {
+ ndoms[from]--;
+ if (ndoms[from]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+ if (pmat[to*nparts+from] == 0) {
+ ndoms[to]--;
+ if (ndoms[to]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ ii = adjncy[j];
+ me = where[ii];
+
+ /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
+ if (me != from && me != to) {
+ pmat[me*nparts+from] -= adjwgt[j];
+ pmat[from*nparts+me] -= adjwgt[j];
+ if (pmat[me*nparts+from] == 0) {
+ ndoms[me]--;
+ if (ndoms[me]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+ if (pmat[from*nparts+me] == 0) {
+ ndoms[from]--;
+ if (ndoms[from]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+
+ if (pmat[me*nparts+to] == 0) {
+ ndoms[me]++;
+ if (ndoms[me] > maxndoms) {
+ IFSET(ctrl->dbglvl, DBG_REFINE, printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms));
+ maxndoms = ndoms[me];
+ }
+ }
+ if (pmat[to*nparts+me] == 0) {
+ ndoms[to]++;
+ if (ndoms[to] > maxndoms) {
+ IFSET(ctrl->dbglvl, DBG_REFINE, printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms));
+ maxndoms = ndoms[to];
+ }
+ }
+ pmat[me*nparts+to] += adjwgt[j];
+ pmat[to*nparts+me] += adjwgt[j];
+ }
+ }
+
+ KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind);
+
+ nmoves++;
+
+ /* CheckVolKWayPartitionParams(ctrl, graph, nparts); */
+ }
+ }
+
+ 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,
+ graph->minvol));
+
+ if (graph->minvol == oldvol && graph->mincut == oldcut)
+ break;
+ }
+
+ GKfree(&marker, &updind, &phtable, LTERM);
+
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nvtxs);
+}
+
+
+
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void Greedy_KWayVolBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts,
+ float ubfactor, int npasses)
+{
+ int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain;
+ int from, me, to, vwgt, gain;
+ idxtype *xadj, *adjncy, *adjwgt;
+ idxtype *where, *pwgts, *perm, *moved, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable;
+ VEDegreeType *myedegrees;
+ VRInfoType *myrinfo;
+ PQueueType queue;
+
+ 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));
+
+ updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind");
+ marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker");
+ phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable");
+
+ 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("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d [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, graph->minvol));
+
+
+ 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);
+
+ RandomPermute(graph->nbnd, perm, 1);
+ for (ii=0; ii<graph->nbnd; ii++) {
+ i = bndind[perm[ii]];
+ PQueueInsert(&queue, i, graph->vrinfo[i].gv);
+ moved[i] = 2;
+ }
+
+ for (nmoves=0;;) {
+ if ((i = PQueueGetMax(&queue)) == -1)
+ break;
+ moved[i] = 1;
+
+ myrinfo = graph->vrinfo+i;
+ from = where[i];
+ vwgt = graph->vwgt[i];
+
+ if (pwgts[from]-vwgt < minwgt[from])
+ continue; /* This cannot be moved! */
+
+ xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0);
+
+ 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] &&
+ (xgain+myedegrees[k].gv < 0 ||
+ (xgain+myedegrees[k].gv == 0 && myedegrees[k].ed-myrinfo->id < 0))
+ )
+ continue;
+
+
+ /*=====================================================================
+ * If we got here, we can now move the vertex from 'from' to 'to'
+ *======================================================================*/
+ INC_DEC(pwgts[to], pwgts[from], vwgt);
+ graph->mincut -= myedegrees[k].ed-myrinfo->id;
+ graph->minvol -= (xgain+myedegrees[k].gv);
+ where[i] = to;
+
+ IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n",
+ i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol));
+
+ KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind);
+
+ nmoves++;
+
+ /*CheckVolKWayPartitionParams(ctrl, graph, nparts); */
+ }
+
+ 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,
+ graph->minvol));
+
+ }
+
+ GKfree(&marker, &updind, &phtable, LTERM);
+
+ 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_KWayVolBalanceMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts,
+ float ubfactor, int npasses)
+{
+ int i, ii, iii, j, jj, k, kk, l, u, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain;
+ int from, me, to, vwgt, gain, maxndoms, nadd;
+ idxtype *xadj, *adjncy, *adjwgt;
+ idxtype *where, *pwgts, *perm, *moved, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable;
+ idxtype *pmat, *pmatptr, *ndoms;
+ VEDegreeType *myedegrees;
+ VRInfoType *myrinfo;
+ PQueueType queue;
+
+ 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));
+
+ updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind");
+ marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker");
+ phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable");
+
+ pmat = ctrl->wspace.pmat;
+ ndoms = idxwspacemalloc(ctrl, nparts);
+
+ ComputeVolSubDomainGraph(graph, nparts, pmat, ndoms);
+
+ 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("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d [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, graph->minvol));
+
+
+ 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);
+
+ RandomPermute(graph->nbnd, perm, 1);
+ for (ii=0; ii<graph->nbnd; ii++) {
+ i = bndind[perm[ii]];
+ PQueueInsert(&queue, i, graph->vrinfo[i].gv);
+ moved[i] = 2;
+ }
+
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+
+ for (nmoves=0;;) {
+ if ((i = PQueueGetMax(&queue)) == -1)
+ break;
+ moved[i] = 1;
+
+ myrinfo = graph->vrinfo+i;
+ from = where[i];
+ vwgt = graph->vwgt[i];
+
+ if (pwgts[from]-vwgt < minwgt[from])
+ continue; /* This cannot be moved! */
+
+ xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0);
+
+ myedegrees = myrinfo->edegrees;
+ myndegrees = myrinfo->ndegrees;
+
+ /* Determine the valid domains */
+ for (j=0; j<myndegrees; j++) {
+ to = myedegrees[j].pid;
+ phtable[to] = 1;
+ pmatptr = pmat + to*nparts;
+ for (nadd=0, k=0; k<myndegrees; k++) {
+ if (k == j)
+ continue;
+
+ l = myedegrees[k].pid;
+ if (pmatptr[l] == 0) {
+ if (ndoms[l] > maxndoms-1) {
+ phtable[to] = 0;
+ nadd = maxndoms;
+ break;
+ }
+ nadd++;
+ }
+ }
+ if (ndoms[to]+nadd > maxndoms)
+ phtable[to] = 0;
+ }
+
+ for (k=0; k<myndegrees; k++) {
+ to = myedegrees[k].pid;
+ if (!phtable[to])
+ continue;
+ 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 (!phtable[to])
+ continue;
+ if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])
+ k = j;
+ }
+
+ to = myedegrees[k].pid;
+
+ for (j=0; j<myndegrees; j++)
+ phtable[myedegrees[j].pid] = -1;
+
+ if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] &&
+ (xgain+myedegrees[k].gv < 0 ||
+ (xgain+myedegrees[k].gv == 0 && myedegrees[k].ed-myrinfo->id < 0))
+ )
+ continue;
+
+
+ /*=====================================================================
+ * If we got here, we can now move the vertex from 'from' to 'to'
+ *======================================================================*/
+ INC_DEC(pwgts[to], pwgts[from], vwgt);
+ graph->mincut -= myedegrees[k].ed-myrinfo->id;
+ graph->minvol -= (xgain+myedegrees[k].gv);
+ where[i] = to;
+
+ IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n",
+ i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol));
+
+ /* Update pmat to reflect the move of 'i' */
+ pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
+ pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
+ if (pmat[from*nparts+to] == 0) {
+ ndoms[from]--;
+ if (ndoms[from]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+ if (pmat[to*nparts+from] == 0) {
+ ndoms[to]--;
+ if (ndoms[to]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ ii = adjncy[j];
+ me = where[ii];
+
+ /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
+ if (me != from && me != to) {
+ pmat[me*nparts+from] -= adjwgt[j];
+ pmat[from*nparts+me] -= adjwgt[j];
+ if (pmat[me*nparts+from] == 0) {
+ ndoms[me]--;
+ if (ndoms[me]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+ if (pmat[from*nparts+me] == 0) {
+ ndoms[from]--;
+ if (ndoms[from]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+
+ if (pmat[me*nparts+to] == 0) {
+ ndoms[me]++;
+ if (ndoms[me] > maxndoms) {
+ IFSET(ctrl->dbglvl, DBG_REFINE, printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms));
+ maxndoms = ndoms[me];
+ }
+ }
+ if (pmat[to*nparts+me] == 0) {
+ ndoms[to]++;
+ if (ndoms[to] > maxndoms) {
+ IFSET(ctrl->dbglvl, DBG_REFINE, printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms));
+ maxndoms = ndoms[to];
+ }
+ }
+ pmat[me*nparts+to] += adjwgt[j];
+ pmat[to*nparts+me] += adjwgt[j];
+ }
+ }
+
+ KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind);
+
+ nmoves++;
+
+ /*CheckVolKWayPartitionParams(ctrl, graph, nparts); */
+ }
+
+ 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,
+ graph->minvol));
+
+ }
+
+ GKfree(&marker, &updind, &phtable, LTERM);
+
+ PQueueFree(ctrl, &queue);
+
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+}
+
+
+
+
+/*************************************************************************
+* This function updates the edge and volume gains as a result of moving
+* v from 'from' to 'to'.
+* The working arrays marker and phtable are assumed to be initialized to
+* -1, and they left to -1 upon return
+**************************************************************************/
+void KWayVolUpdate(CtrlType *ctrl, GraphType *graph, int v, int from, int to,
+ idxtype *marker, idxtype *phtable, idxtype *updind)
+{
+ int ii, iii, j, jj, k, kk, l, u, nupd, other, me, myidx;
+ idxtype *xadj, *vsize, *adjncy, *adjwgt, *where;
+ VEDegreeType *myedegrees, *oedegrees;
+ VRInfoType *myrinfo, *orinfo;
+
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ vsize = graph->vsize;
+ where = graph->where;
+
+ myrinfo = graph->vrinfo+v;
+ myedegrees = myrinfo->edegrees;
+
+
+ /*======================================================================
+ * Remove the contributions on the gain made by 'v'.
+ *=====================================================================*/
+ for (k=0; k<myrinfo->ndegrees; k++)
+ phtable[myedegrees[k].pid] = k;
+ phtable[from] = k;
+
+ myidx = phtable[to]; /* Keep track of the index in myedegrees of the 'to' domain */
+
+ for (j=xadj[v]; j<xadj[v+1]; j++) {
+ ii = adjncy[j];
+ other = where[ii];
+ orinfo = graph->vrinfo+ii;
+ oedegrees = orinfo->edegrees;
+
+ if (other == from) {
+ for (k=0; k<orinfo->ndegrees; k++) {
+ if (phtable[oedegrees[k].pid] == -1)
+ oedegrees[k].gv += vsize[v];
+ }
+ }
+ else {
+ ASSERT(phtable[other] != -1);
+
+ if (myedegrees[phtable[other]].ned > 1) {
+ for (k=0; k<orinfo->ndegrees; k++) {
+ if (phtable[oedegrees[k].pid] == -1)
+ oedegrees[k].gv += vsize[v];
+ }
+ }
+ else { /* There is only one connection */
+ for (k=0; k<orinfo->ndegrees; k++) {
+ if (phtable[oedegrees[k].pid] != -1)
+ oedegrees[k].gv -= vsize[v];
+ }
+ }
+ }
+ }
+
+ for (k=0; k<myrinfo->ndegrees; k++)
+ phtable[myedegrees[k].pid] = -1;
+ phtable[from] = -1;
+
+
+ /*======================================================================
+ * Update the id/ed of vertex 'v'
+ *=====================================================================*/
+ myrinfo->ed += myrinfo->id-myedegrees[myidx].ed;
+ SWAP(myrinfo->id, myedegrees[myidx].ed, j);
+ SWAP(myrinfo->nid, myedegrees[myidx].ned, j);
+ if (myedegrees[myidx].ed == 0)
+ myedegrees[myidx] = myedegrees[--myrinfo->ndegrees];
+ else
+ myedegrees[myidx].pid = from;
+
+ /*======================================================================
+ * Update the degrees of adjacent vertices and their volume gains
+ *=====================================================================*/
+ marker[v] = 1;
+ updind[0] = v;
+ nupd = 1;
+ for (j=xadj[v]; j<xadj[v+1]; j++) {
+ ii = adjncy[j];
+ me = where[ii];
+
+ if (!marker[ii]) { /* The marking is done for boundary and max gv calculations */
+ marker[ii] = 2;
+ updind[nupd++] = ii;
+ }
+
+ myrinfo = graph->vrinfo+ii;
+ if (myrinfo->edegrees == NULL) {
+ myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree;
+ ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
+ }
+ myedegrees = myrinfo->edegrees;
+
+ if (me == from) {
+ INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
+ myrinfo->nid--;
+ }
+ else if (me == to) {
+ INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
+ myrinfo->nid++;
+ }
+
+ /* Remove the edgeweight from the 'pid == from' entry of the vertex */
+ if (me != from) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (myedegrees[k].pid == from) {
+ if (myedegrees[k].ned == 1) {
+ myedegrees[k] = myedegrees[--myrinfo->ndegrees];
+ marker[ii] = 1; /* You do a complete .gv calculation */
+
+ /* All vertices adjacent to 'ii' need to be updated */
+ for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
+ u = adjncy[jj];
+ other = where[u];
+ orinfo = graph->vrinfo+u;
+ oedegrees = orinfo->edegrees;
+
+ for (kk=0; kk<orinfo->ndegrees; kk++) {
+ if (oedegrees[kk].pid == from) {
+ oedegrees[kk].gv -= vsize[ii];
+ break;
+ }
+ }
+ }
+ }
+ else {
+ myedegrees[k].ed -= adjwgt[j];
+ myedegrees[k].ned--;
+
+ /* Update the gv due to single 'ii' connection to 'from' */
+ if (myedegrees[k].ned == 1) {
+ /* find the vertex 'u' that 'ii' was connected into 'from' */
+ for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
+ u = adjncy[jj];
+ other = where[u];
+ orinfo = graph->vrinfo+u;
+ oedegrees = orinfo->edegrees;
+
+ if (other == from) {
+ for (kk=0; kk<orinfo->ndegrees; kk++)
+ oedegrees[kk].gv += vsize[ii];
+ break;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ /* Add the edgeweight to the 'pid == to' entry of the vertex */
+ if (me != to) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (myedegrees[k].pid == to) {
+ myedegrees[k].ed += adjwgt[j];
+ myedegrees[k].ned++;
+
+ /* Update the gv due to non-single 'ii' connection to 'to' */
+ if (myedegrees[k].ned == 2) {
+ /* find the vertex 'u' that 'ii' was connected into 'to' */
+ for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
+ u = adjncy[jj];
+ other = where[u];
+ orinfo = graph->vrinfo+u;
+ oedegrees = orinfo->edegrees;
+
+ if (u != v && other == to) {
+ for (kk=0; kk<orinfo->ndegrees; kk++)
+ oedegrees[kk].gv -= vsize[ii];
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (k == myrinfo->ndegrees) {
+ myedegrees[myrinfo->ndegrees].pid = to;
+ myedegrees[myrinfo->ndegrees].ed = adjwgt[j];
+ myedegrees[myrinfo->ndegrees++].ned = 1;
+ marker[ii] = 1; /* You do a complete .gv calculation */
+
+ /* All vertices adjacent to 'ii' need to be updated */
+ for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
+ u = adjncy[jj];
+ other = where[u];
+ orinfo = graph->vrinfo+u;
+ oedegrees = orinfo->edegrees;
+
+ for (kk=0; kk<orinfo->ndegrees; kk++) {
+ if (oedegrees[kk].pid == to) {
+ oedegrees[kk].gv += vsize[ii];
+ if (!marker[u]) { /* Need to update boundary etc */
+ marker[u] = 2;
+ updind[nupd++] = u;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
+ }
+
+ /*======================================================================
+ * Add the contributions on the volume gain due to 'v'
+ *=====================================================================*/
+ myrinfo = graph->vrinfo+v;
+ myedegrees = myrinfo->edegrees;
+ for (k=0; k<myrinfo->ndegrees; k++)
+ phtable[myedegrees[k].pid] = k;
+ phtable[to] = k;
+
+ for (j=xadj[v]; j<xadj[v+1]; j++) {
+ ii = adjncy[j];
+ other = where[ii];
+ orinfo = graph->vrinfo+ii;
+ oedegrees = orinfo->edegrees;
+
+ if (other == to) {
+ for (k=0; k<orinfo->ndegrees; k++) {
+ if (phtable[oedegrees[k].pid] == -1)
+ oedegrees[k].gv -= vsize[v];
+ }
+ }
+ else {
+ ASSERT(phtable[other] != -1);
+
+ if (myedegrees[phtable[other]].ned > 1) {
+ for (k=0; k<orinfo->ndegrees; k++) {
+ if (phtable[oedegrees[k].pid] == -1)
+ oedegrees[k].gv -= vsize[v];
+ }
+ }
+ else { /* There is only one connection */
+ for (k=0; k<orinfo->ndegrees; k++) {
+ if (phtable[oedegrees[k].pid] != -1)
+ oedegrees[k].gv += vsize[v];
+ }
+ }
+ }
+ }
+ for (k=0; k<myrinfo->ndegrees; k++)
+ phtable[myedegrees[k].pid] = -1;
+ phtable[to] = -1;
+
+
+ /*======================================================================
+ * Recompute the volume information of the 'hard' nodes, and update the
+ * max volume gain for all the update vertices
+ *=====================================================================*/
+ ComputeKWayVolume(graph, nupd, updind, marker, phtable);
+
+
+ /*======================================================================
+ * Maintain a consistent boundary
+ *=====================================================================*/
+ for (j=0; j<nupd; j++) {
+ k = updind[j];
+ marker[k] = 0;
+ myrinfo = graph->vrinfo+k;
+
+ if ((myrinfo->gv >= 0 || myrinfo->ed-myrinfo->id >= 0) && graph->bndptr[k] == -1)
+ BNDInsert(graph->nbnd, graph->bndind, graph->bndptr, k);
+
+ if (myrinfo->gv < 0 && myrinfo->ed-myrinfo->id < 0 && graph->bndptr[k] != -1)
+ BNDDelete(graph->nbnd, graph->bndind, graph->bndptr, k);
+ }
+
+}
+
+
+
+
+/*************************************************************************
+* This function computes the initial id/ed
+**************************************************************************/
+void ComputeKWayVolume(GraphType *graph, int nupd, idxtype *updind, idxtype *marker, idxtype *phtable)
+{
+ int ii, iii, i, j, k, kk, l, nvtxs, me, other, pid;
+ idxtype *xadj, *vsize, *adjncy, *adjwgt, *where;
+ 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;
+ rinfo = graph->vrinfo;
+
+
+ /*------------------------------------------------------------
+ / Compute now the iv/ev degrees
+ /------------------------------------------------------------*/
+ for (iii=0; iii<nupd; iii++) {
+ i = updind[iii];
+ me = where[i];
+
+ myrinfo = rinfo+i;
+ myedegrees = myrinfo->edegrees;
+
+ if (marker[i] == 1) { /* Only complete gain updates go through */
+ for (k=0; k<myrinfo->ndegrees; k++)
+ myedegrees[k].gv = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ ii = adjncy[j];
+ other = where[ii];
+ orinfo = rinfo+ii;
+ oedegrees = orinfo->edegrees;
+
+ for (kk=0; kk<orinfo->ndegrees; kk++)
+ phtable[oedegrees[kk].pid] = kk;
+ phtable[other] = 1;
+
+ if (me == other) {
+ /* Find which domains 'i' is connected and 'ii' is not and update their gain */
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (phtable[myedegrees[k].pid] == -1)
+ myedegrees[k].gv -= vsize[ii];
+ }
+ }
+ else {
+ ASSERT(phtable[me] != -1);
+
+ /* I'm the only connection of 'ii' in 'me' */
+ if (oedegrees[phtable[me]].ned == 1) {
+ /* Increase the gains for all the common domains between 'i' and 'ii' */
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (phtable[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<myrinfo->ndegrees; k++) {
+ if (phtable[myedegrees[k].pid] == -1)
+ myedegrees[k].gv -= vsize[ii];
+ }
+ }
+ }
+
+ for (kk=0; kk<orinfo->ndegrees; kk++)
+ phtable[oedegrees[kk].pid] = -1;
+ phtable[other] = -1;
+
+ }
+ }
+
+ myrinfo->gv = -MAXIDX;
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (myedegrees[k].gv > myrinfo->gv)
+ myrinfo->gv = myedegrees[k].gv;
+ }
+ if (myrinfo->ed > 0 && myrinfo->id == 0)
+ myrinfo->gv += vsize[i];
+
+ }
+
+}
+
+
+
+/*************************************************************************
+* This function computes the total volume
+**************************************************************************/
+int ComputeVolume(GraphType *graph, idxtype *where)
+{
+ int i, j, k, me, nvtxs, nparts, totalv;
+ idxtype *xadj, *adjncy, *vsize, *marker;
+
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vsize = (graph->vsize == NULL ? graph->vwgt : graph->vsize);
+
+ nparts = where[idxamax(nvtxs, where)]+1;
+ marker = idxsmalloc(nparts, -1, "ComputeVolume: marker");
+
+ totalv = 0;
+
+ for (i=0; i<nvtxs; i++) {
+ marker[where[i]] = i;
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = where[adjncy[j]];
+ if (marker[k] != i) {
+ marker[k] = i;
+ totalv += vsize[i];
+ }
+ }
+ }
+
+ free(marker);
+
+ return totalv;
+}
+
+
+
+
+
+/*************************************************************************
+* This function computes the initial id/ed
+**************************************************************************/
+void CheckVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
+{
+ int i, ii, j, k, kk, l, nvtxs, nbnd, mincut, minvol, me, other, pid;
+ idxtype *xadj, *vsize, *adjncy, *adjwgt, *pwgts, *where, *bndind, *bndptr;
+ VRInfoType *rinfo, *myrinfo, *orinfo, tmprinfo;
+ VEDegreeType *myedegrees, *oedegrees, *tmpdegrees;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ vsize = graph->vsize;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ rinfo = graph->vrinfo;
+
+ tmpdegrees = (VEDegreeType *)GKmalloc(nparts*sizeof(VEDegreeType), "CheckVolKWayPartitionParams: tmpdegrees");
+
+ /*------------------------------------------------------------
+ / Compute now the iv/ev degrees
+ /------------------------------------------------------------*/
+ for (i=0; i<nvtxs; i++) {
+ me = where[i];
+
+ myrinfo = rinfo+i;
+ myedegrees = myrinfo->edegrees;
+
+ for (k=0; k<myrinfo->ndegrees; k++)
+ tmpdegrees[k] = myedegrees[k];
+
+ tmprinfo.ndegrees = myrinfo->ndegrees;
+ tmprinfo.id = myrinfo->id;
+ tmprinfo.ed = myrinfo->ed;
+
+ myrinfo = &tmprinfo;
+ myedegrees = tmpdegrees;
+
+
+ for (k=0; k<myrinfo->ndegrees; k++)
+ myedegrees[k].gv = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ ii = adjncy[j];
+ other = where[ii];
+ orinfo = rinfo+ii;
+ oedegrees = orinfo->edegrees;
+
+ if (me == other) {
+ /* Find which domains 'i' is connected and 'ii' is not and update their gain */
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ pid = myedegrees[k].pid;
+ for (kk=0; kk<orinfo->ndegrees; kk++) {
+ if (oedegrees[kk].pid == pid)
+ break;
+ }
+ if (kk == orinfo->ndegrees)
+ myedegrees[k].gv -= vsize[ii];
+ }
+ }
+ else {
+ /* Find the orinfo[me].ed and see if I'm the only connection */
+ for (k=0; k<orinfo->ndegrees; k++) {
+ if (oedegrees[k].pid == me)
+ break;
+ }
+
+ if (oedegrees[k].ned == 1) { /* I'm the only connection of 'ii' in 'me' */
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (myedegrees[k].pid == other) {
+ myedegrees[k].gv += vsize[ii];
+ break;
+ }
+ }
+
+ /* Increase the gains for all the common domains between 'i' and 'ii' */
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if ((pid = myedegrees[k].pid) == other)
+ continue;
+ for (kk=0; kk<orinfo->ndegrees; kk++) {
+ if (oedegrees[kk].pid == pid) {
+ myedegrees[k].gv += vsize[ii];
+ break;
+ }
+ }
+ }
+
+ }
+ else {
+ /* Find which domains 'i' is connected and 'ii' is not and update their gain */
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if ((pid = myedegrees[k].pid) == other)
+ continue;
+ for (kk=0; kk<orinfo->ndegrees; kk++) {
+ if (oedegrees[kk].pid == pid)
+ break;
+ }
+ if (kk == orinfo->ndegrees)
+ myedegrees[k].gv -= vsize[ii];
+ }
+ }
+ }
+ }
+
+ myrinfo = rinfo+i;
+ myedegrees = myrinfo->edegrees;
+
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ pid = myedegrees[k].pid;
+ for (kk=0; kk<tmprinfo.ndegrees; kk++) {
+ if (tmpdegrees[kk].pid == pid) {
+ if (tmpdegrees[kk].gv != myedegrees[k].gv)
+ printf("[%d %d %d %d]\n", i, pid, myedegrees[k].gv, tmpdegrees[kk].gv);
+ break;
+ }
+ }
+ }
+
+ }
+
+ free(tmpdegrees);
+
+}
+
+
+/*************************************************************************
+* This function computes the subdomain graph
+**************************************************************************/
+void ComputeVolSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms)
+{
+ int i, j, k, me, nvtxs, ndegrees;
+ idxtype *xadj, *adjncy, *adjwgt, *where;
+ VRInfoType *rinfo;
+ VEDegreeType *edegrees;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ rinfo = graph->vrinfo;
+
+ idxset(nparts*nparts, 0, pmat);
+
+ for (i=0; i<nvtxs; i++) {
+ if (rinfo[i].ed > 0) {
+ me = where[i];
+ ndegrees = rinfo[i].ndegrees;
+ edegrees = rinfo[i].edegrees;
+
+ k = me*nparts;
+ for (j=0; j<ndegrees; j++)
+ pmat[k+edegrees[j].pid] += edegrees[j].ed;
+ }
+ }
+
+ for (i=0; i<nparts; i++) {
+ ndoms[i] = 0;
+ for (j=0; j<nparts; j++) {
+ if (pmat[i*nparts+j] > 0)
+ ndoms[i]++;
+ }
+ }
+}
+
+
+
+/*************************************************************************
+* This function computes the subdomain graph
+**************************************************************************/
+void EliminateVolSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts)
+{
+ int i, ii, j, k, me, other, nvtxs, total, max, avg, totalout, nind, ncand, ncand2, target, target2, nadd;
+ int min, move, cpwgt, tvwgt;
+ idxtype *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt, *pmat, *ndoms, *mypmat, *otherpmat, *ind;
+ KeyValueType *cand, *cand2;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vwgt = graph->vwgt;
+ adjwgt = graph->adjwgt;
+
+ where = graph->where;
+ pwgts = idxset(nparts, 0, graph->pwgts);
+
+ maxpwgt = idxwspacemalloc(ctrl, nparts);
+ ndoms = idxwspacemalloc(ctrl, nparts);
+ otherpmat = idxwspacemalloc(ctrl, nparts);
+ ind = idxwspacemalloc(ctrl, nvtxs);
+ pmat = idxset(nparts*nparts, 0, ctrl->wspace.pmat);
+
+ cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
+ cand2 = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
+
+ /* Compute the pmat matrix */
+ for (i=0; i<nvtxs; i++) {
+ me = where[i];
+ pwgts[me] += vwgt[i];
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = adjncy[j];
+ if (where[k] != me)
+ pmat[me*nparts+where[k]] += adjwgt[j];
+ }
+ }
+
+ /* Compute the maximum allowed weight for each domain */
+ tvwgt = idxsum(nparts, pwgts);
+ for (i=0; i<nparts; i++)
+ maxpwgt[i] = 1.25*tpwgts[i]*tvwgt;
+
+ /* Determine the domain connectivity */
+ for (i=0; i<nparts; i++) {
+ for (k=0, j=0; j<nparts; j++) {
+ if (pmat[i*nparts+j] > 0)
+ k++;
+ }
+ ndoms[i] = k;
+ }
+
+ /* Get into the loop eliminating subdomain connections */
+ for (;;) {
+ total = idxsum(nparts, ndoms);
+ avg = total/nparts;
+ max = ndoms[idxamax(nparts, ndoms)];
+
+ /* printf("Adjacent Subdomain Stats: Total: %3d, Max: %3d, Avg: %3d\n", total, max, avg); */
+
+ if (max < 1.5*avg)
+ break;
+
+ me = idxamax(nparts, ndoms);
+ mypmat = pmat + me*nparts;
+ totalout = idxsum(nparts, mypmat);
+
+ /*printf("Me: %d, TotalOut: %d,\n", me, totalout);*/
+
+ /* Sort the connections according to their cut */
+ for (ncand2=0, i=0; i<nparts; i++) {
+ if (mypmat[i] > 0) {
+ cand2[ncand2].key = mypmat[i];
+ cand2[ncand2++].val = i;
+ }
+ }
+ ikeysort(ncand2, cand2);
+
+ move = 0;
+ for (min=0; min<ncand2; min++) {
+ if (cand2[min].key > totalout/(2*ndoms[me]))
+ break;
+
+ other = cand2[min].val;
+
+ /*printf("\tMinOut: %d to %d\n", mypmat[other], other);*/
+
+ idxset(nparts, 0, otherpmat);
+
+ /* Go and find the vertices in 'other' that are connected in 'me' */
+ for (nind=0, i=0; i<nvtxs; i++) {
+ if (where[i] == other) {
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ if (where[adjncy[j]] == me) {
+ ind[nind++] = i;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Go and construct the otherpmat to see where these nind vertices are connected to */
+ for (cpwgt=0, ii=0; ii<nind; ii++) {
+ i = ind[ii];
+ cpwgt += vwgt[i];
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = adjncy[j];
+ if (where[k] != other)
+ otherpmat[where[k]] += adjwgt[j];
+ }
+ }
+
+ for (ncand=0, i=0; i<nparts; i++) {
+ if (otherpmat[i] > 0) {
+ cand[ncand].key = -otherpmat[i];
+ cand[ncand++].val = i;
+ }
+ }
+ ikeysort(ncand, cand);
+
+ /*
+ * Go through and the select the first domain that is common with 'me', and
+ * does not increase the ndoms[target] higher than my ndoms, subject to the
+ * maxpwgt constraint. Traversal is done from the mostly connected to the least.
+ */
+ target = target2 = -1;
+ for (i=0; i<ncand; i++) {
+ k = cand[i].val;
+
+ if (mypmat[k] > 0) {
+ if (pwgts[k] + cpwgt > maxpwgt[k]) /* Check if balance will go off */
+ continue;
+
+ for (j=0; j<nparts; j++) {
+ if (otherpmat[j] > 0 && ndoms[j] >= ndoms[me]-1 && pmat[nparts*j+k] == 0)
+ break;
+ }
+ if (j == nparts) { /* No bad second level effects */
+ for (nadd=0, j=0; j<nparts; j++) {
+ if (otherpmat[j] > 0 && pmat[nparts*k+j] == 0)
+ nadd++;
+ }
+
+ /*printf("\t\tto=%d, nadd=%d, %d\n", k, nadd, ndoms[k]);*/
+ if (target2 == -1 && ndoms[k]+nadd < ndoms[me]) {
+ target2 = k;
+ }
+ if (nadd == 0) {
+ target = k;
+ break;
+ }
+ }
+ }
+ }
+ if (target == -1 && target2 != -1)
+ target = target2;
+
+ if (target == -1) {
+ /* printf("\t\tCould not make the move\n");*/
+ continue;
+ }
+
+ /*printf("\t\tMoving to %d\n", target);*/
+
+ /* Update the partition weights */
+ INC_DEC(pwgts[target], pwgts[other], cpwgt);
+
+ /* Set all nind vertices to belong to 'target' */
+ for (ii=0; ii<nind; ii++) {
+ i = ind[ii];
+ where[i] = target;
+
+ /* First remove any contribution that this vertex may have made */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = adjncy[j];
+ if (where[k] != other) {
+ if (pmat[nparts*other + where[k]] == 0)
+ printf("Something wrong\n");
+ pmat[nparts*other + where[k]] -= adjwgt[j];
+ if (pmat[nparts*other + where[k]] == 0)
+ ndoms[other]--;
+
+ if (pmat[nparts*where[k] + other] == 0)
+ printf("Something wrong\n");
+ pmat[nparts*where[k] + other] -= adjwgt[j];
+ if (pmat[nparts*where[k] + other] == 0)
+ ndoms[where[k]]--;
+ }
+ }
+
+ /* Next add the new contributions as a result of the move */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = adjncy[j];
+ if (where[k] != target) {
+ if (pmat[nparts*target + where[k]] == 0)
+ ndoms[target]++;
+ pmat[nparts*target + where[k]] += adjwgt[j];
+
+ if (pmat[nparts*where[k] + target] == 0)
+ ndoms[where[k]]++;
+ pmat[nparts*where[k] + target] += adjwgt[j];
+ }
+ }
+ }
+
+ move = 1;
+ break;
+ }
+
+ if (move == 0)
+ break;
+ }
+
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nvtxs);
+
+ GKfree(&cand, &cand2, LTERM);
+}
+
+
+
+/*************************************************************************
+* This function finds all the connected components induced by the
+* partitioning vector in wgraph->where and tries to push them around to
+* remove some of them
+**************************************************************************/
+void EliminateVolComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
+{
+ int i, ii, j, jj, k, me, nvtxs, tvwgt, first, last, nleft, ncmps, cwgt, ncand, other, target, deltawgt;
+ idxtype *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts, *maxpwgt;
+ idxtype *cpvec, *touched, *perm, *todo, *cind, *cptr, *npcmps;
+ KeyValueType *cand;
+ int recompute=0;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vwgt = graph->vwgt;
+ adjwgt = graph->adjwgt;
+
+ where = graph->where;
+ pwgts = idxset(nparts, 0, graph->pwgts);
+
+ touched = idxset(nvtxs, 0, idxwspacemalloc(ctrl, nvtxs));
+ cptr = idxwspacemalloc(ctrl, nvtxs+1);
+ cind = idxwspacemalloc(ctrl, nvtxs);
+ perm = idxwspacemalloc(ctrl, nvtxs);
+ todo = idxwspacemalloc(ctrl, nvtxs);
+ maxpwgt = idxwspacemalloc(ctrl, nparts);
+ cpvec = idxwspacemalloc(ctrl, nparts);
+ npcmps = idxset(nparts, 0, idxwspacemalloc(ctrl, nparts));
+
+ for (i=0; i<nvtxs; i++)
+ perm[i] = todo[i] = i;
+
+ /* Find the connected componends induced by the partition */
+ ncmps = -1;
+ first = last = 0;
+ nleft = nvtxs;
+ while (nleft > 0) {
+ if (first == last) { /* Find another starting vertex */
+ cptr[++ncmps] = first;
+ ASSERT(touched[todo[0]] == 0);
+ i = todo[0];
+ cind[last++] = i;
+ touched[i] = 1;
+ me = where[i];
+ npcmps[me]++;
+ }
+
+ i = cind[first++];
+ k = perm[i];
+ j = todo[k] = todo[--nleft];
+ perm[j] = k;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == me && !touched[k]) {
+ cind[last++] = k;
+ touched[k] = 1;
+ }
+ }
+ }
+ cptr[++ncmps] = first;
+
+ /* printf("I found %d components, for this %d-way partition\n", ncmps, nparts); */
+
+ if (ncmps > nparts) { /* There are more components than processors */
+ cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
+
+ /* First determine the partition sizes and max allowed load imbalance */
+ for (i=0; i<nvtxs; i++)
+ pwgts[where[i]] += vwgt[i];
+ tvwgt = idxsum(nparts, pwgts);
+ for (i=0; i<nparts; i++)
+ maxpwgt[i] = ubfactor*tpwgts[i]*tvwgt;
+
+ deltawgt = tvwgt/(100*nparts);
+ deltawgt = 5;
+
+ for (i=0; i<ncmps; i++) {
+ me = where[cind[cptr[i]]]; /* Get the domain of this component */
+ if (npcmps[me] == 1)
+ continue; /* Skip it because it is contigous */
+
+ /*printf("Trying to move %d from %d\n", i, me); */
+
+ /* Determine the connectivity */
+ idxset(nparts, 0, cpvec);
+ for (cwgt=0, j=cptr[i]; j<cptr[i+1]; j++) {
+ ii = cind[j];
+ cwgt += vwgt[ii];
+ for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
+ other = where[adjncy[jj]];
+ if (me != other)
+ cpvec[other] += adjwgt[jj];
+ }
+ }
+
+ /*printf("\tCmp weight: %d\n", cwgt);*/
+
+ if (cwgt > .30*pwgts[me])
+ continue; /* Skip the component if it is over 30% of the weight */
+
+ for (ncand=0, j=0; j<nparts; j++) {
+ if (cpvec[j] > 0) {
+ cand[ncand].key = -cpvec[j];
+ cand[ncand++].val = j;
+ }
+ }
+ if (ncand == 0)
+ continue;
+
+ ikeysort(ncand, cand);
+
+ target = -1;
+ for (j=0; j<ncand; j++) {
+ k = cand[j].val;
+ if (cwgt < deltawgt || pwgts[k] + cwgt < maxpwgt[k]) {
+ target = k;
+ break;
+ }
+ }
+
+ /*printf("\tMoving it to %d [%d]\n", target, cpvec[target]);*/
+
+ if (target != -1) {
+ /* Assign all the vertices of 'me' to 'target' and update data structures */
+ pwgts[me] -= cwgt;
+ pwgts[target] += cwgt;
+ npcmps[me]--;
+
+ for (j=cptr[i]; j<cptr[i+1]; j++)
+ where[cind[j]] = target;
+
+ graph->mincut -= cpvec[target];
+ recompute = 1;
+ }
+ }
+
+ free(cand);
+ }
+
+ if (recompute) {
+ int ttlv;
+ idxtype *marker;
+
+ marker = idxset(nparts, -1, cpvec);
+ for (ttlv=0, i=0; i<nvtxs; i++) {
+ marker[where[i]] = i;
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ if (marker[where[adjncy[j]]] != i) {
+ ttlv += graph->vsize[i];
+ marker[where[adjncy[j]]] = i;
+ }
+ }
+ }
+ graph->minvol = ttlv;
+ }
+
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs+1);
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayvolrefine.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayvolrefine.c
new file mode 100644
index 0000000..7cf248d
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/kwayvolrefine.c
@@ -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;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/macros.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/macros.h
new file mode 100644
index 0000000..97e42a2
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/macros.h
@@ -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
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/match.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/match.c
new file mode 100644
index 0000000..509f457
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/match.c
@@ -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);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mbalance.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mbalance.c
new file mode 100644
index 0000000..65e9961
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mbalance.c
@@ -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);
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mbalance2.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mbalance2.c
new file mode 100644
index 0000000..d39f1e0
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mbalance2.c
@@ -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); */
+ }
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mcoarsen.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mcoarsen.c
new file mode 100644
index 0000000..336e6c6
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mcoarsen.c
@@ -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;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/memory.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/memory.c
new file mode 100644
index 0000000..0082b8c
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/memory.c
@@ -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);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mesh.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mesh.c
new file mode 100644
index 0000000..3d93628
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mesh.c
@@ -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);
+
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/meshpart.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/meshpart.c
new file mode 100644
index 0000000..4ca3a2a
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/meshpart.c
@@ -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);
+
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/metis.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/metis.h
new file mode 100644
index 0000000..b655d90
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/metis.h
@@ -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>
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mfm.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mfm.c
new file mode 100644
index 0000000..d0047e5
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mfm.c
@@ -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];
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mfm2.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mfm2.c
new file mode 100644
index 0000000..ce4eb8b
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mfm2.c
@@ -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;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mincover.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mincover.c
new file mode 100644
index 0000000..789022b
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mincover.c
@@ -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);
+ }
+
+}
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/minitpart.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/minitpart.c
new file mode 100644
index 0000000..58dfcea
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/minitpart.c
@@ -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;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/minitpart2.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/minitpart2.c
new file mode 100644
index 0000000..4c1e1b1
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/minitpart2.c
@@ -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;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkmetis.c
new file mode 100644
index 0000000..55c7c9b
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkmetis.c
@@ -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;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkwayfmh.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkwayfmh.c
new file mode 100644
index 0000000..69a781a
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkwayfmh.c
@@ -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;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkwayrefine.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkwayrefine.c
new file mode 100644
index 0000000..15836db
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mkwayrefine.c
@@ -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;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mmatch.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mmatch.c
new file mode 100644
index 0000000..2666dd3
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mmatch.c
@@ -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;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mmd.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mmd.c
new file mode 100644
index 0000000..1b43618
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mmd.c
@@ -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;
+ }
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mpmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mpmetis.c
new file mode 100644
index 0000000..3b7aa9f
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mpmetis.c
@@ -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);
+
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mrefine.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mrefine.c
new file mode 100644
index 0000000..3e28dc7
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mrefine.c
@@ -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;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mrefine2.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mrefine2.c
new file mode 100644
index 0000000..91ad0b5
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mrefine2.c
@@ -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));
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mutil.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mutil.c
new file mode 100644
index 0000000..68dc5c5
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/mutil.c
@@ -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;
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/myqsort.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/myqsort.c
new file mode 100644
index 0000000..a6939ce
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/myqsort.c
@@ -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);
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/ometis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/ometis.c
new file mode 100644
index 0000000..e972e88
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/ometis.c
@@ -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;
+
+}
+
+
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/parmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/parmetis.c
new file mode 100644
index 0000000..d183082
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/parmetis.c
@@ -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;
+
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/pmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/pmetis.c
new file mode 100644
index 0000000..9212cd7
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/pmetis.c
@@ -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");
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/pqueue.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/pqueue.c
new file mode 100644
index 0000000..6a1986f
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/pqueue.c
@@ -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;
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/proto.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/proto.h
new file mode 100644
index 0000000..3cfadab
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/proto.h
@@ -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 *);
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/refine.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/refine.c
new file mode 100644
index 0000000..f479298
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/refine.c
@@ -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;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/rename.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/rename.h
new file mode 100644
index 0000000..ca07dfe
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/rename.h
@@ -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
+
+
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/separator.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/separator.c
new file mode 100644
index 0000000..380d4f4
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/separator.c
@@ -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));
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/sfm.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/sfm.c
new file mode 100644
index 0000000..eece33f
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/sfm.c
@@ -0,0 +1,1069 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * sfm.c
+ *
+ * This file contains code that implementes an FM-based separator refinement
+ *
+ * Started 8/1/97
+ * George
+ *
+ * $Id: sfm.c,v 1.2 2003/07/31 06:14:01 karypis Exp $
+ *
+ */
+
+#include <metis.h>
+
+
+/*************************************************************************
+* This function performs a node-based FM refinement
+**************************************************************************/
+void FM_2WayNodeRefine(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses)
+{
+ int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;
+ idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
+ idxtype *mptr, *mind, *moved, *swaps, *perm;
+ PQueueType parts[2];
+ NRInfoType *rinfo;
+ int higain, oldgain, mincut, initcut, mincutorder;
+ int pass, to, other, limit;
+ int badmaxpwgt, mindiff, newdiff;
+ int u[2], g[2];
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vwgt = graph->vwgt;
+
+ bndind = graph->bndind;
+ bndptr = graph->bndptr;
+ where = graph->where;
+ pwgts = graph->pwgts;
+ rinfo = graph->nrinfo;
+
+
+ i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt);
+ PQueueInit(ctrl, &parts[0], nvtxs, i);
+ PQueueInit(ctrl, &parts[1], nvtxs, i);
+
+ moved = idxwspacemalloc(ctrl, nvtxs);
+ swaps = idxwspacemalloc(ctrl, nvtxs);
+ mptr = idxwspacemalloc(ctrl, nvtxs+1);
+ mind = idxwspacemalloc(ctrl, nvtxs);
+ perm = idxwspacemalloc(ctrl, nvtxs);
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
+
+ badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2);
+
+ for (pass=0; pass<npasses; pass++) {
+ idxset(nvtxs, -1, moved);
+ PQueueReset(&parts[0]);
+ PQueueReset(&parts[1]);
+
+ mincutorder = -1;
+ initcut = mincut = graph->mincut;
+ nbnd = graph->nbnd;
+
+ RandomPermute(nbnd, perm, 1);
+ for (ii=0; ii<nbnd; ii++) {
+ i = bndind[perm[ii]];
+ ASSERT(where[i] == 2);
+ PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]);
+ PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]);
+ }
+
+ ASSERT(CheckNodeBnd(graph, nbnd));
+ ASSERT(CheckNodePartitionParams(graph));
+
+ limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300));
+
+ /******************************************************
+ * Get into the FM loop
+ *******************************************************/
+ mptr[0] = nmind = 0;
+ mindiff = abs(pwgts[0]-pwgts[1]);
+ to = (pwgts[0] < pwgts[1] ? 0 : 1);
+ for (nswaps=0; nswaps<nvtxs; nswaps++) {
+ u[0] = PQueueSeeMax(&parts[0]);
+ u[1] = PQueueSeeMax(&parts[1]);
+ if (u[0] != -1 && u[1] != -1) {
+ g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1];
+ g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0];
+
+ to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2));
+ /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */
+
+ if (pwgts[to]+vwgt[u[to]] > badmaxpwgt)
+ to = (to+1)%2;
+ }
+ else if (u[0] == -1 && u[1] == -1) {
+ break;
+ }
+ else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) {
+ to = 0;
+ }
+ else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) {
+ to = 1;
+ }
+ else
+ break;
+
+ other = (to+1)%2;
+
+ higain = PQueueGetMax(&parts[to]);
+ if (moved[higain] == -1) /* Delete if it was in the separator originally */
+ PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]);
+
+ ASSERT(bndptr[higain] != -1);
+
+ pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
+
+ newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
+ if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
+ mincut = pwgts[2];
+ mincutorder = nswaps;
+ mindiff = newdiff;
+ }
+ else {
+ if (nswaps - mincutorder > limit) {
+ pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
+ break; /* No further improvement, break out */
+ }
+ }
+
+ BNDDelete(nbnd, bndind, bndptr, higain);
+ pwgts[to] += vwgt[higain];
+ where[higain] = to;
+ moved[higain] = nswaps;
+ swaps[nswaps] = higain;
+
+
+ /**********************************************************
+ * Update the degrees of the affected nodes
+ ***********************************************************/
+ for (j=xadj[higain]; j<xadj[higain+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
+ oldgain = vwgt[k]-rinfo[k].edegrees[to];
+ rinfo[k].edegrees[to] += vwgt[higain];
+ if (moved[k] == -1 || moved[k] == -(2+other))
+ PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]);
+ }
+ else if (where[k] == other) { /* This vertex is pulled into the separator */
+ ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
+ BNDInsert(nbnd, bndind, bndptr, k);
+
+ mind[nmind++] = k; /* Keep track for rollback */
+ where[k] = 2;
+ pwgts[other] -= vwgt[k];
+
+ edegrees = rinfo[k].edegrees;
+ edegrees[0] = edegrees[1] = 0;
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ kk = adjncy[jj];
+ if (where[kk] != 2)
+ edegrees[where[kk]] += vwgt[kk];
+ else {
+ oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
+ rinfo[kk].edegrees[other] -= vwgt[k];
+ if (moved[kk] == -1 || moved[kk] == -(2+to))
+ PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]);
+ }
+ }
+
+ /* Insert the new vertex into the priority queue. Only one side! */
+ if (moved[k] == -1) {
+ PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]);
+ moved[k] = -(2+to);
+ }
+ }
+ }
+ mptr[nswaps+1] = nmind;
+
+ IFSET(ctrl->dbglvl, DBG_MOVEINFO,
+ printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2]));
+
+ }
+
+
+ /****************************************************************
+ * Roll back computation
+ *****************************************************************/
+ for (nswaps--; nswaps>mincutorder; nswaps--) {
+ higain = swaps[nswaps];
+
+ ASSERT(CheckNodePartitionParams(graph));
+
+ to = where[higain];
+ other = (to+1)%2;
+ INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
+ where[higain] = 2;
+ BNDInsert(nbnd, bndind, bndptr, higain);
+
+ edegrees = rinfo[higain].edegrees;
+ edegrees[0] = edegrees[1] = 0;
+ for (j=xadj[higain]; j<xadj[higain+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == 2)
+ rinfo[k].edegrees[to] -= vwgt[higain];
+ else
+ edegrees[where[k]] += vwgt[k];
+ }
+
+ /* Push nodes out of the separator */
+ for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
+ k = mind[j];
+ ASSERT(where[k] == 2);
+ where[k] = other;
+ INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
+ BNDDelete(nbnd, bndind, bndptr, k);
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ kk = adjncy[jj];
+ if (where[kk] == 2)
+ rinfo[kk].edegrees[other] += vwgt[k];
+ }
+ }
+ }
+
+ ASSERT(mincut == pwgts[2]);
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("\tMinimum sep: %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+1);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+}
+
+
+/*************************************************************************
+* This function performs a node-based FM refinement
+**************************************************************************/
+void FM_2WayNodeRefine2(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses)
+{
+ int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;
+ idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
+ idxtype *mptr, *mind, *moved, *swaps, *perm;
+ PQueueType parts[2];
+ NRInfoType *rinfo;
+ int higain, oldgain, mincut, initcut, mincutorder;
+ int pass, to, other, limit;
+ int badmaxpwgt, mindiff, newdiff;
+ int u[2], g[2];
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vwgt = graph->vwgt;
+
+ bndind = graph->bndind;
+ bndptr = graph->bndptr;
+ where = graph->where;
+ pwgts = graph->pwgts;
+ rinfo = graph->nrinfo;
+
+
+ i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt);
+ PQueueInit(ctrl, &parts[0], nvtxs, i);
+ PQueueInit(ctrl, &parts[1], nvtxs, i);
+
+ moved = idxwspacemalloc(ctrl, nvtxs);
+ swaps = idxwspacemalloc(ctrl, nvtxs);
+ mptr = idxwspacemalloc(ctrl, nvtxs+1);
+ mind = idxwspacemalloc(ctrl, nvtxs);
+ perm = idxwspacemalloc(ctrl, nvtxs);
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
+
+ badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2);
+
+ for (pass=0; pass<npasses; pass++) {
+ idxset(nvtxs, -1, moved);
+ PQueueReset(&parts[0]);
+ PQueueReset(&parts[1]);
+
+ mincutorder = -1;
+ initcut = mincut = graph->mincut;
+ nbnd = graph->nbnd;
+
+ RandomPermute(nbnd, perm, 1);
+ for (ii=0; ii<nbnd; ii++) {
+ i = bndind[perm[ii]];
+ ASSERT(where[i] == 2);
+ PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]);
+ PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]);
+ }
+
+ ASSERT(CheckNodeBnd(graph, nbnd));
+ ASSERT(CheckNodePartitionParams(graph));
+
+ limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300));
+
+ /******************************************************
+ * Get into the FM loop
+ *******************************************************/
+ mptr[0] = nmind = 0;
+ mindiff = abs(pwgts[0]-pwgts[1]);
+ to = (pwgts[0] < pwgts[1] ? 0 : 1);
+ for (nswaps=0; nswaps<nvtxs; nswaps++) {
+ badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2]/2)/2);
+
+ u[0] = PQueueSeeMax(&parts[0]);
+ u[1] = PQueueSeeMax(&parts[1]);
+ if (u[0] != -1 && u[1] != -1) {
+ g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1];
+ g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0];
+
+ to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2));
+ /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */
+
+ if (pwgts[to]+vwgt[u[to]] > badmaxpwgt)
+ to = (to+1)%2;
+ }
+ else if (u[0] == -1 && u[1] == -1) {
+ break;
+ }
+ else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) {
+ to = 0;
+ }
+ else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) {
+ to = 1;
+ }
+ else
+ break;
+
+ other = (to+1)%2;
+
+ higain = PQueueGetMax(&parts[to]);
+ if (moved[higain] == -1) /* Delete if it was in the separator originally */
+ PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]);
+
+ ASSERT(bndptr[higain] != -1);
+
+ pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
+
+ newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
+ if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
+ mincut = pwgts[2];
+ mincutorder = nswaps;
+ mindiff = newdiff;
+ }
+ else {
+ if (nswaps - mincutorder > limit) {
+ pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
+ break; /* No further improvement, break out */
+ }
+ }
+
+ BNDDelete(nbnd, bndind, bndptr, higain);
+ pwgts[to] += vwgt[higain];
+ where[higain] = to;
+ moved[higain] = nswaps;
+ swaps[nswaps] = higain;
+
+
+ /**********************************************************
+ * Update the degrees of the affected nodes
+ ***********************************************************/
+ for (j=xadj[higain]; j<xadj[higain+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
+ oldgain = vwgt[k]-rinfo[k].edegrees[to];
+ rinfo[k].edegrees[to] += vwgt[higain];
+ if (moved[k] == -1 || moved[k] == -(2+other))
+ PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]);
+ }
+ else if (where[k] == other) { /* This vertex is pulled into the separator */
+ ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
+ BNDInsert(nbnd, bndind, bndptr, k);
+
+ mind[nmind++] = k; /* Keep track for rollback */
+ where[k] = 2;
+ pwgts[other] -= vwgt[k];
+
+ edegrees = rinfo[k].edegrees;
+ edegrees[0] = edegrees[1] = 0;
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ kk = adjncy[jj];
+ if (where[kk] != 2)
+ edegrees[where[kk]] += vwgt[kk];
+ else {
+ oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
+ rinfo[kk].edegrees[other] -= vwgt[k];
+ if (moved[kk] == -1 || moved[kk] == -(2+to))
+ PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]);
+ }
+ }
+
+ /* Insert the new vertex into the priority queue. Only one side! */
+ if (moved[k] == -1) {
+ PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]);
+ moved[k] = -(2+to);
+ }
+ }
+ }
+ mptr[nswaps+1] = nmind;
+
+ IFSET(ctrl->dbglvl, DBG_MOVEINFO,
+ printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2]));
+
+ }
+
+
+ /****************************************************************
+ * Roll back computation
+ *****************************************************************/
+ for (nswaps--; nswaps>mincutorder; nswaps--) {
+ higain = swaps[nswaps];
+
+ ASSERT(CheckNodePartitionParams(graph));
+
+ to = where[higain];
+ other = (to+1)%2;
+ INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
+ where[higain] = 2;
+ BNDInsert(nbnd, bndind, bndptr, higain);
+
+ edegrees = rinfo[higain].edegrees;
+ edegrees[0] = edegrees[1] = 0;
+ for (j=xadj[higain]; j<xadj[higain+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == 2)
+ rinfo[k].edegrees[to] -= vwgt[higain];
+ else
+ edegrees[where[k]] += vwgt[k];
+ }
+
+ /* Push nodes out of the separator */
+ for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
+ k = mind[j];
+ ASSERT(where[k] == 2);
+ where[k] = other;
+ INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
+ BNDDelete(nbnd, bndind, bndptr, k);
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ kk = adjncy[jj];
+ if (where[kk] == 2)
+ rinfo[kk].edegrees[other] += vwgt[k];
+ }
+ }
+ }
+
+ ASSERT(mincut == pwgts[2]);
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("\tMinimum sep: %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+1);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+}
+
+
+/*************************************************************************
+* This function performs a node-based FM refinement
+**************************************************************************/
+void FM_2WayNodeRefineEqWgt(CtrlType *ctrl, GraphType *graph, int npasses)
+{
+ int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;
+ idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
+ idxtype *mptr, *mind, *moved, *swaps, *perm;
+ PQueueType parts[2];
+ NRInfoType *rinfo;
+ int higain, oldgain, mincut, initcut, mincutorder;
+ int pass, to, other, limit;
+ int mindiff, newdiff;
+ int u[2], g[2];
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vwgt = graph->vwgt;
+
+ bndind = graph->bndind;
+ bndptr = graph->bndptr;
+ where = graph->where;
+ pwgts = graph->pwgts;
+ rinfo = graph->nrinfo;
+
+
+ i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt);
+ PQueueInit(ctrl, &parts[0], nvtxs, i);
+ PQueueInit(ctrl, &parts[1], nvtxs, i);
+
+ moved = idxwspacemalloc(ctrl, nvtxs);
+ swaps = idxwspacemalloc(ctrl, nvtxs);
+ mptr = idxwspacemalloc(ctrl, nvtxs+1);
+ mind = idxwspacemalloc(ctrl, nvtxs);
+ perm = idxwspacemalloc(ctrl, nvtxs);
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
+
+ for (pass=0; pass<npasses; pass++) {
+ idxset(nvtxs, -1, moved);
+ PQueueReset(&parts[0]);
+ PQueueReset(&parts[1]);
+
+ mincutorder = -1;
+ initcut = mincut = graph->mincut;
+ nbnd = graph->nbnd;
+
+ RandomPermute(nbnd, perm, 1);
+ for (ii=0; ii<nbnd; ii++) {
+ i = bndind[perm[ii]];
+ ASSERT(where[i] == 2);
+ PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]);
+ PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]);
+ }
+
+ ASSERT(CheckNodeBnd(graph, nbnd));
+ ASSERT(CheckNodePartitionParams(graph));
+
+ limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300));
+
+ /******************************************************
+ * Get into the FM loop
+ *******************************************************/
+ mptr[0] = nmind = 0;
+ mindiff = abs(pwgts[0]-pwgts[1]);
+ to = (pwgts[0] < pwgts[1] ? 0 : 1);
+ for (nswaps=0; nswaps<nvtxs; nswaps++) {
+ to = (pwgts[0] < pwgts[1] ? 0 : 1);
+
+ if (pwgts[0] == pwgts[1]) {
+ u[0] = PQueueSeeMax(&parts[0]);
+ u[1] = PQueueSeeMax(&parts[1]);
+ if (u[0] != -1 && u[1] != -1) {
+ g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1];
+ g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0];
+
+ to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2));
+ }
+ }
+ other = (to+1)%2;
+
+ if ((higain = PQueueGetMax(&parts[to])) == -1)
+ break;
+
+ if (moved[higain] == -1) /* Delete if it was in the separator originally */
+ PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]);
+
+ ASSERT(bndptr[higain] != -1);
+
+ pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
+
+ newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
+ if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
+ mincut = pwgts[2];
+ mincutorder = nswaps;
+ mindiff = newdiff;
+ }
+ else {
+ if (nswaps - mincutorder > limit) {
+ pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
+ break; /* No further improvement, break out */
+ }
+ }
+
+ BNDDelete(nbnd, bndind, bndptr, higain);
+ pwgts[to] += vwgt[higain];
+ where[higain] = to;
+ moved[higain] = nswaps;
+ swaps[nswaps] = higain;
+
+
+ /**********************************************************
+ * Update the degrees of the affected nodes
+ ***********************************************************/
+ for (j=xadj[higain]; j<xadj[higain+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
+ oldgain = vwgt[k]-rinfo[k].edegrees[to];
+ rinfo[k].edegrees[to] += vwgt[higain];
+ if (moved[k] == -1 || moved[k] == -(2+other))
+ PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]);
+ }
+ else if (where[k] == other) { /* This vertex is pulled into the separator */
+ ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
+ BNDInsert(nbnd, bndind, bndptr, k);
+
+ mind[nmind++] = k; /* Keep track for rollback */
+ where[k] = 2;
+ pwgts[other] -= vwgt[k];
+
+ edegrees = rinfo[k].edegrees;
+ edegrees[0] = edegrees[1] = 0;
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ kk = adjncy[jj];
+ if (where[kk] != 2)
+ edegrees[where[kk]] += vwgt[kk];
+ else {
+ oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
+ rinfo[kk].edegrees[other] -= vwgt[k];
+ if (moved[kk] == -1 || moved[kk] == -(2+to))
+ PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]);
+ }
+ }
+
+ /* Insert the new vertex into the priority queue. Only one side! */
+ if (moved[k] == -1) {
+ PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]);
+ moved[k] = -(2+to);
+ }
+ }
+ }
+ mptr[nswaps+1] = nmind;
+
+ IFSET(ctrl->dbglvl, DBG_MOVEINFO,
+ printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2]));
+
+ }
+
+
+ /****************************************************************
+ * Roll back computation
+ *****************************************************************/
+ for (nswaps--; nswaps>mincutorder; nswaps--) {
+ higain = swaps[nswaps];
+
+ ASSERT(CheckNodePartitionParams(graph));
+
+ to = where[higain];
+ other = (to+1)%2;
+ INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
+ where[higain] = 2;
+ BNDInsert(nbnd, bndind, bndptr, higain);
+
+ edegrees = rinfo[higain].edegrees;
+ edegrees[0] = edegrees[1] = 0;
+ for (j=xadj[higain]; j<xadj[higain+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == 2)
+ rinfo[k].edegrees[to] -= vwgt[higain];
+ else
+ edegrees[where[k]] += vwgt[k];
+ }
+
+ /* Push nodes out of the separator */
+ for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
+ k = mind[j];
+ ASSERT(where[k] == 2);
+ where[k] = other;
+ INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
+ BNDDelete(nbnd, bndind, bndptr, k);
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ kk = adjncy[jj];
+ if (where[kk] == 2)
+ rinfo[kk].edegrees[other] += vwgt[k];
+ }
+ }
+ }
+
+ ASSERT(mincut == pwgts[2]);
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("\tMinimum sep: %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+1);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+}
+
+
+/*************************************************************************
+* This function performs a node-based FM refinement. This is the
+* one-way version
+**************************************************************************/
+void FM_2WayNodeRefine_OneSided(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses)
+{
+ int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;
+ idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
+ idxtype *mptr, *mind, *swaps, *perm;
+ PQueueType parts;
+ NRInfoType *rinfo;
+ int higain, oldgain, mincut, initcut, mincutorder;
+ int pass, to, other, limit;
+ int badmaxpwgt, mindiff, newdiff;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vwgt = graph->vwgt;
+
+ bndind = graph->bndind;
+ bndptr = graph->bndptr;
+ where = graph->where;
+ pwgts = graph->pwgts;
+ rinfo = graph->nrinfo;
+
+ PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt));
+
+ perm = idxwspacemalloc(ctrl, nvtxs);
+ swaps = idxwspacemalloc(ctrl, nvtxs);
+ mptr = idxwspacemalloc(ctrl, nvtxs+1);
+ mind = idxwspacemalloc(ctrl, nvtxs);
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("Partitions-N1: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
+
+ badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2);
+
+ to = (pwgts[0] < pwgts[1] ? 1 : 0);
+ for (pass=0; pass<npasses; pass++) {
+ other = to;
+ to = (to+1)%2;
+
+ PQueueReset(&parts);
+
+ mincutorder = -1;
+ initcut = mincut = graph->mincut;
+ nbnd = graph->nbnd;
+
+ RandomPermute(nbnd, perm, 1);
+ for (ii=0; ii<nbnd; ii++) {
+ i = bndind[perm[ii]];
+ ASSERT(where[i] == 2);
+ PQueueInsert(&parts, i, vwgt[i]-rinfo[i].edegrees[other]);
+ }
+
+ ASSERT(CheckNodeBnd(graph, nbnd));
+ ASSERT(CheckNodePartitionParams(graph));
+
+ limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300));
+
+ /******************************************************
+ * Get into the FM loop
+ *******************************************************/
+ mptr[0] = nmind = 0;
+ mindiff = abs(pwgts[0]-pwgts[1]);
+ for (nswaps=0; nswaps<nvtxs; nswaps++) {
+
+ if ((higain = PQueueGetMax(&parts)) == -1)
+ break;
+
+ ASSERT(bndptr[higain] != -1);
+
+ if (pwgts[to]+vwgt[higain] > badmaxpwgt)
+ break; /* No point going any further. Balance will be bad */
+
+ pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
+
+ newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
+ if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
+ mincut = pwgts[2];
+ mincutorder = nswaps;
+ mindiff = newdiff;
+ }
+ else {
+ if (nswaps - mincutorder > limit) {
+ pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
+ break; /* No further improvement, break out */
+ }
+ }
+
+ BNDDelete(nbnd, bndind, bndptr, higain);
+ pwgts[to] += vwgt[higain];
+ where[higain] = to;
+ swaps[nswaps] = higain;
+
+
+ /**********************************************************
+ * Update the degrees of the affected nodes
+ ***********************************************************/
+ for (j=xadj[higain]; j<xadj[higain+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
+ rinfo[k].edegrees[to] += vwgt[higain];
+ }
+ else if (where[k] == other) { /* This vertex is pulled into the separator */
+ ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
+ BNDInsert(nbnd, bndind, bndptr, k);
+
+ mind[nmind++] = k; /* Keep track for rollback */
+ where[k] = 2;
+ pwgts[other] -= vwgt[k];
+
+ edegrees = rinfo[k].edegrees;
+ edegrees[0] = edegrees[1] = 0;
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ kk = adjncy[jj];
+ if (where[kk] != 2)
+ edegrees[where[kk]] += vwgt[kk];
+ else {
+ oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
+ rinfo[kk].edegrees[other] -= vwgt[k];
+
+ /* Since the moves are one-sided this vertex has not been moved yet */
+ PQueueUpdateUp(&parts, kk, oldgain, oldgain+vwgt[k]);
+ }
+ }
+
+ /* Insert the new vertex into the priority queue. Safe due to one-sided moves */
+ PQueueInsert(&parts, k, vwgt[k]-edegrees[other]);
+ }
+ }
+ mptr[nswaps+1] = nmind;
+
+
+ IFSET(ctrl->dbglvl, DBG_MOVEINFO,
+ printf("Moved %6d to %3d, Gain: %5d [%5d] \t[%5d %5d %5d] [%3d %2d]\n",
+ higain, to, (vwgt[higain]-rinfo[higain].edegrees[other]), vwgt[higain], pwgts[0], pwgts[1], pwgts[2], nswaps, limit));
+
+ }
+
+
+ /****************************************************************
+ * Roll back computation
+ *****************************************************************/
+ for (nswaps--; nswaps>mincutorder; nswaps--) {
+ higain = swaps[nswaps];
+
+ ASSERT(CheckNodePartitionParams(graph));
+ ASSERT(where[higain] == to);
+
+ INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
+ where[higain] = 2;
+ BNDInsert(nbnd, bndind, bndptr, higain);
+
+ edegrees = rinfo[higain].edegrees;
+ edegrees[0] = edegrees[1] = 0;
+ for (j=xadj[higain]; j<xadj[higain+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == 2)
+ rinfo[k].edegrees[to] -= vwgt[higain];
+ else
+ edegrees[where[k]] += vwgt[k];
+ }
+
+ /* Push nodes out of the separator */
+ for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
+ k = mind[j];
+ ASSERT(where[k] == 2);
+ where[k] = other;
+ INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
+ BNDDelete(nbnd, bndind, bndptr, k);
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ kk = adjncy[jj];
+ if (where[kk] == 2)
+ rinfo[kk].edegrees[other] += vwgt[k];
+ }
+ }
+ }
+
+ ASSERT(mincut == pwgts[2]);
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));
+
+ graph->mincut = mincut;
+ graph->nbnd = nbnd;
+
+ if (pass%2 == 1 && (mincutorder == -1 || mincut >= initcut))
+ break;
+ }
+
+ PQueueFree(ctrl, &parts);
+
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs+1);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+}
+
+
+
+/*************************************************************************
+* This function performs a node-based FM refinement
+**************************************************************************/
+void FM_2WayNodeBalance(CtrlType *ctrl, GraphType *graph, float ubfactor)
+{
+ int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps;
+ idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
+ idxtype *perm, *moved;
+ PQueueType parts;
+ NRInfoType *rinfo;
+ int higain, oldgain;
+ int pass, to, other;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vwgt = graph->vwgt;
+
+ bndind = graph->bndind;
+ bndptr = graph->bndptr;
+ where = graph->where;
+ pwgts = graph->pwgts;
+ rinfo = graph->nrinfo;
+
+ if (abs(pwgts[0]-pwgts[1]) < (int)((ubfactor-1.0)*(pwgts[0]+pwgts[1])))
+ return;
+ if (abs(pwgts[0]-pwgts[1]) < 3*idxsum(nvtxs, vwgt)/nvtxs)
+ return;
+
+ to = (pwgts[0] < pwgts[1] ? 0 : 1);
+ other = (to+1)%2;
+
+ PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt));
+
+ perm = idxwspacemalloc(ctrl, nvtxs);
+ moved = idxset(nvtxs, -1, idxwspacemalloc(ctrl, nvtxs));
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d [B]\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
+
+ nbnd = graph->nbnd;
+ RandomPermute(nbnd, perm, 1);
+ for (ii=0; ii<nbnd; ii++) {
+ i = bndind[perm[ii]];
+ ASSERT(where[i] == 2);
+ PQueueInsert(&parts, i, vwgt[i]-rinfo[i].edegrees[other]);
+ }
+
+ ASSERT(CheckNodeBnd(graph, nbnd));
+ ASSERT(CheckNodePartitionParams(graph));
+
+ /******************************************************
+ * Get into the FM loop
+ *******************************************************/
+ for (nswaps=0; nswaps<nvtxs; nswaps++) {
+ if ((higain = PQueueGetMax(&parts)) == -1)
+ break;
+
+ moved[higain] = 1;
+
+ if (pwgts[other] - rinfo[higain].edegrees[other] < (pwgts[0]+pwgts[1])/2)
+ continue;
+#ifdef XXX
+ if (pwgts[other] - rinfo[higain].edegrees[other] < pwgts[to]+vwgt[higain])
+ break;
+#endif
+
+ ASSERT(bndptr[higain] != -1);
+
+ pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
+
+ BNDDelete(nbnd, bndind, bndptr, higain);
+ pwgts[to] += vwgt[higain];
+ where[higain] = to;
+
+ IFSET(ctrl->dbglvl, DBG_MOVEINFO,
+ printf("Moved %6d to %3d, Gain: %3d, \t[%5d %5d %5d]\n", higain, to, vwgt[higain]-rinfo[higain].edegrees[other], pwgts[0], pwgts[1], pwgts[2]));
+
+
+ /**********************************************************
+ * Update the degrees of the affected nodes
+ ***********************************************************/
+ for (j=xadj[higain]; j<xadj[higain+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
+ rinfo[k].edegrees[to] += vwgt[higain];
+ }
+ else if (where[k] == other) { /* This vertex is pulled into the separator */
+ ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
+ BNDInsert(nbnd, bndind, bndptr, k);
+
+ where[k] = 2;
+ pwgts[other] -= vwgt[k];
+
+ edegrees = rinfo[k].edegrees;
+ edegrees[0] = edegrees[1] = 0;
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ kk = adjncy[jj];
+ if (where[kk] != 2)
+ edegrees[where[kk]] += vwgt[kk];
+ else {
+ ASSERT(bndptr[kk] != -1);
+ oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
+ rinfo[kk].edegrees[other] -= vwgt[k];
+
+ if (moved[kk] == -1)
+ PQueueUpdateUp(&parts, kk, oldgain, oldgain+vwgt[k]);
+ }
+ }
+
+ /* Insert the new vertex into the priority queue */
+ PQueueInsert(&parts, k, vwgt[k]-edegrees[other]);
+ }
+ }
+
+ if (pwgts[to] > pwgts[other])
+ break;
+ }
+
+ IFSET(ctrl->dbglvl, DBG_REFINE,
+ printf("\tBalanced sep: %6d at %4d, PWGTS: [%6d %6d], NBND: %6d\n", pwgts[2], nswaps, pwgts[0], pwgts[1], nbnd));
+
+ graph->mincut = pwgts[2];
+ graph->nbnd = nbnd;
+
+
+ PQueueFree(ctrl, &parts);
+
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+}
+
+
+/*************************************************************************
+* This function computes the maximum possible gain for a vertex
+**************************************************************************/
+int ComputeMaxNodeGain(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt)
+{
+ int i, j, k, max;
+
+ max = 0;
+ for (j=xadj[0]; j<xadj[1]; j++)
+ max += vwgt[adjncy[j]];
+
+ for (i=1; i<nvtxs; i++) {
+ for (k=0, j=xadj[i]; j<xadj[i+1]; j++)
+ k += vwgt[adjncy[j]];
+ if (max < k)
+ max = k;
+ }
+
+ return max;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/srefine.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/srefine.c
new file mode 100644
index 0000000..cd02cb9
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/srefine.c
@@ -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);
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stat.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stat.c
new file mode 100644
index 0000000..6156d6d
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stat.c
@@ -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);
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stats.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stats.c
new file mode 100644
index 0000000..4f6b548
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stats.c
@@ -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);
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stdheaders.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stdheaders.h
new file mode 100644
index 0000000..f82b0cb
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/stdheaders.h
@@ -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>
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/struct.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/struct.h
new file mode 100644
index 0000000..ff091c6
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/struct.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;
+
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/subdomains.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/subdomains.c
new file mode 100644
index 0000000..6fc65e7
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/subdomains.c
@@ -0,0 +1,1295 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * subdomains.c
+ *
+ * This file contains functions that deal with prunning the number of
+ * adjacent subdomains in KMETIS
+ *
+ * Started 7/15/98
+ * George
+ *
+ * $Id: subdomains.c,v 1.2 2003/07/31 06:14:01 karypis Exp $
+ *
+ */
+
+#include <metis.h>
+
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void Random_KWayEdgeRefineMConn(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;
+ int maxndoms, nadd;
+ idxtype *xadj, *adjncy, *adjwgt;
+ idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts;
+ idxtype *phtable, *pmat, *pmatptr, *ndoms;
+ 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;
+
+ pmat = ctrl->wspace.pmat;
+ phtable = idxwspacemalloc(ctrl, nparts);
+ ndoms = idxwspacemalloc(ctrl, nparts);
+
+ ComputeSubDomainGraph(graph, nparts, pmat, ndoms);
+
+ /* 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);
+
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+
+ 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;
+
+ /* Determine the valid domains */
+ for (j=0; j<myndegrees; j++) {
+ to = myedegrees[j].pid;
+ phtable[to] = 1;
+ pmatptr = pmat + to*nparts;
+ for (nadd=0, k=0; k<myndegrees; k++) {
+ if (k == j)
+ continue;
+
+ l = myedegrees[k].pid;
+ if (pmatptr[l] == 0) {
+ if (ndoms[l] > maxndoms-1) {
+ phtable[to] = 0;
+ nadd = maxndoms;
+ break;
+ }
+ nadd++;
+ }
+ }
+ if (ndoms[to]+nadd > maxndoms)
+ phtable[to] = 0;
+ if (nadd == 0)
+ phtable[to] = 2;
+ }
+
+ /* Find the first valid move */
+ j = myrinfo->id;
+ for (k=0; k<myndegrees; k++) {
+ to = myedegrees[k].pid;
+ if (!phtable[to])
+ continue;
+ 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 (!phtable[to])
+ continue;
+ 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 ||*/ phtable[myedegrees[k].pid] == 2 || 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 pmat to reflect the move of 'i' */
+ pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
+ pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
+ if (pmat[from*nparts+to] == 0) {
+ ndoms[from]--;
+ if (ndoms[from]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+ if (pmat[to*nparts+from] == 0) {
+ ndoms[to]--;
+ if (ndoms[to]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+
+ /* 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];
+ }
+ }
+
+ /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
+ if (me != from && me != to) {
+ pmat[me*nparts+from] -= adjwgt[j];
+ pmat[from*nparts+me] -= adjwgt[j];
+ if (pmat[me*nparts+from] == 0) {
+ ndoms[me]--;
+ if (ndoms[me]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+ if (pmat[from*nparts+me] == 0) {
+ ndoms[from]--;
+ if (ndoms[from]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+
+ if (pmat[me*nparts+to] == 0) {
+ ndoms[me]++;
+ if (ndoms[me] > maxndoms) {
+ IFSET(ctrl->dbglvl, DBG_REFINE, printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms));
+ maxndoms = ndoms[me];
+ }
+ }
+ if (pmat[to*nparts+me] == 0) {
+ ndoms[to]++;
+ if (ndoms[to] > maxndoms) {
+ IFSET(ctrl->dbglvl, DBG_REFINE, printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms));
+ maxndoms = ndoms[to];
+ }
+ }
+ pmat[me*nparts+to] += adjwgt[j];
+ pmat[to*nparts+me] += 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: %5d, Vol: %5d, %d\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), idxsum(nparts, ndoms)));
+
+ if (graph->mincut == oldcut)
+ break;
+ }
+
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nvtxs);
+}
+
+
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void Greedy_KWayEdgeBalanceMConn(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, maxndoms, nadd;
+ idxtype *xadj, *adjncy, *adjwgt;
+ idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts;
+ idxtype *phtable, *pmat, *pmatptr, *ndoms;
+ 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;
+
+ pmat = ctrl->wspace.pmat;
+ phtable = idxwspacemalloc(ctrl, nparts);
+ ndoms = idxwspacemalloc(ctrl, nparts);
+
+ ComputeSubDomainGraph(graph, nparts, pmat, ndoms);
+
+
+ /* 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;
+ }
+
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+
+ for (nmoves=0;;) {
+ 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;
+
+ /* Determine the valid domains */
+ for (j=0; j<myndegrees; j++) {
+ to = myedegrees[j].pid;
+ phtable[to] = 1;
+ pmatptr = pmat + to*nparts;
+ for (nadd=0, k=0; k<myndegrees; k++) {
+ if (k == j)
+ continue;
+
+ l = myedegrees[k].pid;
+ if (pmatptr[l] == 0) {
+ if (ndoms[l] > maxndoms-1) {
+ phtable[to] = 0;
+ nadd = maxndoms;
+ break;
+ }
+ nadd++;
+ }
+ }
+ if (ndoms[to]+nadd > maxndoms)
+ phtable[to] = 0;
+ }
+
+ for (k=0; k<myndegrees; k++) {
+ to = myedegrees[k].pid;
+ if (!phtable[to])
+ continue;
+ 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 (!phtable[to])
+ continue;
+ 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 pmat to reflect the move of 'i' */
+ pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
+ pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
+ if (pmat[from*nparts+to] == 0) {
+ ndoms[from]--;
+ if (ndoms[from]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+ if (pmat[to*nparts+from] == 0) {
+ ndoms[to]--;
+ if (ndoms[to]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+
+
+ /* 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 pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
+ if (me != from && me != to) {
+ pmat[me*nparts+from] -= adjwgt[j];
+ pmat[from*nparts+me] -= adjwgt[j];
+ if (pmat[me*nparts+from] == 0) {
+ ndoms[me]--;
+ if (ndoms[me]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+ if (pmat[from*nparts+me] == 0) {
+ ndoms[from]--;
+ if (ndoms[from]+1 == maxndoms)
+ maxndoms = ndoms[idxamax(nparts, ndoms)];
+ }
+
+ if (pmat[me*nparts+to] == 0) {
+ ndoms[me]++;
+ if (ndoms[me] > maxndoms) {
+ IFSET(ctrl->dbglvl, DBG_REFINE, printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms));
+ maxndoms = ndoms[me];
+ }
+ }
+ if (pmat[to*nparts+me] == 0) {
+ ndoms[to]++;
+ if (ndoms[to] > maxndoms) {
+ IFSET(ctrl->dbglvl, DBG_REFINE, printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms));
+ maxndoms = ndoms[to];
+ }
+ }
+ pmat[me*nparts+to] += adjwgt[j];
+ pmat[to*nparts+me] += 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, %d\n",
+ pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
+ 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut,idxsum(nparts, ndoms)));
+ }
+
+ PQueueFree(ctrl, &queue);
+
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+
+}
+
+
+
+
+/*************************************************************************
+* This function computes the subdomain graph
+**************************************************************************/
+void PrintSubDomainGraph(GraphType *graph, int nparts, idxtype *where)
+{
+ int i, j, k, me, nvtxs, total, max;
+ idxtype *xadj, *adjncy, *adjwgt, *pmat;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+
+ pmat = idxsmalloc(nparts*nparts, 0, "ComputeSubDomainGraph: pmat");
+
+ for (i=0; i<nvtxs; i++) {
+ me = where[i];
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = adjncy[j];
+ if (where[k] != me)
+ pmat[me*nparts+where[k]] += adjwgt[j];
+ }
+ }
+
+ /* printf("Subdomain Info\n"); */
+ total = max = 0;
+ for (i=0; i<nparts; i++) {
+ for (k=0, j=0; j<nparts; j++) {
+ if (pmat[i*nparts+j] > 0)
+ k++;
+ }
+ total += k;
+
+ if (k > max)
+ max = k;
+/*
+ printf("%2d -> %2d ", i, k);
+ for (j=0; j<nparts; j++) {
+ if (pmat[i*nparts+j] > 0)
+ printf("[%2d %4d] ", j, pmat[i*nparts+j]);
+ }
+ printf("\n");
+*/
+ }
+ printf("Total adjacent subdomains: %d, Max: %d\n", total, max);
+
+ free(pmat);
+}
+
+
+
+/*************************************************************************
+* This function computes the subdomain graph
+**************************************************************************/
+void ComputeSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms)
+{
+ int i, j, k, me, nvtxs, ndegrees;
+ idxtype *xadj, *adjncy, *adjwgt, *where;
+ RInfoType *rinfo;
+ EDegreeType *edegrees;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ rinfo = graph->rinfo;
+
+ idxset(nparts*nparts, 0, pmat);
+
+ for (i=0; i<nvtxs; i++) {
+ if (rinfo[i].ed > 0) {
+ me = where[i];
+ ndegrees = rinfo[i].ndegrees;
+ edegrees = rinfo[i].edegrees;
+
+ k = me*nparts;
+ for (j=0; j<ndegrees; j++)
+ pmat[k+edegrees[j].pid] += edegrees[j].ed;
+ }
+ }
+
+ for (i=0; i<nparts; i++) {
+ ndoms[i] = 0;
+ for (j=0; j<nparts; j++) {
+ if (pmat[i*nparts+j] > 0)
+ ndoms[i]++;
+ }
+ }
+
+}
+
+
+
+
+
+/*************************************************************************
+* This function computes the subdomain graph
+**************************************************************************/
+void EliminateSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts)
+{
+ int i, ii, j, k, me, other, nvtxs, total, max, avg, totalout, nind, ncand, ncand2, target, target2, nadd;
+ int min, move, cpwgt, tvwgt;
+ idxtype *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt, *pmat, *ndoms, *mypmat, *otherpmat, *ind;
+ KeyValueType *cand, *cand2;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vwgt = graph->vwgt;
+ adjwgt = graph->adjwgt;
+
+ where = graph->where;
+ pwgts = graph->pwgts; /* We assume that this is properly initialized */
+
+ maxpwgt = idxwspacemalloc(ctrl, nparts);
+ ndoms = idxwspacemalloc(ctrl, nparts);
+ otherpmat = idxwspacemalloc(ctrl, nparts);
+ ind = idxwspacemalloc(ctrl, nvtxs);
+ pmat = ctrl->wspace.pmat;
+
+ cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
+ cand2 = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
+
+ /* Compute the pmat matrix and ndoms */
+ ComputeSubDomainGraph(graph, nparts, pmat, ndoms);
+
+
+ /* Compute the maximum allowed weight for each domain */
+ tvwgt = idxsum(nparts, pwgts);
+ for (i=0; i<nparts; i++)
+ maxpwgt[i] = 1.25*tpwgts[i]*tvwgt;
+
+
+ /* Get into the loop eliminating subdomain connections */
+ for (;;) {
+ total = idxsum(nparts, ndoms);
+ avg = total/nparts;
+ max = ndoms[idxamax(nparts, ndoms)];
+
+ /* printf("Adjacent Subdomain Stats: Total: %3d, Max: %3d, Avg: %3d [%5d]\n", total, max, avg, idxsum(nparts*nparts, pmat)); */
+
+ if (max < 1.4*avg)
+ break;
+
+ me = idxamax(nparts, ndoms);
+ mypmat = pmat + me*nparts;
+ totalout = idxsum(nparts, mypmat);
+
+ /*printf("Me: %d, TotalOut: %d,\n", me, totalout);*/
+
+ /* Sort the connections according to their cut */
+ for (ncand2=0, i=0; i<nparts; i++) {
+ if (mypmat[i] > 0) {
+ cand2[ncand2].key = mypmat[i];
+ cand2[ncand2++].val = i;
+ }
+ }
+ ikeysort(ncand2, cand2);
+
+ move = 0;
+ for (min=0; min<ncand2; min++) {
+ if (cand2[min].key > totalout/(2*ndoms[me]))
+ break;
+
+ other = cand2[min].val;
+
+ /*printf("\tMinOut: %d to %d\n", mypmat[other], other);*/
+
+ idxset(nparts, 0, otherpmat);
+
+ /* Go and find the vertices in 'other' that are connected in 'me' */
+ for (nind=0, i=0; i<nvtxs; i++) {
+ if (where[i] == other) {
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ if (where[adjncy[j]] == me) {
+ ind[nind++] = i;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Go and construct the otherpmat to see where these nind vertices are connected to */
+ for (cpwgt=0, ii=0; ii<nind; ii++) {
+ i = ind[ii];
+ cpwgt += vwgt[i];
+
+ for (j=xadj[i]; j<xadj[i+1]; j++)
+ otherpmat[where[adjncy[j]]] += adjwgt[j];
+ }
+ otherpmat[other] = 0;
+
+ for (ncand=0, i=0; i<nparts; i++) {
+ if (otherpmat[i] > 0) {
+ cand[ncand].key = -otherpmat[i];
+ cand[ncand++].val = i;
+ }
+ }
+ ikeysort(ncand, cand);
+
+ /*
+ * Go through and the select the first domain that is common with 'me', and
+ * does not increase the ndoms[target] higher than my ndoms, subject to the
+ * maxpwgt constraint. Traversal is done from the mostly connected to the least.
+ */
+ target = target2 = -1;
+ for (i=0; i<ncand; i++) {
+ k = cand[i].val;
+
+ if (mypmat[k] > 0) {
+ if (pwgts[k] + cpwgt > maxpwgt[k]) /* Check if balance will go off */
+ continue;
+
+ for (j=0; j<nparts; j++) {
+ if (otherpmat[j] > 0 && ndoms[j] >= ndoms[me]-1 && pmat[nparts*j+k] == 0)
+ break;
+ }
+ if (j == nparts) { /* No bad second level effects */
+ for (nadd=0, j=0; j<nparts; j++) {
+ if (otherpmat[j] > 0 && pmat[nparts*k+j] == 0)
+ nadd++;
+ }
+
+ /*printf("\t\tto=%d, nadd=%d, %d\n", k, nadd, ndoms[k]);*/
+ if (target2 == -1 && ndoms[k]+nadd < ndoms[me]) {
+ target2 = k;
+ }
+ if (nadd == 0) {
+ target = k;
+ break;
+ }
+ }
+ }
+ }
+ if (target == -1 && target2 != -1)
+ target = target2;
+
+ if (target == -1) {
+ /* printf("\t\tCould not make the move\n");*/
+ continue;
+ }
+
+ /*printf("\t\tMoving to %d\n", target);*/
+
+ /* Update the partition weights */
+ INC_DEC(pwgts[target], pwgts[other], cpwgt);
+
+ MoveGroupMConn(ctrl, graph, ndoms, pmat, nparts, target, nind, ind);
+
+ move = 1;
+ break;
+ }
+
+ if (move == 0)
+ break;
+ }
+
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nvtxs);
+
+ GKfree(&cand, &cand2, LTERM);
+}
+
+
+/*************************************************************************
+* This function moves a collection of vertices and updates their rinfo
+**************************************************************************/
+void MoveGroupMConn(CtrlType *ctrl, GraphType *graph, idxtype *ndoms, idxtype *pmat,
+ int nparts, int to, int nind, idxtype *ind)
+{
+ int i, ii, iii, j, jj, k, l, nvtxs, nbnd, myndegrees;
+ int from, me;
+ idxtype *xadj, *adjncy, *adjwgt;
+ idxtype *where, *bndptr, *bndind;
+ EDegreeType *myedegrees;
+ RInfoType *myrinfo;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+
+ where = graph->where;
+ bndptr = graph->bndptr;
+ bndind = graph->bndind;
+
+ nbnd = graph->nbnd;
+
+ for (iii=0; iii<nind; iii++) {
+ i = ind[iii];
+ from = where[i];
+
+ myrinfo = graph->rinfo+i;
+ if (myrinfo->edegrees == NULL) {
+ myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
+ ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
+ myrinfo->ndegrees = 0;
+ }
+ myedegrees = myrinfo->edegrees;
+
+ /* find the location of 'to' in myrinfo or create it if it is not there */
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (myedegrees[k].pid == to)
+ break;
+ }
+ if (k == myrinfo->ndegrees) {
+ myedegrees[k].pid = to;
+ myedegrees[k].ed = 0;
+ myrinfo->ndegrees++;
+ }
+
+ graph->mincut -= myedegrees[k].ed-myrinfo->id;
+
+ /* Update pmat to reflect the move of 'i' */
+ pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
+ pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
+ if (pmat[from*nparts+to] == 0)
+ ndoms[from]--;
+ if (pmat[to*nparts+from] == 0)
+ ndoms[to]--;
+
+ /* Update where, weight, and ID/ED information of the vertex you moved */
+ 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 && bndptr[i] != -1)
+ 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];
+ }
+ }
+
+ /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
+ if (me != from && me != to) {
+ pmat[me*nparts+from] -= adjwgt[j];
+ pmat[from*nparts+me] -= adjwgt[j];
+ if (pmat[me*nparts+from] == 0)
+ ndoms[me]--;
+ if (pmat[from*nparts+me] == 0)
+ ndoms[from]--;
+
+ if (pmat[me*nparts+to] == 0)
+ ndoms[me]++;
+ if (pmat[to*nparts+me] == 0)
+ ndoms[to]++;
+
+ pmat[me*nparts+to] += adjwgt[j];
+ pmat[to*nparts+me] += adjwgt[j];
+ }
+
+ ASSERT(CheckRInfo(myrinfo));
+ }
+
+ ASSERT(CheckRInfo(graph->rinfo+i));
+ }
+
+ graph->nbnd = nbnd;
+
+}
+
+
+
+
+/*************************************************************************
+* This function finds all the connected components induced by the
+* partitioning vector in wgraph->where and tries to push them around to
+* remove some of them
+**************************************************************************/
+void EliminateComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
+{
+ int i, ii, j, jj, k, me, nvtxs, tvwgt, first, last, nleft, ncmps, cwgt, other, target, deltawgt;
+ idxtype *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts, *maxpwgt;
+ idxtype *cpvec, *touched, *perm, *todo, *cind, *cptr, *npcmps;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vwgt = graph->vwgt;
+ adjwgt = graph->adjwgt;
+
+ where = graph->where;
+ pwgts = graph->pwgts;
+
+ touched = idxset(nvtxs, 0, idxwspacemalloc(ctrl, nvtxs));
+ cptr = idxwspacemalloc(ctrl, nvtxs+1);
+ cind = idxwspacemalloc(ctrl, nvtxs);
+ perm = idxwspacemalloc(ctrl, nvtxs);
+ todo = idxwspacemalloc(ctrl, nvtxs);
+ maxpwgt = idxwspacemalloc(ctrl, nparts);
+ cpvec = idxwspacemalloc(ctrl, nparts);
+ npcmps = idxset(nparts, 0, idxwspacemalloc(ctrl, nparts));
+
+ for (i=0; i<nvtxs; i++)
+ perm[i] = todo[i] = i;
+
+ /* Find the connected componends induced by the partition */
+ ncmps = -1;
+ first = last = 0;
+ nleft = nvtxs;
+ while (nleft > 0) {
+ if (first == last) { /* Find another starting vertex */
+ cptr[++ncmps] = first;
+ ASSERT(touched[todo[0]] == 0);
+ i = todo[0];
+ cind[last++] = i;
+ touched[i] = 1;
+ me = where[i];
+ npcmps[me]++;
+ }
+
+ i = cind[first++];
+ k = perm[i];
+ j = todo[k] = todo[--nleft];
+ perm[j] = k;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = adjncy[j];
+ if (where[k] == me && !touched[k]) {
+ cind[last++] = k;
+ touched[k] = 1;
+ }
+ }
+ }
+ cptr[++ncmps] = first;
+
+ /* printf("I found %d components, for this %d-way partition\n", ncmps, nparts); */
+
+ if (ncmps > nparts) { /* There are more components than processors */
+ /* First determine the max allowed load imbalance */
+ tvwgt = idxsum(nparts, pwgts);
+ for (i=0; i<nparts; i++)
+ maxpwgt[i] = ubfactor*tpwgts[i]*tvwgt;
+
+ deltawgt = 5;
+
+ for (i=0; i<ncmps; i++) {
+ me = where[cind[cptr[i]]]; /* Get the domain of this component */
+ if (npcmps[me] == 1)
+ continue; /* Skip it because it is contigous */
+
+ /*printf("Trying to move %d from %d\n", i, me); */
+
+ /* Determine the weight of the block to be moved and abort if too high */
+ for (cwgt=0, j=cptr[i]; j<cptr[i+1]; j++)
+ cwgt += vwgt[cind[j]];
+
+ if (cwgt > .30*pwgts[me])
+ continue; /* Skip the component if it is over 30% of the weight */
+
+ /* Determine the connectivity */
+ idxset(nparts, 0, cpvec);
+ for (j=cptr[i]; j<cptr[i+1]; j++) {
+ ii = cind[j];
+ for (jj=xadj[ii]; jj<xadj[ii+1]; jj++)
+ cpvec[where[adjncy[jj]]] += adjwgt[jj];
+ }
+ cpvec[me] = 0;
+
+ target = -1;
+ for (j=0; j<nparts; j++) {
+ if (cpvec[j] > 0 && (cwgt < deltawgt || pwgts[j] + cwgt < maxpwgt[j])) {
+ if (target == -1 || cpvec[target] < cpvec[j])
+ target = j;
+ }
+ }
+
+ /* printf("\tMoving it to %d [%d]\n", target, cpvec[target]);*/
+
+ if (target != -1) {
+ /* Assign all the vertices of 'me' to 'target' and update data structures */
+ INC_DEC(pwgts[target], pwgts[me], cwgt);
+ npcmps[me]--;
+
+ MoveGroup(ctrl, graph, nparts, target, i, cptr, cind);
+ }
+ }
+
+ }
+
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nparts);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs);
+ idxwspacefree(ctrl, nvtxs+1);
+
+}
+
+
+/*************************************************************************
+* This function moves a collection of vertices and updates their rinfo
+**************************************************************************/
+void MoveGroup(CtrlType *ctrl, GraphType *graph, int nparts, int to, int gid, idxtype *ptr, idxtype *ind)
+{
+ int i, ii, iii, j, jj, k, l, nvtxs, nbnd, myndegrees;
+ int from, me;
+ idxtype *xadj, *adjncy, *adjwgt;
+ idxtype *where, *bndptr, *bndind;
+ EDegreeType *myedegrees;
+ RInfoType *myrinfo;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+
+ where = graph->where;
+ bndptr = graph->bndptr;
+ bndind = graph->bndind;
+
+ nbnd = graph->nbnd;
+
+ for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) {
+ i = ind[iii];
+ from = where[i];
+
+ myrinfo = graph->rinfo+i;
+ if (myrinfo->edegrees == NULL) {
+ myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
+ ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
+ myrinfo->ndegrees = 0;
+ }
+ myedegrees = myrinfo->edegrees;
+
+ /* find the location of 'to' in myrinfo or create it if it is not there */
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (myedegrees[k].pid == to)
+ break;
+ }
+ if (k == myrinfo->ndegrees) {
+ myedegrees[k].pid = to;
+ myedegrees[k].ed = 0;
+ myrinfo->ndegrees++;
+ }
+
+ graph->mincut -= myedegrees[k].ed-myrinfo->id;
+
+
+ /* Update where, weight, and ID/ED information of the vertex you moved */
+ 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 && bndptr[i] != -1)
+ 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(CheckRInfo(myrinfo));
+ }
+
+ ASSERT(CheckRInfo(graph->rinfo+i));
+ }
+
+ graph->nbnd = nbnd;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/timing.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/timing.c
new file mode 100644
index 0000000..a9d0910
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/timing.c
@@ -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);
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/util.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/util.c
new file mode 100644
index 0000000..5d2e739
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/METISLib/util.c
@@ -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;
+}
+