summaryrefslogtreecommitdiff
path: root/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib
diff options
context:
space:
mode:
authorTor Aamodt <[email protected]>2010-07-15 18:09:46 -0800
committerTor Aamodt <[email protected]>2010-07-15 18:09:46 -0800
commit69f2911e04ffb1b19eef1fafb8c040af271f656e (patch)
tree231d3b6bdc3a202f7c255bfcf7bf2c36e32cee9e /benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib
creating branch for adding support for CUDA 3.x and Fermi
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 6829]
Diffstat (limited to 'benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib')
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/Makefile48
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/adrivers.c117
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/akwayfm.c629
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ametis.c272
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/backcompat.c517
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/balancemylink.c342
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/coarsen.c485
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/comm.c213
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/csrmatch.c88
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/debug.c247
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/defs.h102
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/diffutil.c298
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/fpqueue.c440
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/frename.c322
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/gkmetis.c331
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/grsetup.c274
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/iidxsort.c152
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/iintsort.c157
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ikeysort.c151
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ikeyvalsort.c151
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initbalance.c498
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initmsection.c242
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initpart.c252
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kmetis.c274
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwaybalance.c456
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwayfm.c599
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwayrefine.c239
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/lmatch.c364
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/macros.h163
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/match.c320
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mdiffusion.c455
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mdrivers.c116
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/memory.c216
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mesh.c335
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mmetis.c95
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/move.c338
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/msetup.c95
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/node_refine.c383
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ometis.c188
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/order.c348
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/parmetislib.h31
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/proto.h352
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/pspases.c167
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/redomylink.c175
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/remap.c181
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/rename.h290
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/rmetis.c165
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/selectq.c340
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/serial.c1251
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/setup.c219
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/stat.c332
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/stdheaders.h25
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/struct.h290
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/sync186
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/timer.c90
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/util.c983
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/wave.c241
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/weird.c275
-rw-r--r--benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/xyzpart.c257
59 files changed, 17162 insertions, 0 deletions
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/Makefile b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/Makefile
new file mode 100644
index 0000000..3281a07
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/Makefile
@@ -0,0 +1,48 @@
+include ../Makefile.in
+
+
+CFLAGS = $(COPTIONS) $(OPTFLAGS) -I. $(INCDIR)
+
+
+OBJS = comm.o util.o debug.o setup.o grsetup.o timer.o \
+ node_refine.o initmsection.o order.o \
+ xyzpart.o pspases.o frename.o \
+ iintsort.o iidxsort.o ikeysort.o ikeyvalsort.o \
+ kmetis.o gkmetis.o ometis.o \
+ initpart.o match.o coarsen.o \
+ kwayfm.o kwayrefine.o kwaybalance.o \
+ remap.o stat.o fpqueue.o \
+ ametis.o rmetis.o lmatch.o initbalance.o \
+ mdiffusion.o diffutil.o wave.o \
+ csrmatch.o redomylink.o balancemylink.o \
+ selectq.o akwayfm.o serial.o move.o \
+ mmetis.o mesh.o memory.o weird.o backcompat.o
+
+.c.o:
+ $(CC) $(CFLAGS) -c $*.c
+
+
+../libparmetis.a: $(OBJS)
+ $(AR) $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ rm -f *.o
+
+realclean:
+ rm -f *.o ; rm -f ../libparmetis.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/ParMETISLib/adrivers.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/adrivers.c
new file mode 100644
index 0000000..e9c5fe0
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/adrivers.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * adrivers.c
+ *
+ * This file contains the driving routines for the various parallel
+ * multilevel partitioning and repartitioning algorithms
+ *
+ * Started 11/19/96
+ * George
+ *
+ * $Id: adrivers.c,v 1.5 2003/07/30 18:37:58 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+/*************************************************************************
+* This function is the driver for the adaptive refinement mode of ParMETIS
+**************************************************************************/
+void Adaptive_Partition(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i;
+ int tewgt, tvsize;
+ float gtewgt, gtvsize;
+ float ubavg, lbavg, lbvec[MAXNCON];
+
+ /************************************/
+ /* Set up important data structures */
+ /************************************/
+ SetUp(ctrl, graph, wspace);
+
+ ubavg = savg(graph->ncon, ctrl->ubvec);
+ tewgt = idxsum(graph->nedges, graph->adjwgt);
+ tvsize = idxsum(graph->nvtxs, graph->vsize);
+ gtewgt = (float) GlobalSESum(ctrl, tewgt) + 1.0; /* The +1 were added to remove any FPE */
+ gtvsize = (float) GlobalSESum(ctrl, tvsize) + 1.0;
+ ctrl->redist_factor = ctrl->redist_base * ((gtewgt/gtvsize)/ ctrl->edge_size_ratio);
+
+ IFSET(ctrl->dbglvl, DBG_PROGRESS, rprintf(ctrl, "[%6d %8d %5d %5d][%d]\n",
+ graph->gnvtxs, GlobalSESum(ctrl, graph->nedges), GlobalSEMin(ctrl, graph->nvtxs), GlobalSEMax(ctrl, graph->nvtxs), ctrl->CoarsenTo));
+
+ if (graph->gnvtxs < 1.3*ctrl->CoarsenTo ||
+ (graph->finer != NULL && graph->gnvtxs > graph->finer->gnvtxs*COARSEN_FRACTION)) {
+
+ /***********************************************/
+ /* Balance the partition on the coarsest graph */
+ /***********************************************/
+ graph->where = idxsmalloc(graph->nvtxs+graph->nrecv, -1, "graph->where");
+ idxcopy(graph->nvtxs, graph->home, graph->where);
+
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ lbavg = savg(graph->ncon, lbvec);
+
+ if (lbavg > ubavg + 0.035 && ctrl->partType != REFINE_PARTITION)
+ Balance_Partition(ctrl, graph, wspace);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, balance: ", graph->gnvtxs);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+
+ /* check if no coarsening took place */
+ if (graph->finer == NULL) {
+ Moc_ComputePartitionParams(ctrl, graph, wspace);
+ Moc_KWayBalance(ctrl, graph, wspace, graph->ncon);
+ Moc_KWayAdaptiveRefine(ctrl, graph, wspace, NGR_PASSES);
+ }
+ }
+ else {
+ /*******************************/
+ /* Coarsen it and partition it */
+ /*******************************/
+ switch (ctrl->ps_relation) {
+ case COUPLED:
+ Mc_LocalMatch_HEM(ctrl, graph, wspace);
+ break;
+ case DISCOUPLED:
+ default:
+ Moc_GlobalMatch_Balance(ctrl, graph, wspace);
+ break;
+ }
+
+ Adaptive_Partition(ctrl, graph->coarser, wspace);
+
+ /********************************/
+ /* project partition and refine */
+ /********************************/
+ Moc_ProjectPartition(ctrl, graph, wspace);
+ Moc_ComputePartitionParams(ctrl, graph, wspace);
+
+ if (graph->ncon > 1 && graph->level < 4) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ lbavg = savg(graph->ncon, lbvec);
+
+ if (lbavg > ubavg + 0.025) {
+ Moc_KWayBalance(ctrl, graph, wspace, graph->ncon);
+ }
+ }
+
+ Moc_KWayAdaptiveRefine(ctrl, graph, wspace, NGR_PASSES);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, cut: %8d, balance: ", graph->gnvtxs, graph->mincut);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+ }
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/akwayfm.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/akwayfm.c
new file mode 100644
index 0000000..7579d8b
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/akwayfm.c
@@ -0,0 +1,629 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * makwayfm.c
+ *
+ * This file contains code that performs the k-way refinement
+ *
+ * Started 3/1/96
+ * George
+ *
+ * $Id: akwayfm.c,v 1.3 2003/07/22 22:58:18 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+#define ProperSide(c, from, other) \
+ (((c) == 0 && (from)-(other) < 0) || ((c) == 1 && (from)-(other) > 0))
+
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void Moc_KWayAdaptiveRefine(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace, int npasses)
+{
+ int h, i, ii, iii, j, k, c;
+ int pass, nvtxs, nedges, ncon;
+ int nmoves, nmoved;
+ int me, firstvtx, lastvtx, yourlastvtx;
+ int from, to = -1, oldto, oldcut, mydomain, yourdomain, imbalanced, overweight;
+ int npes = ctrl->npes, mype = ctrl->mype, nparts = ctrl->nparts;
+ int nlupd, nsupd, nnbrs, nchanged;
+ idxtype *xadj, *ladjncy, *adjwgt, *vtxdist;
+ idxtype *where, *tmp_where, *moved;
+ float *lnpwgts, *gnpwgts, *ognpwgts, *pgnpwgts, *movewgts, *overfill;
+ idxtype *update, *supdate, *rupdate, *pe_updates;
+ idxtype *changed, *perm, *pperm, *htable;
+ idxtype *peind, *recvptr, *sendptr;
+ KeyValueType *swchanges, *rwchanges;
+ RInfoType *rinfo, *myrinfo, *tmp_myrinfo, *tmp_rinfo;
+ EdgeType *tmp_edegrees, *my_edegrees, *your_edegrees;
+ float lbvec[MAXNCON], *nvwgt, *badmaxpwgt, *ubvec, *tpwgts, lbavg, ubavg;
+ float oldgain, gain;
+ float ipc_factor, redist_factor, vsize;
+ int *nupds_pe, ndirty, nclean, dptr;
+ int better, worse;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->KWayTmr));
+
+ /*************************/
+ /* set up common aliases */
+ /*************************/
+ nvtxs = graph->nvtxs;
+ nedges = graph->nedges;
+ ncon = graph->ncon;
+
+ vtxdist = graph->vtxdist;
+ xadj = graph->xadj;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+
+ firstvtx = vtxdist[mype];
+ lastvtx = vtxdist[mype+1];
+
+ where = graph->where;
+ rinfo = graph->rinfo;
+ lnpwgts = graph->lnpwgts;
+ gnpwgts = graph->gnpwgts;
+ ubvec = ctrl->ubvec;
+ tpwgts = ctrl->tpwgts;
+ ipc_factor = ctrl->ipc_factor;
+ redist_factor = ctrl->redist_factor;
+
+ nnbrs = graph->nnbrs;
+ peind = graph->peind;
+ recvptr = graph->recvptr;
+ sendptr = graph->sendptr;
+
+ changed = idxmalloc(nvtxs, "AKWR: changed");
+ rwchanges = wspace->pairs;
+ swchanges = rwchanges + recvptr[nnbrs];
+
+ /************************************/
+ /* set up important data structures */
+ /************************************/
+ perm = idxmalloc(nvtxs, "AKWR: perm");
+ pperm = idxmalloc(nparts, "AKWR: pperm");
+
+ update = idxmalloc(nvtxs, "AKWR: update");
+ supdate = wspace->indices;
+ rupdate = supdate + recvptr[nnbrs];
+ nupds_pe = imalloc(npes, "AKWR: nupds_pe");
+ htable = idxsmalloc(nvtxs+graph->nrecv, 0, "AKWR: lhtable");
+ badmaxpwgt = fmalloc(nparts*ncon, "badmaxpwgt");
+
+ for (i=0; i<nparts; i++) {
+ for (h=0; h<ncon; h++) {
+ badmaxpwgt[i*ncon+h] = ubvec[h]*tpwgts[i*ncon+h];
+ }
+ }
+
+ movewgts = fmalloc(ncon*nparts, "AKWR: movewgts");
+ ognpwgts = fmalloc(nparts*ncon, "AKWR: ognpwgts");
+ pgnpwgts = fmalloc(nparts*ncon, "AKWR: pgnpwgts");
+ overfill = fmalloc(nparts*ncon, "AKWR: overfill");
+ moved = idxmalloc(nvtxs, "AKWR: moved");
+ tmp_where = idxmalloc(nvtxs+graph->nrecv, "AKWR: tmp_where");
+ tmp_rinfo = (RInfoType *)GKmalloc(sizeof(RInfoType)*nvtxs, "AKWR: tmp_rinfo");
+ tmp_edegrees = (EdgeType *)GKmalloc(sizeof(EdgeType)*nedges, "AKWR: tmp_edegrees");
+
+ idxcopy(nvtxs+graph->nrecv, where, tmp_where);
+ for (i=0; i<nvtxs; i++) {
+ tmp_rinfo[i].id = rinfo[i].id;
+ tmp_rinfo[i].ed = rinfo[i].ed;
+ tmp_rinfo[i].ndegrees = rinfo[i].ndegrees;
+ tmp_rinfo[i].degrees = tmp_edegrees+xadj[i];
+
+ for (j=0; j<rinfo[i].ndegrees; j++) {
+ tmp_rinfo[i].degrees[j].edge = rinfo[i].degrees[j].edge;
+ tmp_rinfo[i].degrees[j].ewgt = rinfo[i].degrees[j].ewgt;
+ }
+ }
+
+ /*********************************************************/
+ /* perform a small number of passes through the vertices */
+ /*********************************************************/
+ for (pass=0; pass<npasses; pass++) {
+ oldcut = graph->mincut;
+ if (mype == 0)
+ RandomPermute(nparts, pperm, 1);
+ MPI_Bcast((void *)pperm, nparts, IDX_DATATYPE, 0, ctrl->comm);
+/* FastRandomPermute(nvtxs, perm, 1); */
+
+ /*****************************/
+ /* move dirty vertices first */
+ /*****************************/
+ ndirty = 0;
+ for (i=0; i<nvtxs; i++)
+ if (where[i] != mype)
+ ndirty++;
+
+ dptr = 0;
+ for (i=0; i<nvtxs; i++)
+ if (where[i] != mype)
+ perm[dptr++] = i;
+ else
+ perm[ndirty++] = i;
+
+ ASSERT(ctrl, ndirty == nvtxs);
+ ndirty = dptr;
+ nclean = nvtxs-dptr;
+ FastRandomPermute(ndirty, perm, 0);
+ FastRandomPermute(nclean, perm+ndirty, 0);
+
+ /* check to see if the partitioning is imbalanced */
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ ubavg = savg(ncon, ubvec);
+ lbavg = savg(ncon, lbvec);
+ imbalanced = (lbavg > ubavg) ? 1 : 0;
+
+ for (c=0; c<2; c++) {
+ scopy(ncon*nparts, gnpwgts, ognpwgts);
+ sset(ncon*nparts, 0.0, movewgts);
+ nmoved = 0;
+
+ /**********************************************/
+ /* PASS ONE -- record stats for desired moves */
+ /**********************************************/
+ for (iii=0; iii<nvtxs; iii++) {
+ i = perm[iii];
+ from = tmp_where[i];
+ nvwgt = graph->nvwgt+i*ncon;
+ vsize = (float)(graph->vsize[i]);
+
+ for (h=0; h<ncon; h++) {
+ if (fabs(nvwgt[h]-gnpwgts[from*ncon+h]) < SMALLFLOAT)
+ break;
+ }
+ if (h < ncon)
+ continue;
+
+ /* only check border vertices */
+ if (tmp_rinfo[i].ed <= 0)
+ continue;
+
+ my_edegrees = tmp_rinfo[i].degrees;
+
+ for (k=0; k<tmp_rinfo[i].ndegrees; k++) {
+ to = my_edegrees[k].edge;
+ if (ProperSide(c, pperm[from], pperm[to])) {
+ for (h=0; h<ncon; h++) {
+ if (gnpwgts[to*ncon+h]+nvwgt[h] > badmaxpwgt[to*ncon+h] && nvwgt[h] > 0.0)
+ break;
+ }
+ if (h == ncon)
+ break;
+ }
+ }
+ oldto = to;
+
+ /* check if a subdomain was found that fits */
+ if (k < tmp_rinfo[i].ndegrees) {
+ /**************************/
+ /**************************/
+ switch (ctrl->ps_relation) {
+ case COUPLED:
+ better = (oldto == mype) ? 1 : 0;
+ worse = (from == mype) ? 1 : 0;
+ break;
+ case DISCOUPLED:
+ default:
+ better = (oldto == graph->home[i]) ? 1 : 0;
+ worse = (from == graph->home[i]) ? 1 : 0;
+ break;
+ }
+ /**************************/
+ /**************************/
+
+ oldgain = ipc_factor * (float)(my_edegrees[k].ewgt-tmp_rinfo[i].id);
+ if (better) oldgain += redist_factor * vsize;
+ if (worse) oldgain -= redist_factor * vsize;
+
+ for (j=k+1; j<tmp_rinfo[i].ndegrees; j++) {
+ to = my_edegrees[j].edge;
+ if (ProperSide(c, pperm[from], pperm[to])) {
+ /**************************/
+ /**************************/
+ switch (ctrl->ps_relation) {
+ case COUPLED:
+ better = (to == mype) ? 1 : 0;
+ break;
+ case DISCOUPLED:
+ default:
+ better = (to == graph->home[i]) ? 1 : 0;
+ break;
+ }
+ /**************************/
+ /**************************/
+
+ gain = ipc_factor * (float)(my_edegrees[j].ewgt-tmp_rinfo[i].id);
+ if (better) gain += redist_factor * vsize;
+ if (worse) gain -= redist_factor * vsize;
+
+ for (h=0; h<ncon; h++)
+ if (gnpwgts[to*ncon+h]+nvwgt[h] > badmaxpwgt[to*ncon+h] && nvwgt[h] > 0.0)
+ break;
+
+ if (h == ncon) {
+ if (gain > oldgain ||
+ (fabs(gain-oldgain) < SMALLFLOAT &&
+ IsHBalanceBetterTT(ncon,gnpwgts+oldto*ncon,gnpwgts+to*ncon,nvwgt,ubvec))){
+ oldgain = gain;
+ oldto = to;
+ k = j;
+ }
+ }
+ }
+ }
+ to = oldto;
+ gain = oldgain;
+
+ if (gain > 0.0 ||
+ (gain > -1.0*SMALLFLOAT &&
+ (imbalanced || graph->level > 3 || iii % 8 == 0) &&
+ IsHBalanceBetterFT(ncon,gnpwgts+from*ncon,gnpwgts+to*ncon,nvwgt,ubvec))){
+
+ /****************************************/
+ /* Update tmp arrays of the moved vertex */
+ /****************************************/
+ tmp_where[i] = to;
+ moved[nmoved++] = i;
+ for (h=0; h<ncon; h++) {
+ INC_DEC(lnpwgts[to*ncon+h], lnpwgts[from*ncon+h], nvwgt[h]);
+ INC_DEC(gnpwgts[to*ncon+h], gnpwgts[from*ncon+h], nvwgt[h]);
+ INC_DEC(movewgts[to*ncon+h], movewgts[from*ncon+h], nvwgt[h]);
+ }
+
+ tmp_rinfo[i].ed += tmp_rinfo[i].id-my_edegrees[k].ewgt;
+ SWAP(tmp_rinfo[i].id, my_edegrees[k].ewgt, j);
+ if (my_edegrees[k].ewgt == 0) {
+ tmp_rinfo[i].ndegrees--;
+ my_edegrees[k].edge = my_edegrees[tmp_rinfo[i].ndegrees].edge;
+ my_edegrees[k].ewgt = my_edegrees[tmp_rinfo[i].ndegrees].ewgt;
+ }
+ else {
+ my_edegrees[k].edge = from;
+ }
+
+ /* Update the degrees of adjacent vertices */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ /* no need to bother about vertices on different pe's */
+ if (ladjncy[j] >= nvtxs)
+ continue;
+
+ me = ladjncy[j];
+ mydomain = tmp_where[me];
+
+ myrinfo = tmp_rinfo+me;
+ your_edegrees = myrinfo->degrees;
+
+ if (mydomain == from) {
+ INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
+ }
+ else {
+ if (mydomain == to) {
+ INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
+ }
+ }
+
+ /* Remove contribution from the .ed of 'from' */
+ if (mydomain != from) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == from) {
+ if (your_edegrees[k].ewgt == adjwgt[j]) {
+ myrinfo->ndegrees--;
+ your_edegrees[k].edge = your_edegrees[myrinfo->ndegrees].edge;
+ your_edegrees[k].ewgt = your_edegrees[myrinfo->ndegrees].ewgt;
+ }
+ else {
+ your_edegrees[k].ewgt -= adjwgt[j];
+ }
+ break;
+ }
+ }
+ }
+
+ /* Add contribution to the .ed of 'to' */
+ if (mydomain != to) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == to) {
+ your_edegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ your_edegrees[myrinfo->ndegrees].edge = to;
+ your_edegrees[myrinfo->ndegrees++].ewgt = adjwgt[j];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /******************************************/
+ /* Let processors know the subdomain wgts */
+ /* if all proposed moves commit. */
+ /******************************************/
+ MPI_Allreduce((void *)lnpwgts, (void *)pgnpwgts, nparts*ncon, MPI_FLOAT, MPI_SUM, ctrl->comm);
+
+ /**************************/
+ /* compute overfill array */
+ /**************************/
+ overweight = 0;
+ for (j=0; j<nparts; j++) {
+ for (h=0; h<ncon; h++) {
+ if (pgnpwgts[j*ncon+h] > ognpwgts[j*ncon+h])
+ overfill[j*ncon+h] = (pgnpwgts[j*ncon+h]-badmaxpwgt[j*ncon+h]) / (pgnpwgts[j*ncon+h]-ognpwgts[j*ncon+h]);
+ else
+ overfill[j*ncon+h] = 0.0;
+
+ overfill[j*ncon+h] = amax(overfill[j*ncon+h], 0.0);
+ overfill[j*ncon+h] *= movewgts[j*ncon+h];
+
+ if (overfill[j*ncon+h] > 0.0)
+ overweight = 1;
+
+ ASSERTP(ctrl, ognpwgts[j*ncon+h] <= badmaxpwgt[j*ncon+h] || pgnpwgts[j*ncon+h] <= ognpwgts[j*ncon+h],
+ (ctrl, "%.4f %.4f %.4f\n", ognpwgts[j*ncon+h], badmaxpwgt[j*ncon+h], pgnpwgts[j*ncon+h]));
+ }
+ }
+
+ /****************************************************/
+ /* select moves to undo according to overfill array */
+ /****************************************************/
+ if (overweight == 1) {
+ for (iii=0; iii<nmoved; iii++) {
+ i = moved[iii];
+ oldto = tmp_where[i];
+ nvwgt = graph->nvwgt+i*ncon;
+ my_edegrees = tmp_rinfo[i].degrees;
+
+ for (k=0; k<tmp_rinfo[i].ndegrees; k++)
+ if (my_edegrees[k].edge == where[i])
+ break;
+
+ for (h=0; h<ncon; h++)
+ if (nvwgt[h] > 0.0 && overfill[oldto*ncon+h] > nvwgt[h]/4.0)
+ break;
+
+ /**********************************/
+ /* nullify this move if necessary */
+ /**********************************/
+ if (k != tmp_rinfo[i].ndegrees && h != ncon) {
+ moved[iii] = -1;
+ from = oldto;
+ to = where[i];
+
+ for (h=0; h<ncon; h++)
+ overfill[oldto*ncon+h] = amax(overfill[oldto*ncon+h]-nvwgt[h], 0.0);
+
+ tmp_where[i] = to;
+ tmp_rinfo[i].ed += tmp_rinfo[i].id-my_edegrees[k].ewgt;
+ SWAP(tmp_rinfo[i].id, my_edegrees[k].ewgt, j);
+ if (my_edegrees[k].ewgt == 0) {
+ tmp_rinfo[i].ndegrees--;
+ my_edegrees[k].edge = my_edegrees[tmp_rinfo[i].ndegrees].edge;
+ my_edegrees[k].ewgt = my_edegrees[tmp_rinfo[i].ndegrees].ewgt;
+ }
+ else {
+ my_edegrees[k].edge = from;
+ }
+
+ for (h=0; h<ncon; h++)
+ INC_DEC(lnpwgts[to*ncon+h], lnpwgts[from*ncon+h], nvwgt[h]);
+
+ /* Update the degrees of adjacent vertices */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ /* no need to bother about vertices on different pe's */
+ if (ladjncy[j] >= nvtxs)
+ continue;
+
+ me = ladjncy[j];
+ mydomain = tmp_where[me];
+
+ myrinfo = tmp_rinfo+me;
+ your_edegrees = myrinfo->degrees;
+
+ if (mydomain == from) {
+ INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
+ }
+ else {
+ if (mydomain == to) {
+ INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
+ }
+ }
+
+ /* Remove contribution from the .ed of 'from' */
+ if (mydomain != from) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == from) {
+ if (your_edegrees[k].ewgt == adjwgt[j]) {
+ myrinfo->ndegrees--;
+ your_edegrees[k].edge = your_edegrees[myrinfo->ndegrees].edge;
+ your_edegrees[k].ewgt = your_edegrees[myrinfo->ndegrees].ewgt;
+ }
+ else {
+ your_edegrees[k].ewgt -= adjwgt[j];
+ }
+ break;
+ }
+ }
+ }
+
+ /* Add contribution to the .ed of 'to' */
+ if (mydomain != to) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == to) {
+ your_edegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ your_edegrees[myrinfo->ndegrees].edge = to;
+ your_edegrees[myrinfo->ndegrees++].ewgt = adjwgt[j];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*************************************************/
+ /* PASS TWO -- commit the remainder of the moves */
+ /*************************************************/
+ nlupd = nsupd = nmoves = nchanged = 0;
+ for (iii=0; iii<nmoved; iii++) {
+ i = moved[iii];
+ if (i == -1)
+ continue;
+
+ where[i] = tmp_where[i];
+
+ /* Make sure to update the vertex information */
+ if (htable[i] == 0) {
+ /* make sure you do the update */
+ htable[i] = 1;
+ update[nlupd++] = i;
+ }
+
+ /* Put the vertices adjacent to i into the update array */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = ladjncy[j];
+ if (htable[k] == 0) {
+ htable[k] = 1;
+ if (k<nvtxs)
+ update[nlupd++] = k;
+ else
+ supdate[nsupd++] = k;
+ }
+ }
+ nmoves++;
+
+ if (graph->pexadj[i+1]-graph->pexadj[i] > 0)
+ changed[nchanged++] = i;
+ }
+
+ /* Tell interested pe's the new where[] info for the interface vertices */
+ CommChangedInterfaceData(ctrl, graph, nchanged, changed, where, swchanges, rwchanges, wspace->pv4);
+
+
+ IFSET(ctrl->dbglvl, DBG_RMOVEINFO, rprintf(ctrl, "\t[%d %d], [%.4f], [%d %d %d]\n",
+ pass, c, badmaxpwgt[0], GlobalSESum(ctrl, nmoves), GlobalSESum(ctrl, nsupd), GlobalSESum(ctrl, nlupd)));
+
+ /*-------------------------------------------------------------
+ / Time to communicate with processors to send the vertices
+ / whose degrees need to be update.
+ /-------------------------------------------------------------*/
+ /* Issue the receives first */
+ for (i=0; i<nnbrs; i++)
+ MPI_Irecv((void *)(rupdate+sendptr[i]), sendptr[i+1]-sendptr[i], IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->rreq+i);
+
+ /* Issue the sends next. This needs some preporcessing */
+ for (i=0; i<nsupd; i++) {
+ htable[supdate[i]] = 0;
+ supdate[i] = graph->imap[supdate[i]];
+ }
+ iidxsort(nsupd, supdate);
+
+ for (j=i=0; i<nnbrs; i++) {
+ yourlastvtx = vtxdist[peind[i]+1];
+ for (k=j; k<nsupd && supdate[k] < yourlastvtx; k++);
+ MPI_Isend((void *)(supdate+j), k-j, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ j = k;
+ }
+
+ /* OK, now get into the loop waiting for the send/recv operations to finish */
+ MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+ for (i=0; i<nnbrs; i++)
+ MPI_Get_count(ctrl->statuses+i, IDX_DATATYPE, nupds_pe+i);
+ MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+
+
+ /*-------------------------------------------------------------
+ / Place the recieved to-be updated vertices into update[]
+ /-------------------------------------------------------------*/
+ for (i=0; i<nnbrs; i++) {
+ pe_updates = rupdate+sendptr[i];
+ for (j=0; j<nupds_pe[i]; j++) {
+ k = pe_updates[j];
+ if (htable[k-firstvtx] == 0) {
+ htable[k-firstvtx] = 1;
+ update[nlupd++] = k-firstvtx;
+ }
+ }
+ }
+
+
+ /*-------------------------------------------------------------
+ / Update the rinfo of the vertices in the update[] array
+ /-------------------------------------------------------------*/
+ for (ii=0; ii<nlupd; ii++) {
+ i = update[ii];
+ ASSERT(ctrl, htable[i] == 1);
+
+ htable[i] = 0;
+
+ mydomain = where[i];
+ myrinfo = rinfo+i;
+ tmp_myrinfo = tmp_rinfo+i;
+ my_edegrees = myrinfo->degrees;
+ your_edegrees = tmp_myrinfo->degrees;
+
+ graph->lmincut -= myrinfo->ed;
+ myrinfo->ndegrees = 0;
+ myrinfo->id = 0;
+ myrinfo->ed = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ yourdomain = where[ladjncy[j]];
+ if (mydomain != yourdomain) {
+ myrinfo->ed += adjwgt[j];
+
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (my_edegrees[k].edge == yourdomain) {
+ my_edegrees[k].ewgt += adjwgt[j];
+ your_edegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ my_edegrees[k].edge = yourdomain;
+ my_edegrees[k].ewgt = adjwgt[j];
+ your_edegrees[k].edge = yourdomain;
+ your_edegrees[k].ewgt = adjwgt[j];
+ myrinfo->ndegrees++;
+ }
+ ASSERT(ctrl, myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
+ ASSERT(ctrl, tmp_myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
+
+ }
+ else {
+ myrinfo->id += adjwgt[j];
+ }
+ }
+ graph->lmincut += myrinfo->ed;
+
+ tmp_myrinfo->id = myrinfo->id;
+ tmp_myrinfo->ed = myrinfo->ed;
+ tmp_myrinfo->ndegrees = myrinfo->ndegrees;
+ }
+
+ /* finally, sum-up the partition weights */
+ MPI_Allreduce((void *)lnpwgts, (void *)gnpwgts, nparts*ncon, MPI_FLOAT, MPI_SUM, ctrl->comm);
+ }
+ graph->mincut = GlobalSESum(ctrl, graph->lmincut)/2;
+
+ if (graph->mincut == oldcut)
+ break;
+ }
+
+ GKfree((void **)&badmaxpwgt, (void **)&update, (void **)&nupds_pe, (void **)&htable, LTERM);
+ GKfree((void **)&changed, (void **)&pperm, (void **)&perm, (void **)&moved, LTERM);
+ GKfree((void **)&pgnpwgts, (void **)&ognpwgts, (void **)&overfill, (void **)&movewgts, LTERM);
+ GKfree((void **)&tmp_where, (void **)&tmp_rinfo, (void **)&tmp_edegrees, LTERM);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->KWayTmr));
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ametis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ametis.c
new file mode 100644
index 0000000..6fac271
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ametis.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * ametis.c
+ *
+ * This is the entry point of parallel difussive repartitioning routines
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: ametis.c,v 1.6 2003/07/25 04:01:03 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel multilevel local diffusion
+* algorithm. It uses parallel undirected diffusion followed by adaptive k-way
+* refinement. This function utilizes local coarsening.
+************************************************************************************/
+void ParMETIS_V3_AdaptiveRepart(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy,
+ idxtype *vwgt, idxtype *vsize, idxtype *adjwgt, int *wgtflag, int *numflag,
+ int *ncon, int *nparts, float *tpwgts, float *ubvec, float *ipc2redist,
+ int *options, int *edgecut, idxtype *part, MPI_Comm *comm)
+{
+ int h, i;
+ int npes, mype;
+ CtrlType ctrl;
+ WorkSpaceType wspace;
+ GraphType *graph;
+ int tewgt, tvsize, nmoved, maxin, maxout, vtx_factor;
+ float gtewgt, gtvsize, avg, maximb;
+ int ps_relation, seed, dbglvl = 0;
+ int iwgtflag, inumflag, incon, inparts, ioptions[10];
+ float iipc2redist, *itpwgts, iubvec[MAXNCON];
+
+ MPI_Comm_size(*comm, &npes);
+ MPI_Comm_rank(*comm, &mype);
+
+ /********************************/
+ /* Try and take care bad inputs */
+ /********************************/
+ if (options != NULL && options[0] == 1)
+ dbglvl = options[PMV3_OPTION_DBGLVL];
+ CheckInputs(ADAPTIVE_PARTITION, npes, dbglvl, wgtflag, &iwgtflag, numflag, &inumflag,
+ ncon, &incon, nparts, &inparts, tpwgts, &itpwgts, ubvec, iubvec,
+ ipc2redist, &iipc2redist, options, ioptions, part, comm);
+
+ /* ADD: take care of disconnected graph */
+ /* ADD: take care of highly unbalanced vtxdist */
+ /*********************************/
+ /* Take care the nparts = 1 case */
+ /*********************************/
+ if (inparts == 1) {
+ idxset(vtxdist[mype+1]-vtxdist[mype], 0, part);
+ *edgecut = 0;
+ return;
+ }
+
+ /**************************/
+ /* Set up data structures */
+ /**************************/
+ if (inumflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 1);
+
+ /*****************************/
+ /* Set up control structures */
+ /*****************************/
+ if (ioptions[0] == 1) {
+ dbglvl = ioptions[PMV3_OPTION_DBGLVL];
+ seed = ioptions[PMV3_OPTION_SEED];
+ ps_relation = (npes == inparts ? ioptions[PMV3_OPTION_PSR] : DISCOUPLED);
+ }
+ else {
+ dbglvl = GLOBAL_DBGLVL;
+ seed = GLOBAL_SEED;
+ ps_relation = (npes == inparts ? COUPLED : DISCOUPLED);
+ }
+
+ SetUpCtrl(&ctrl, inparts, dbglvl, *comm);
+ vtx_factor = (amax(npes, inparts) > 256) ? 20 : 50;
+ ctrl.CoarsenTo = amin(vtxdist[npes]+1, vtx_factor*incon*amax(npes, inparts));
+ ctrl.ipc_factor = iipc2redist;
+ ctrl.redist_factor = 1.0;
+ ctrl.redist_base = 1.0;
+ ctrl.seed = (seed == 0 ? mype : seed*mype);
+ ctrl.sync = GlobalSEMax(&ctrl, seed);
+ ctrl.partType = ADAPTIVE_PARTITION;
+ ctrl.ps_relation = ps_relation;
+ ctrl.tpwgts = itpwgts;
+
+ graph = Moc_SetUpGraph(&ctrl, incon, vtxdist, xadj, vwgt, adjncy, adjwgt, &iwgtflag);
+ graph->vsize = (vsize == NULL ? idxsmalloc(graph->nvtxs, 1, "vsize") : vsize);
+
+ graph->home = idxmalloc(graph->nvtxs, "home");
+ if (ctrl.ps_relation == COUPLED)
+ idxset(graph->nvtxs, mype, graph->home);
+ else {
+ /* Downgrade the partition numbers if part[] has more partitions that nparts */
+ for (i=0; i<graph->nvtxs; i++)
+ part[i] = (part[i] >= ctrl.nparts ? 0 : part[i]);
+
+ idxcopy(graph->nvtxs, part, graph->home);
+ }
+
+ tewgt = idxsum(graph->nedges, graph->adjwgt);
+ tvsize = idxsum(graph->nvtxs, graph->vsize);
+ gtewgt = (float) GlobalSESum(&ctrl, tewgt) + 1.0/graph->gnvtxs; /* The +1/graph->gnvtxs were added to remove any FPE */
+ gtvsize = (float) GlobalSESum(&ctrl, tvsize) + 1.0/graph->gnvtxs;
+ ctrl.edge_size_ratio = gtewgt/gtvsize;
+ scopy(incon, iubvec, ctrl.ubvec);
+
+ PreAllocateMemory(&ctrl, graph, &wspace);
+
+ /***********************/
+ /* Partition and Remap */
+ /***********************/
+ IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
+
+ Adaptive_Partition(&ctrl, graph, &wspace);
+ ParallelReMapGraph(&ctrl, graph, &wspace);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
+
+ idxcopy(graph->nvtxs, graph->where, part);
+ if (edgecut != NULL)
+ *edgecut = graph->mincut;
+
+ /***********************/
+ /* Take care of output */
+ /***********************/
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+
+ if (ctrl.dbglvl&DBG_INFO) {
+ Mc_ComputeMoveStatistics(&ctrl, graph, &nmoved, &maxin, &maxout);
+ rprintf(&ctrl, "Final %3d-way Cut: %6d \tBalance: ", inparts, graph->mincut);
+ avg = 0.0;
+ for (h=0; h<incon; h++) {
+ maximb = 0.0;
+ for (i=0; i<inparts; i++)
+ maximb = amax(maximb, graph->gnpwgts[i*incon+h]/itpwgts[i*incon+h]);
+ avg += maximb;
+ rprintf(&ctrl, "%.3f ", maximb);
+ }
+ rprintf(&ctrl, "\nNMoved: %d %d %d %d\n", nmoved, maxin, maxout, maxin+maxout);
+ }
+
+ /*************************************/
+ /* Free memory, renumber, and return */
+ /*************************************/
+ GKfree((void **)&graph->lnpwgts, (void **)&graph->gnpwgts, (void **)&graph->nvwgt, (void **)(&graph->home), LTERM);
+ if (vsize == NULL)
+ GKfree((void **)(&graph->vsize), LTERM);
+ GKfree((void **)&itpwgts, LTERM);
+ FreeInitialGraphAndRemap(graph, iwgtflag);
+ FreeWSpace(&wspace);
+ FreeCtrl(&ctrl);
+
+ if (inumflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 0);
+
+ return;
+}
+
+
+
+
+/*************************************************************************
+* This function is the driver for the adaptive refinement mode of ParMETIS
+**************************************************************************/
+void Adaptive_Partition(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i;
+ int tewgt, tvsize;
+ float gtewgt, gtvsize;
+ float ubavg, lbavg, lbvec[MAXNCON];
+
+ /************************************/
+ /* Set up important data structures */
+ /************************************/
+ SetUp(ctrl, graph, wspace);
+
+ ubavg = savg(graph->ncon, ctrl->ubvec);
+ tewgt = idxsum(graph->nedges, graph->adjwgt);
+ tvsize = idxsum(graph->nvtxs, graph->vsize);
+ gtewgt = (float) GlobalSESum(ctrl, tewgt) + 1.0/graph->gnvtxs; /* The +1/graph->gnvtxs were added to remove any FPE */
+ gtvsize = (float) GlobalSESum(ctrl, tvsize) + 1.0/graph->gnvtxs;
+ ctrl->redist_factor = ctrl->redist_base * ((gtewgt/gtvsize)/ ctrl->edge_size_ratio);
+
+ IFSET(ctrl->dbglvl, DBG_PROGRESS, rprintf(ctrl, "[%6d %8d %5d %5d][%d]\n",
+ graph->gnvtxs, GlobalSESum(ctrl, graph->nedges), GlobalSEMin(ctrl, graph->nvtxs), GlobalSEMax(ctrl, graph->nvtxs), ctrl->CoarsenTo));
+
+ if (graph->gnvtxs < 1.3*ctrl->CoarsenTo ||
+ (graph->finer != NULL && graph->gnvtxs > graph->finer->gnvtxs*COARSEN_FRACTION)) {
+
+ /***********************************************/
+ /* Balance the partition on the coarsest graph */
+ /***********************************************/
+ graph->where = idxsmalloc(graph->nvtxs+graph->nrecv, -1, "graph->where");
+ idxcopy(graph->nvtxs, graph->home, graph->where);
+
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ lbavg = savg(graph->ncon, lbvec);
+
+ if (lbavg > ubavg + 0.035 && ctrl->partType != REFINE_PARTITION)
+ Balance_Partition(ctrl, graph, wspace);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, balance: ", graph->gnvtxs);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+
+ /* check if no coarsening took place */
+ if (graph->finer == NULL) {
+ Moc_ComputePartitionParams(ctrl, graph, wspace);
+ Moc_KWayBalance(ctrl, graph, wspace, graph->ncon);
+ Moc_KWayAdaptiveRefine(ctrl, graph, wspace, NGR_PASSES);
+ }
+ }
+ else {
+ /*******************************/
+ /* Coarsen it and partition it */
+ /*******************************/
+ switch (ctrl->ps_relation) {
+ case COUPLED:
+ Mc_LocalMatch_HEM(ctrl, graph, wspace);
+ break;
+ case DISCOUPLED:
+ default:
+ Moc_GlobalMatch_Balance(ctrl, graph, wspace);
+ break;
+ }
+
+ Adaptive_Partition(ctrl, graph->coarser, wspace);
+
+ /********************************/
+ /* project partition and refine */
+ /********************************/
+ Moc_ProjectPartition(ctrl, graph, wspace);
+ Moc_ComputePartitionParams(ctrl, graph, wspace);
+
+ if (graph->ncon > 1 && graph->level < 4) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ lbavg = savg(graph->ncon, lbvec);
+
+ if (lbavg > ubavg + 0.025) {
+ Moc_KWayBalance(ctrl, graph, wspace, graph->ncon);
+ }
+ }
+
+ Moc_KWayAdaptiveRefine(ctrl, graph, wspace, NGR_PASSES);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, cut: %8d, balance: ", graph->gnvtxs, graph->mincut);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+ }
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/backcompat.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/backcompat.c
new file mode 100644
index 0000000..b62d4bb
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/backcompat.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * backcompat.c
+ *
+ * This file ensures backwards compatability with previous ParMETIS releases
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: backcompat.c,v 1.2 2003/07/21 17:18:48 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+/*****************************************************************************
+* This function computes a partitioning.
+*****************************************************************************/
+void ParMETIS_PartKway(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
+ idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut,
+ idxtype *part, MPI_Comm *comm)
+{
+ int i;
+ int ncon = 1;
+ float *tpwgts, ubvec[MAXNCON];
+ int myoptions[10];
+
+ tpwgts = fmalloc(*nparts*ncon, "tpwgts");
+ for (i=0; i<*nparts*ncon; i++)
+ tpwgts[i] = 1.0/(float)(*nparts);
+ for (i=0; i<ncon; i++)
+ ubvec[i] = UNBALANCE_FRACTION;
+
+ if (options[0] == 0) {
+ myoptions[0] = 0;
+ }
+ else {
+ myoptions[0] = 1;
+ myoptions[PMV3_OPTION_DBGLVL] = options[OPTION_DBGLVL];
+ myoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+ }
+
+ ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag,
+ &ncon, nparts, tpwgts, ubvec, myoptions, edgecut, part, comm);
+
+ free(tpwgts);
+}
+
+
+
+/***********************************************************************************
+ * * This function is the entry point of the parallel k-way multilevel partitionioner.
+ * * This function assumes nothing about the graph distribution.
+ * * It is the general case.
+ * ************************************************************************************/
+void PARKMETIS(idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ idxtype *part, int *options, MPI_Comm comm)
+{
+ int wgtflag, numflag, edgecut, newoptions[5];
+ int npes;
+
+ MPI_Comm_size(comm, &npes);
+
+ newoptions[0] = 1;
+ newoptions[OPTION_IPART] = options[2];
+ newoptions[OPTION_FOLDF] = options[1];
+ newoptions[OPTION_DBGLVL] = options[4];
+
+ numflag = options[3];
+ wgtflag = (vwgt == NULL ? 0 : 2) + (adjwgt == NULL ? 0 : 1);
+
+ ParMETIS_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &npes,
+ newoptions, &edgecut, part, &comm);
+
+ options[0] = edgecut;
+
+}
+
+
+
+/*****************************************************************************
+* This function computes a partitioning using coordinate data.
+*****************************************************************************/
+void ParMETIS_PartGeomKway(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
+ idxtype *adjwgt, int *wgtflag, int *numflag, int *ndims, float *xyz, int *nparts,
+ int *options, int *edgecut, idxtype *part, MPI_Comm *comm)
+{
+ int i;
+ int ncon = 1;
+ float *tpwgts, ubvec[MAXNCON];
+ int myoptions[10];
+
+ tpwgts = fmalloc(*nparts*ncon, "tpwgts");
+ for (i=0; i<*nparts*ncon; i++)
+ tpwgts[i] = 1.0/(float)(*nparts);
+ for (i=0; i<ncon; i++)
+ ubvec[i] = UNBALANCE_FRACTION;
+
+ if (options[0] == 0) {
+ myoptions[0] = 0;
+ }
+ else {
+ myoptions[0] = 1;
+ myoptions[PMV3_OPTION_DBGLVL] = options[OPTION_DBGLVL];
+ myoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+ }
+
+ ParMETIS_V3_PartGeomKway(vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, ndims, xyz,
+ &ncon, nparts, tpwgts, ubvec, myoptions, edgecut, part, comm);
+
+ free(tpwgts);
+ return;
+}
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel ordering algorithm.
+* This function assumes that the graph is already nice partitioned among the
+* processors and then proceeds to perform recursive bisection.
+************************************************************************************/
+void ParMETIS_PartGeom(idxtype *vtxdist, int *ndims, float *xyz, idxtype *part, MPI_Comm *comm)
+{
+ ParMETIS_V3_PartGeom(vtxdist, ndims, xyz, part, comm);
+}
+
+
+/*****************************************************************************
+* This function computes a partitioning using coordinate data.
+*****************************************************************************/
+void ParMETIS_PartGeomRefine(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy,
+ idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *ndims,
+ float *xyz, int *options, int *edgecut, idxtype *part, MPI_Comm *comm)
+{
+ int i;
+ int npes, nparts, ncon = 1;
+ float *tpwgts, ubvec[MAXNCON];
+ int myoptions[10];
+
+ MPI_Comm_size(*comm, &npes);
+ nparts = npes;
+
+ tpwgts = fmalloc(nparts*ncon, "tpwgts");
+ for (i=0; i<nparts*ncon; i++)
+ tpwgts[i] = 1.0/(float)(nparts);
+ for (i=0; i<ncon; i++)
+ ubvec[i] = UNBALANCE_FRACTION;
+
+ if (options[0] == 0) {
+ myoptions[0] = 0;
+ }
+ else {
+ myoptions[0] = 1;
+ myoptions[PMV3_OPTION_DBGLVL] = options[OPTION_DBGLVL];
+ myoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+ }
+
+ ParMETIS_V3_PartGeomKway(vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, ndims, xyz,
+ &ncon, &nparts, tpwgts, ubvec, myoptions, edgecut, part, comm);
+
+ free(tpwgts);
+ return;
+}
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel kmetis algorithm that uses
+* coordinates to compute an initial graph distribution.
+************************************************************************************/
+void PARGKMETIS(idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ int ndims, float *xyz, idxtype *part, int *options, MPI_Comm comm)
+{
+ int npes, wgtflag, numflag, edgecut, newoptions[5];
+
+ MPI_Comm_size(comm, &npes);
+
+ newoptions[0] = 1;
+ newoptions[OPTION_IPART] = options[2];
+ newoptions[OPTION_FOLDF] = options[1];
+ newoptions[OPTION_DBGLVL] = options[4];
+
+ numflag = options[3];
+ wgtflag = (vwgt == NULL ? 0 : 2) + (adjwgt == NULL ? 0 : 1);
+
+ ParMETIS_PartGeomKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag,
+ &ndims, xyz, &npes, newoptions, &edgecut, part, &comm);
+
+ options[0] = edgecut;
+
+}
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel rmetis algorithm that uses
+* coordinates to compute an initial graph distribution.
+************************************************************************************/
+void PARGRMETIS(idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ int ndims, float *xyz, idxtype *part, int *options, MPI_Comm comm)
+{
+ int wgtflag, numflag, edgecut, newoptions[5];
+
+ newoptions[0] = 1;
+ newoptions[OPTION_IPART] = options[2];
+ newoptions[OPTION_FOLDF] = options[1];
+ newoptions[OPTION_DBGLVL] = options[4];
+
+ numflag = options[3];
+ wgtflag = (vwgt == NULL ? 0 : 2) + (adjwgt == NULL ? 0 : 1);
+
+ ParMETIS_PartGeomRefine(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag,
+ &ndims, xyz, newoptions, &edgecut, part, &comm);
+
+ options[0] = edgecut;
+
+}
+
+/***********************************************************************************
+* This function is the entry point of the parallel ordering algorithm.
+* This function assumes that the graph is already nice partitioned among the
+* processors and then proceeds to perform recursive bisection.
+************************************************************************************/
+void PARGMETIS(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, int ndims, float *xyz,
+ idxtype *part, int *options, MPI_Comm comm)
+{
+
+ ParMETIS_PartGeom(vtxdist, &ndims, xyz, part, &comm);
+
+ options[0] = -1;
+
+}
+
+/*****************************************************************************
+* This function performs refinement on a partitioning.
+*****************************************************************************/
+void ParMETIS_RefineKway(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy,
+ idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *options,
+ int *edgecut, idxtype *part, MPI_Comm *comm)
+{
+ int i;
+ int nparts;
+ int ncon = 1;
+ float *tpwgts, ubvec[MAXNCON];
+ int myoptions[10];
+
+ MPI_Comm_size(*comm, &nparts);
+ tpwgts = fmalloc(nparts*ncon, "tpwgts");
+ for (i=0; i<nparts*ncon; i++)
+ tpwgts[i] = 1.0/(float)(nparts);
+ for (i=0; i<ncon; i++)
+ ubvec[i] = UNBALANCE_FRACTION;
+
+ if (options[0] == 0) {
+ myoptions[0] = 0;
+ }
+ else {
+ myoptions[0] = 1;
+ myoptions[PMV3_OPTION_DBGLVL] = options[OPTION_DBGLVL];
+ myoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+ myoptions[PMV3_OPTION_PSR] = COUPLED;
+ }
+
+ ParMETIS_V3_RefineKway(vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag,
+ &ncon, &nparts, tpwgts, ubvec, myoptions, edgecut, part, comm);
+
+ free(tpwgts);
+}
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel k-way multilevel partitionioner.
+* This function assumes nothing about the graph distribution.
+* It is the general case.
+************************************************************************************/
+void PARRMETIS(idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ idxtype *part, int *options, MPI_Comm comm)
+{
+ int wgtflag, numflag, edgecut, newoptions[5];
+
+ newoptions[0] = 1;
+ newoptions[OPTION_IPART] = options[2];
+ newoptions[OPTION_FOLDF] = options[1];
+ newoptions[OPTION_DBGLVL] = options[4];
+
+ numflag = options[3];
+ wgtflag = (vwgt == NULL ? 0 : 2) + (adjwgt == NULL ? 0 : 1);
+
+ ParMETIS_RefineKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag,
+ newoptions, &edgecut, part, &comm);
+
+ options[0] = edgecut;
+
+}
+
+
+/*****************************************************************************
+* This function computes a repartitioning by local diffusion.
+*****************************************************************************/
+void ParMETIS_RepartLDiffusion(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy,
+ idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *options,
+ int *edgecut, idxtype *part, MPI_Comm *comm)
+{
+ int i;
+ int nparts;
+ int ncon = 1;
+ float *tpwgts, ubvec[MAXNCON];
+ float ipc_factor = 1.0;
+ int myoptions[10];
+
+ MPI_Comm_size(*comm, &nparts);
+ tpwgts = fmalloc(nparts*ncon, "tpwgts");
+ for (i=0; i<nparts*ncon; i++)
+ tpwgts[i] = 1.0/(float)(nparts);
+ for (i=0; i<ncon; i++)
+ ubvec[i] = UNBALANCE_FRACTION;
+
+ if (options[0] == 0) {
+ myoptions[0] = 0;
+ }
+ else {
+ myoptions[0] = 1;
+ myoptions[PMV3_OPTION_DBGLVL] = options[OPTION_DBGLVL];
+ myoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+ myoptions[PMV3_OPTION_PSR] = COUPLED;
+ }
+
+ ParMETIS_V3_AdaptiveRepart(vtxdist, xadj, adjncy, vwgt, NULL, adjwgt, wgtflag, numflag,
+ &ncon, &nparts, tpwgts, ubvec, &ipc_factor, myoptions, edgecut, part, comm);
+
+ free(tpwgts);
+}
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel multilevel undirected diffusion
+* algorithm. It uses parallel undirected diffusion followed by adaptive k-way
+* refinement. This function utilizes local coarsening.
+************************************************************************************/
+void PARUAMETIS(idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ idxtype *part, int *options, MPI_Comm comm)
+{
+ int wgtflag, numflag, edgecut, newoptions[5];
+
+ newoptions[0] = 1;
+ newoptions[OPTION_IPART] = options[2];
+ newoptions[OPTION_FOLDF] = options[1];
+ newoptions[OPTION_DBGLVL] = options[4];
+
+ numflag = options[3];
+ wgtflag = (vwgt == NULL ? 0 : 2) + (adjwgt == NULL ? 0 : 1);
+
+ ParMETIS_RepartLDiffusion(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag,
+ newoptions, &edgecut, part, &comm);
+
+ options[0] = edgecut;
+
+}
+
+/*****************************************************************************
+* This function computes a repartitioning by global diffusion.
+*****************************************************************************/
+void ParMETIS_RepartGDiffusion(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy,
+ idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *options,
+ int *edgecut, idxtype *part, MPI_Comm *comm)
+{
+ int i;
+ int nparts;
+ int ncon = 1;
+ float *tpwgts, ubvec[MAXNCON];
+ float ipc_factor = 100.0;
+ int myoptions[10];
+
+ MPI_Comm_size(*comm, &nparts);
+ tpwgts = fmalloc(nparts*ncon, "tpwgts");
+ for (i=0; i<nparts*ncon; i++)
+ tpwgts[i] = 1.0/(float)(nparts);
+ for (i=0; i<ncon; i++)
+ ubvec[i] = UNBALANCE_FRACTION;
+
+ if (options[0] == 0) {
+ myoptions[0] = 0;
+ }
+ else {
+ myoptions[0] = 1;
+ myoptions[PMV3_OPTION_DBGLVL] = options[OPTION_DBGLVL];
+ myoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+ myoptions[PMV3_OPTION_PSR] = COUPLED;
+ }
+
+ ParMETIS_V3_AdaptiveRepart(vtxdist, xadj, adjncy, vwgt, NULL, adjwgt, wgtflag, numflag,
+ &ncon, &nparts, tpwgts, ubvec, &ipc_factor, myoptions, edgecut, part, comm);
+
+ free(tpwgts);
+}
+
+/***********************************************************************************
+* This function is the entry point of the parallel multilevel directed diffusion
+* algorithm. It uses parallel undirected diffusion followed by adaptive k-way
+* refinement. This function utilizes local coarsening.
+************************************************************************************/
+void PARDAMETIS(idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ idxtype *part, int *options, MPI_Comm comm)
+{
+ int wgtflag, numflag, edgecut, newoptions[5];
+
+ newoptions[0] = 1;
+ newoptions[OPTION_IPART] = options[2];
+ newoptions[OPTION_FOLDF] = options[1];
+ newoptions[OPTION_DBGLVL] = options[4];
+
+ numflag = options[3];
+ wgtflag = (vwgt == NULL ? 0 : 2) + (adjwgt == NULL ? 0 : 1);
+
+ ParMETIS_RepartGDiffusion(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag,
+ newoptions, &edgecut, part, &comm);
+
+ options[0] = edgecut;
+
+}
+
+/*****************************************************************************
+* This function computes a repartitioning by scratch-remap.
+*****************************************************************************/
+void ParMETIS_RepartRemap(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy,
+ idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *options,
+ int *edgecut, idxtype *part, MPI_Comm *comm)
+{
+ int i;
+ int nparts;
+ int ncon = 1;
+ float *tpwgts, ubvec[MAXNCON];
+ float ipc_factor = 1000.0;
+ int myoptions[10];
+
+ MPI_Comm_size(*comm, &nparts);
+ tpwgts = fmalloc(nparts*ncon, "tpwgts");
+ for (i=0; i<nparts*ncon; i++)
+ tpwgts[i] = 1.0/(float)(nparts);
+ for (i=0; i<ncon; i++)
+ ubvec[i] = UNBALANCE_FRACTION;
+
+ if (options[0] == 0) {
+ myoptions[0] = 0;
+ }
+ else {
+ myoptions[0] = 1;
+ myoptions[PMV3_OPTION_DBGLVL] = options[OPTION_DBGLVL];
+ myoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+ myoptions[PMV3_OPTION_PSR] = COUPLED;
+ }
+
+ ParMETIS_V3_AdaptiveRepart(vtxdist, xadj, adjncy, vwgt, NULL, adjwgt, wgtflag, numflag,
+ &ncon, &nparts, tpwgts, ubvec, &ipc_factor, myoptions, edgecut, part, comm);
+
+ free(tpwgts);
+}
+
+
+/*****************************************************************************
+* This function computes a repartitioning by LMSR scratch-remap.
+*****************************************************************************/
+void ParMETIS_RepartMLRemap(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy,
+ idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *options,
+ int *edgecut, idxtype *part, MPI_Comm *comm)
+{
+ int i;
+ int nparts;
+ int ncon = 1;
+ float *tpwgts, ubvec[MAXNCON];
+ float ipc_factor = 1000.0;
+ int myoptions[10];
+
+ MPI_Comm_size(*comm, &nparts);
+ tpwgts = fmalloc(nparts*ncon, "tpwgts");
+ for (i=0; i<nparts*ncon; i++)
+ tpwgts[i] = 1.0/(float)(nparts);
+ for (i=0; i<ncon; i++)
+ ubvec[i] = UNBALANCE_FRACTION;
+
+ if (options[0] == 0) {
+ myoptions[0] = 0;
+ }
+ else {
+ myoptions[0] = 1;
+ myoptions[PMV3_OPTION_DBGLVL] = options[OPTION_DBGLVL];
+ myoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+ myoptions[PMV3_OPTION_PSR] = COUPLED;
+ }
+
+ ParMETIS_V3_AdaptiveRepart(vtxdist, xadj, adjncy, vwgt, NULL, adjwgt, wgtflag, numflag,
+ &ncon, &nparts, tpwgts, ubvec, &ipc_factor, myoptions, edgecut, part, comm);
+
+ free(tpwgts);
+}
+
+/***********************************************************************************
+* This function is the entry point of the parallel ordering algorithm.
+* This function assumes that the graph is already nice partitioned among the
+* processors and then proceeds to perform recursive bisection.
+************************************************************************************/
+void ParMETIS_NodeND(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, int *numflag,
+ int *options, idxtype *order, idxtype *sizes, MPI_Comm *comm)
+{
+ int myoptions[10];
+
+ if (options[0] == 0) {
+ myoptions[0] = 0;
+ }
+ else {
+ myoptions[0] = 1;
+ myoptions[PMV3_OPTION_DBGLVL] = options[OPTION_DBGLVL];
+ myoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+ myoptions[PMV3_OPTION_IPART] = options[OPTION_IPART];
+ }
+
+ ParMETIS_V3_NodeND(vtxdist, xadj, adjncy, numflag, myoptions, order, sizes, comm);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/balancemylink.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/balancemylink.c
new file mode 100644
index 0000000..dd944d1
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/balancemylink.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * balancemylink.c
+ *
+ * This file contains code that implements the edge-based FM refinement
+ *
+ * Started 7/23/97
+ * George
+ *
+ * $Id: balancemylink.c,v 1.2 2003/07/21 17:18:48 karypis Exp $
+ */
+
+#include <parmetislib.h>
+#define PE 0
+
+/*************************************************************************
+* This function performs an edge-based FM refinement
+**************************************************************************/
+int BalanceMyLink(CtrlType *ctrl, GraphType *graph, idxtype *home, int me,
+ int you, float *flows, float maxdiff, float *diff_cost, float *diff_lbavg,
+ float avgvwgt)
+{
+ int h, i, ii, j, k;
+ int nvtxs, ncon;
+ int nqueues, minval, maxval, higain, vtx, edge, totalv;
+ int from, to, qnum, index, nchanges, cut, tmp;
+ int pass, nswaps, nmoves, multiplier;
+ idxtype *xadj, *vsize, *adjncy, *adjwgt, *where, *ed, *id;
+ idxtype *hval, *nvpq, *inq, *map, *rmap, *ptr, *myqueue, *changes;
+ float *nvwgt, lbvec[MAXNCON], pwgts[MAXNCON*2], tpwgts[MAXNCON*2], my_wgt[MAXNCON];
+ float newgain, oldgain = 0.0;
+ float lbavg, bestflow, mycost;
+ float ipc_factor, redist_factor, ftmp;
+ FPQueueType *queues;
+int mype;
+MPI_Comm_rank(MPI_COMM_WORLD, &mype);
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ nvwgt = graph->nvwgt;
+ vsize = graph->vsize;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ ipc_factor = ctrl->ipc_factor;
+ redist_factor = ctrl->redist_factor;
+
+ hval = idxmalloc(nvtxs*7, "hval");
+ id = hval + nvtxs;
+ ed = hval + nvtxs*2;
+ map = hval + nvtxs*3;
+ rmap = hval + nvtxs*4;
+ myqueue = hval + nvtxs*5;
+ changes = hval + nvtxs*6;
+
+ sset(ncon*2, 0.0, pwgts);
+ for (h=0; h<ncon; h++) {
+ tpwgts[h] = -1.0 * flows[h];
+ tpwgts[ncon+h] = flows[h];
+ }
+
+ for (i=0; i<nvtxs; i++) {
+ if (where[i] == me) {
+ for (h=0; h<ncon; h++) {
+ tpwgts[h] += nvwgt[i*ncon+h];
+ pwgts[h] += nvwgt[i*ncon+h];
+ }
+ }
+ else {
+ ASSERTS(where[i] == you);
+ for (h=0; h<ncon; h++) {
+ tpwgts[ncon+h] += nvwgt[i*ncon+h];
+ pwgts[ncon+h] += nvwgt[i*ncon+h];
+ }
+ }
+ }
+
+ /* we don't want any tpwgts to be less than zero */
+ for (h=0; h<ncon; h++) {
+ if (tpwgts[h] < 0.0) {
+ tpwgts[ncon+h] += tpwgts[h];
+ tpwgts[h] = 0.0;
+ }
+
+ if (tpwgts[ncon+h] < 0.0) {
+ tpwgts[h] += tpwgts[ncon+h];
+ tpwgts[ncon+h] = 0.0;
+ }
+ }
+
+ /*******************************/
+ /* insert vertices into queues */
+ /*******************************/
+ minval = maxval = 0;
+ multiplier = 1;
+ for (i=0; i<ncon; i++) {
+ multiplier *= (i+1);
+ maxval += i*multiplier;
+ minval += (ncon-1-i)*multiplier;
+ }
+
+ nqueues = maxval-minval+1;
+ nvpq = idxsmalloc(nqueues, 0, "nvpq");
+ ptr = idxmalloc(nqueues+1, "ptr");
+ inq = idxmalloc(nqueues*2, "inq");
+ queues = (FPQueueType *)(GKmalloc(sizeof(FPQueueType)*nqueues*2, "queues"));
+
+ for (i=0; i<nvtxs; i++)
+ hval[i] = Moc_HashVwgts(ncon, nvwgt+i*ncon) - minval;
+
+ for (i=0; i<nvtxs; i++)
+ nvpq[hval[i]]++;
+
+ ptr[0] = 0;
+ for (i=0; i<nqueues; i++)
+ ptr[i+1] = ptr[i] + nvpq[i];
+
+ for (i=0; i<nvtxs; i++) {
+ map[i] = ptr[hval[i]];
+ rmap[ptr[hval[i]]++] = i;
+ }
+
+ for (i=nqueues-1; i>0; i--)
+ ptr[i] = ptr[i-1];
+ ptr[0] = 0;
+
+ /* initialize queues */
+ for (i=0; i<nqueues; i++)
+ if (nvpq[i] > 0) {
+ FPQueueInit(queues+i, nvpq[i]);
+ FPQueueInit(queues+i+nqueues, nvpq[i]);
+ }
+
+ /* compute internal/external degrees */
+ idxset(nvtxs, 0, id);
+ idxset(nvtxs, 0, ed);
+ for (j=0; j<nvtxs; j++)
+ for (k=xadj[j]; k<xadj[j+1]; k++)
+ if (where[adjncy[k]] == where[j])
+ id[j] += adjwgt[k];
+ else
+ ed[j] += adjwgt[k];
+
+ nswaps = 0;
+ for (pass=0; pass<N_MOC_BAL_PASSES; pass++) {
+ idxset(nvtxs, -1, myqueue);
+ idxset(nqueues*2, 0, inq);
+
+ /* insert vertices into correct queues */
+ for (j=0; j<nvtxs; j++) {
+ index = (where[j] == me) ? 0 : nqueues;
+
+ newgain = ipc_factor*(float)(ed[j]-id[j]);
+ if (home[j] == me || home[j] == you) {
+ if (where[j] == home[j])
+ newgain -= redist_factor*(float)vsize[j];
+ else
+ newgain += redist_factor*(float)vsize[j];
+ }
+
+ FPQueueInsert(queues+hval[j]+index, map[j]-ptr[hval[j]], newgain);
+ myqueue[j] = (where[j] == me) ? 0 : 1;
+ inq[hval[j]+index]++;
+ }
+
+/* bestflow = sfavg(ncon, flows); */
+ for (j=0, h=0; h<ncon; h++)
+ if (fabs(flows[h]) > fabs(flows[j])) j = h;
+ bestflow = fabs(flows[j]);
+
+ nchanges = nmoves = 0;
+ for (ii=0; ii<nvtxs/2; ii++) {
+ from = -1;
+ Moc_DynamicSelectQueue(nqueues, ncon, me, you, inq, flows, &from,
+ &qnum, minval, avgvwgt, maxdiff);
+
+ /* can't find a vertex in one subdomain, try the other */
+ if (from != -1 && qnum == -1) {
+ from = (from == me) ? you : me;
+
+ if (from == me) {
+ for (j=0; j<ncon; j++)
+ if (flows[j] > avgvwgt)
+ break;
+ }
+ else {
+ for (j=0; j<ncon; j++)
+ if (flows[j] < -1.0*avgvwgt)
+ break;
+ }
+
+ if (j != ncon)
+ Moc_DynamicSelectQueue(nqueues, ncon, me, you, inq, flows, &from,
+ &qnum, minval, avgvwgt, maxdiff);
+ }
+
+ if (qnum == -1)
+ break;
+
+ to = (from == me) ? you : me;
+ index = (from == me) ? 0 : nqueues;
+ higain = FPQueueGetMax(queues+qnum+index);
+ inq[qnum+index]--;
+ ASSERTS(higain != -1);
+
+ /*****************/
+ /* make the swap */
+ /*****************/
+ vtx = rmap[higain+ptr[qnum]];
+ myqueue[vtx] = -1;
+ where[vtx] = to;
+ nswaps++;
+ nmoves++;
+
+ /* update the flows */
+ for (j=0; j<ncon; j++)
+ flows[j] += (to == me) ? nvwgt[vtx*ncon+j] : -1.0*nvwgt[vtx*ncon+j];
+
+/* ftmp = sfavg(ncon, flows); */
+ for (j=0, h=0; h<ncon; h++)
+ if (fabs(flows[h]) > fabs(flows[j])) j = h;
+ ftmp = fabs(flows[j]);
+
+ if (ftmp < bestflow) {
+ bestflow = ftmp;
+ nchanges = 0;
+ }
+ else {
+ changes[nchanges++] = vtx;
+ }
+
+ SWAP(id[vtx], ed[vtx], tmp);
+
+ for (j=xadj[vtx]; j<xadj[vtx+1]; j++) {
+ edge = adjncy[j];
+
+ /* must compute oldgain before changing id/ed */
+ if (myqueue[edge] != -1) {
+ oldgain = ipc_factor*(float)(ed[edge]-id[edge]);
+ if (home[edge] == me || home[edge] == you) {
+ if (where[edge] == home[edge])
+ oldgain -= redist_factor*(float)vsize[edge];
+ else
+ oldgain += redist_factor*(float)vsize[edge];
+ }
+ }
+
+ tmp = (to == where[edge] ? adjwgt[j] : -adjwgt[j]);
+ INC_DEC(id[edge], ed[edge], tmp);
+
+ if (myqueue[edge] != -1) {
+ newgain = ipc_factor*(float)(ed[edge]-id[edge]);
+ if (home[edge] == me || home[edge] == you) {
+ if (where[edge] == home[edge])
+ newgain -= redist_factor*(float)vsize[edge];
+ else
+ newgain += redist_factor*(float)vsize[edge];
+ }
+
+ FPQueueUpdate(queues+hval[edge]+(nqueues*myqueue[edge]),
+ map[edge]-ptr[hval[edge]], oldgain, newgain);
+ }
+ }
+ }
+
+ /****************************/
+ /* now go back to best flow */
+ /****************************/
+ nswaps -= nchanges;
+ nmoves -= nchanges;
+ for (i=0; i<nchanges; i++) {
+ vtx = changes[i];
+ from = where[vtx];
+ where[vtx] = to = (from == me) ? you : me;
+
+ SWAP(id[vtx], ed[vtx], tmp);
+ for (j=xadj[vtx]; j<xadj[vtx+1]; j++) {
+ edge = adjncy[j];
+ tmp = (to == where[edge] ? adjwgt[j] : -adjwgt[j]);
+ INC_DEC(id[edge], ed[edge], tmp);
+ }
+ }
+
+ for (i=0; i<nqueues; i++) {
+ if (nvpq[i] > 0) {
+ FPQueueReset(queues+i);
+ FPQueueReset(queues+i+nqueues);
+ }
+ }
+
+ if (nmoves == 0)
+ break;
+ }
+
+ /***************************/
+ /* compute 2-way imbalance */
+ /***************************/
+ sset(ncon, 0.0, my_wgt);
+ for (i=0; i<nvtxs; i++)
+ if (where[i] == me)
+ for (h=0; h<ncon; h++)
+ my_wgt[h] += nvwgt[i*ncon+h];
+
+ for (i=0; i<ncon; i++) {
+ ftmp = (pwgts[i]+pwgts[ncon+i])/2.0;
+ if (ftmp != 0.0)
+ lbvec[i] = fabs(my_wgt[i]-tpwgts[i]) / ftmp;
+ else
+ lbvec[i] = 0.0;
+ }
+ lbavg = savg(ncon, lbvec);
+ *diff_lbavg = lbavg;
+
+ /****************/
+ /* compute cost */
+ /****************/
+ cut = totalv = 0;
+ for (i=0; i<nvtxs; i++) {
+ if (where[i] != home[i])
+ totalv += vsize[i];
+
+ for (j=xadj[i]; j<xadj[i+1]; j++)
+ if (where[adjncy[j]] != where[i])
+ cut += adjwgt[j];
+ }
+ cut /= 2;
+ mycost = cut*ipc_factor + totalv*redist_factor;
+ *diff_cost = mycost;
+
+ /* free memory */
+ for (i=0; i<nqueues; i++)
+ if (nvpq[i] > 0) {
+ FPQueueFree(queues+i);
+ FPQueueFree(queues+i+nqueues);
+ }
+
+ GKfree((void **)&hval, (void **)&nvpq, (void **)&ptr, (void **)&inq, (void **)&queues, LTERM);
+ return nswaps;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/coarsen.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/coarsen.c
new file mode 100644
index 0000000..70f48c2
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/coarsen.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mcoarsen.c
+ *
+ * This file contains code that performs graph coarsening
+ *
+ * Started 2/22/96
+ * George
+ *
+ * $Id: coarsen.c,v 1.2 2003/07/21 17:18:48 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function creates the coarser graph
+**************************************************************************/
+void Moc_Global_CreateCoarseGraph(CtrlType *ctrl, GraphType *graph,
+ WorkSpaceType *wspace, int cnvtxs)
+{
+ int h, i, j, k, l, ii, jj, ll, nnbrs, nvtxs, nedges, ncon;
+ int firstvtx, lastvtx, cfirstvtx, clastvtx, otherlastvtx;
+ int npes=ctrl->npes, mype=ctrl->mype;
+ int cnedges, nsend, nrecv, nkeepsize, nrecvsize, nsendsize, v, u;
+ idxtype *xadj, *ladjncy, *adjwgt, *vwgt, *vsize, *vtxdist, *home;
+ idxtype *match, *cmap, *rcmap, *scmap;
+ idxtype *cxadj, *cadjncy, *cadjwgt, *cvwgt, *cvsize = NULL, *chome = NULL, *cvtxdist;
+ idxtype *rsizes, *ssizes, *rlens, *slens, *rgraph, *sgraph, *perm;
+ idxtype *peind, *recvptr, *recvind;
+ float *nvwgt, *cnvwgt;
+ GraphType *cgraph;
+ KeyValueType *scand, *rcand;
+ int mask=(1<<13)-1, htable[8192], htableidx[8192];
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+
+ vtxdist = graph->vtxdist;
+ xadj = graph->xadj;
+ vwgt = graph->vwgt;
+ vsize = graph->vsize;
+ nvwgt = graph->nvwgt;
+ home = graph->home;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+
+ match = graph->match;
+
+ firstvtx = vtxdist[mype];
+ lastvtx = vtxdist[mype+1];
+
+ cmap = graph->cmap = idxmalloc(nvtxs+graph->nrecv, "CreateCoarseGraph: cmap");
+
+ nnbrs = graph->nnbrs;
+ peind = graph->peind;
+ recvind = graph->recvind;
+ recvptr = graph->recvptr;
+
+ /* Use wspace->indices as the tmp space for map of the boundary
+ * vertices that are sent and received */
+ scmap = wspace->indices;
+ rcmap = cmap + nvtxs;
+
+
+ /* Initialize the coarser graph */
+ cgraph = CreateGraph();
+ cgraph->nvtxs = cnvtxs;
+ cgraph->ncon = ncon;
+ cgraph->level = graph->level+1;
+ cgraph->finer = graph;
+ graph->coarser = cgraph;
+
+
+
+ /*************************************************************
+ * Obtain the vtxdist of the coarser graph
+ **************************************************************/
+ cvtxdist = cgraph->vtxdist = idxmalloc(npes+1, "CreateCoarseGraph: cvtxdist");
+ cvtxdist[npes] = cnvtxs; /* Use last position in the cvtxdist as a temp buffer */
+
+ MPI_Allgather((void *)(cvtxdist+npes), 1, IDX_DATATYPE, (void *)cvtxdist, 1, IDX_DATATYPE, ctrl->comm);
+
+ MAKECSR(i, npes, cvtxdist);
+
+ cgraph->gnvtxs = cvtxdist[npes];
+
+#ifdef DEBUG_CONTRACT
+ PrintVector(ctrl, npes+1, 0, cvtxdist, "cvtxdist");
+#endif
+
+
+ /*************************************************************
+ * Construct the cmap vector
+ **************************************************************/
+ cfirstvtx = cvtxdist[mype];
+ clastvtx = cvtxdist[mype+1];
+
+ /* Create the cmap of what you know so far locally */
+ cnvtxs = 0;
+ for (i=0; i<nvtxs; i++) {
+ if (match[i] >= KEEP_BIT) {
+ k = match[i] - KEEP_BIT;
+ if (k>=firstvtx && k<firstvtx+i)
+ continue; /* Both (i,k) are local and i has been matched via the (k,i) side */
+
+ cmap[i] = cfirstvtx + cnvtxs++;
+ if (k != firstvtx+i && (k>=firstvtx && k<lastvtx)) { /* I'm matched locally */
+ cmap[k-firstvtx] = cmap[i];
+ match[k-firstvtx] += KEEP_BIT; /* Add the KEEP_BIT to simplify coding */
+ }
+ }
+ }
+ ASSERT(ctrl, cnvtxs == clastvtx-cfirstvtx);
+
+ CommInterfaceData(ctrl, graph, cmap, scmap, rcmap);
+
+ /* Update the cmap of the locally stored vertices that will go away.
+ * The remote processor assigned cmap for them */
+ for (i=0; i<nvtxs; i++) {
+ if (match[i] < KEEP_BIT) { /* Only vertices that go away satisfy this*/
+ cmap[i] = rcmap[BSearch(graph->nrecv, recvind, match[i])];
+ }
+ }
+
+ CommInterfaceData(ctrl, graph, cmap, scmap, rcmap);
+
+
+#ifdef DEBUG_CONTRACT
+ PrintVector(ctrl, nvtxs, firstvtx, cmap, "Cmap");
+#endif
+
+
+ /*************************************************************
+ * Determine how many adjcency lists you need to send/receive.
+ **************************************************************/
+ /* Use wspace->pairs as the tmp space for the boundary vertices that are sent and received */
+ scand = wspace->pairs;
+ rcand = graph->rcand = (KeyValueType *)GKmalloc(recvptr[nnbrs]*sizeof(KeyValueType), "CreateCoarseGraph: rcand");
+
+ nkeepsize = nsend = nrecv = 0;
+ for (i=0; i<nvtxs; i++) {
+ if (match[i] < KEEP_BIT) { /* This is going away */
+ scand[nsend].key = match[i];
+ scand[nsend].val = i;
+ nsend++;
+ }
+ else {
+ nkeepsize += (xadj[i+1]-xadj[i]);
+
+ k = match[i]-KEEP_BIT;
+ if (k<firstvtx || k>=lastvtx) { /* This is comming from afar */
+ rcand[nrecv].key = k;
+ rcand[nrecv].val = cmap[i] - cfirstvtx; /* Set it for use during the partition projection */
+ ASSERT(ctrl, rcand[nrecv].val>=0 && rcand[nrecv].val<cnvtxs);
+ nrecv++;
+ }
+ }
+ }
+
+
+#ifdef DEBUG_CONTRACT
+ PrintPairs(ctrl, nsend, scand, "scand");
+ PrintPairs(ctrl, nrecv, rcand, "rcand");
+#endif
+
+ /***************************************************************
+ * Determine how many lists and their sizes you will send and
+ * received for each of the neighboring PEs
+ ****************************************************************/
+ rsizes = wspace->pv1;
+ ssizes = wspace->pv2;
+ idxset(nnbrs, 0, ssizes);
+ idxset(nnbrs, 0, rsizes);
+ rlens = graph->rlens = idxmalloc(nnbrs+1, "CreateCoarseGraph: graph->rlens");
+ slens = graph->slens = idxmalloc(nnbrs+1, "CreateCoarseGraph: graph->slens");
+
+ /* Take care the sending data first */
+ ikeyvalsort(nsend, scand);
+ slens[0] = 0;
+ for (k=i=0; i<nnbrs; i++) {
+ otherlastvtx = vtxdist[peind[i]+1];
+ for (; k<nsend && scand[k].key < otherlastvtx; k++)
+ ssizes[i] += (xadj[scand[k].val+1]-xadj[scand[k].val]);
+ slens[i+1] = k;
+ }
+
+ /* Take care the receiving data next. You cannot yet determine the rsizes[] */
+ ikeyvalsort(nrecv, rcand);
+ rlens[0] = 0;
+ for (k=i=0; i<nnbrs; i++) {
+ otherlastvtx = vtxdist[peind[i]+1];
+ for (; k<nrecv && rcand[k].key < otherlastvtx; k++);
+ rlens[i+1] = k;
+ }
+
+#ifdef DEBUG_CONTRACT
+ PrintVector(ctrl, nnbrs+1, 0, slens, "slens");
+ PrintVector(ctrl, nnbrs+1, 0, rlens, "rlens");
+#endif
+
+ /***************************************************************
+ * Exchange size information
+ ****************************************************************/
+ /* Issue the receives first. */
+ for (i=0; i<nnbrs; i++) {
+ if (rlens[i+1]-rlens[i] > 0) /* Issue a receive only if you are getting something */
+ MPI_Irecv((void *)(rsizes+i), 1, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ /* Take care the sending data next */
+ for (i=0; i<nnbrs; i++) {
+ if (slens[i+1]-slens[i] > 0) /* Issue a send only if you are sending something */
+ MPI_Isend((void *)(ssizes+i), 1, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ }
+
+ /* OK, now get into the loop waiting for the operations to finish */
+ for (i=0; i<nnbrs; i++) {
+ if (rlens[i+1]-rlens[i] > 0)
+ MPI_Wait(ctrl->rreq+i, &ctrl->status);
+ }
+ for (i=0; i<nnbrs; i++) {
+ if (slens[i+1]-slens[i] > 0)
+ MPI_Wait(ctrl->sreq+i, &ctrl->status);
+ }
+
+
+#ifdef DEBUG_CONTRACT
+ PrintVector(ctrl, nnbrs, 0, rsizes, "rsizes");
+ PrintVector(ctrl, nnbrs, 0, ssizes, "ssizes");
+#endif
+
+ /*************************************************************
+ * Allocate memory for received/sent graphs and start sending
+ * and receiving data.
+ * rgraph and sgraph is a different data structure than CSR
+ * to facilitate single message exchange.
+ **************************************************************/
+ nrecvsize = idxsum(nnbrs, rsizes);
+ nsendsize = idxsum(nnbrs, ssizes);
+ if ((4+ncon)*(nrecv+nsend) + 2*(nrecvsize+nsendsize) <= wspace->nlarge) {
+ rgraph = (idxtype *)wspace->degrees;
+ sgraph = rgraph + (4+ncon)*nrecv+2*nrecvsize;
+ }
+ else {
+ rgraph = idxmalloc((4+ncon)*nrecv+2*nrecvsize, "CreateCoarseGraph: rgraph");
+ sgraph = idxmalloc((4+ncon)*nsend+2*nsendsize, "CreateCoarseGraph: sgraph");
+ }
+
+ /* Deal with the received portion first */
+ for (l=i=0; i<nnbrs; i++) {
+ /* Issue a receive only if you are getting something */
+ if (rlens[i+1]-rlens[i] > 0) {
+ MPI_Irecv((void *)(rgraph+l), (4+ncon)*(rlens[i+1]-rlens[i])+2*rsizes[i], IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ l += (4+ncon)*(rlens[i+1]-rlens[i])+2*rsizes[i];
+ }
+ }
+
+
+ /* Deal with the sent portion now */
+ for (ll=l=i=0; i<nnbrs; i++) {
+ if (slens[i+1]-slens[i] > 0) { /* Issue a send only if you are sending something */
+ for (k=slens[i]; k<slens[i+1]; k++) {
+ ii = scand[k].val;
+ sgraph[ll++] = firstvtx+ii;
+ sgraph[ll++] = xadj[ii+1]-xadj[ii];
+ for (h=0; h<ncon; h++)
+ sgraph[ll++] = vwgt[ii*ncon+h];
+ sgraph[ll++] = (ctrl->partType == STATIC_PARTITION) ? -1 : vsize[ii];
+ sgraph[ll++] = (ctrl->partType == STATIC_PARTITION) ? -1 : home[ii];
+ for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
+ sgraph[ll++] = cmap[ladjncy[jj]];
+ sgraph[ll++] = adjwgt[jj];
+ }
+ }
+
+ ASSERT(ctrl, ll-l == (4+ncon)*(slens[i+1]-slens[i])+2*ssizes[i]);
+
+ /* myprintf(ctrl, "Sending to pe:%d, %d lists of size %d\n", peind[i], slens[i+1]-slens[i], ssizes[i]); */
+ MPI_Isend((void *)(sgraph+l), ll-l, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ l = ll;
+ }
+ }
+
+ /* OK, now get into the loop waiting for the operations to finish */
+ for (i=0; i<nnbrs; i++) {
+ if (rlens[i+1]-rlens[i] > 0)
+ MPI_Wait(ctrl->rreq+i, &ctrl->status);
+ }
+ for (i=0; i<nnbrs; i++) {
+ if (slens[i+1]-slens[i] > 0)
+ MPI_Wait(ctrl->sreq+i, &ctrl->status);
+ }
+
+
+#ifdef DEBUG_CONTRACT
+ rprintf(ctrl, "Graphs were sent!\n");
+ PrintTransferedGraphs(ctrl, nnbrs, peind, slens, rlens, sgraph, rgraph);
+#endif
+
+ /*************************************************************
+ * Setup the mapping from indices returned by BSearch to
+ * those that are actually stored
+ **************************************************************/
+ perm = idxsmalloc(recvptr[nnbrs], -1, "CreateCoarseGraph: perm");
+ for (j=i=0; i<nrecv; i++) {
+ /* myprintf(ctrl, "For received vertex %d, set perm[%d]=%d\n", rgraph[j], BSearch(graph->nrecv, recvind, rgraph[j]), j+ncon); */
+ perm[BSearch(graph->nrecv, recvind, rgraph[j])] = j+1;
+ j += (4+ncon)+2*rgraph[j+1];
+ }
+
+ /*************************************************************
+ * Finally, create the coarser graph
+ **************************************************************/
+ /* Allocate memory for the coarser graph, and fire up coarsening */
+ cxadj = cgraph->xadj = idxmalloc(cnvtxs+1, "CreateCoarserGraph: cxadj");
+ cvwgt = cgraph->vwgt = idxmalloc(cnvtxs*ncon, "CreateCoarserGraph: cvwgt");
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+ cvsize = cgraph->vsize = idxmalloc(cnvtxs, "CreateCoarserGraph: cvsize");
+ chome = cgraph->home = idxmalloc(cnvtxs, "CreateCoarserGraph: chome");
+ }
+ cnvwgt = cgraph->nvwgt = fmalloc(cnvtxs*ncon, "CreateCoarserGraph: cnvwgt");
+ cadjncy = idxmalloc(2*(nkeepsize+nrecvsize), "CreateCoarserGraph: cadjncy");
+ cadjwgt = cadjncy + nkeepsize+nrecvsize;
+
+ iset(8192, -1, htable);
+
+ cxadj[0] = cnvtxs = cnedges = 0;
+ for (i=0; i<nvtxs; i++) {
+ if (match[i] >= KEEP_BIT) {
+ v = firstvtx+i;
+ u = match[i]-KEEP_BIT;
+
+ if (u>=firstvtx && u<lastvtx && v > u)
+ continue; /* I have already collapsed it as (u,v) */
+
+ /* Collapse the v vertex first, which you know is local */
+ for (h=0; h<ncon; h++)
+ cvwgt[cnvtxs*ncon+h] = vwgt[i*ncon+h];
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+ cvsize[cnvtxs] = vsize[i];
+ chome[cnvtxs] = home[i];
+ }
+ nedges = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = cmap[ladjncy[j]];
+ if (k != cfirstvtx+cnvtxs) { /* If this is not an internal edge */
+ l = k&mask;
+ if (htable[l] == -1) { /* Seeing this for first time */
+ htable[l] = k;
+ htableidx[l] = cnedges+nedges;
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = adjwgt[j];
+ }
+ else if (htable[l] == k) {
+ cadjwgt[htableidx[l]] += adjwgt[j];
+ }
+ else { /* Now you have to go and do a search. Expensive case */
+ for (l=0; l<nedges; l++) {
+ if (cadjncy[cnedges+l] == k)
+ break;
+ }
+ if (l < nedges) {
+ cadjwgt[cnedges+l] += adjwgt[j];
+ }
+ else {
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = adjwgt[j];
+ }
+ }
+ }
+ }
+
+ /* Collapse the u vertex next */
+ if (v != u) {
+ if (u>=firstvtx && u<lastvtx) { /* Local vertex */
+ u -= firstvtx;
+ for (h=0; h<ncon; h++)
+ cvwgt[cnvtxs*ncon+h] += vwgt[u*ncon+h];
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+ cvsize[cnvtxs] += vsize[u];
+ /* chome[cnvtxs] = home[u]; */
+ }
+
+ for (j=xadj[u]; j<xadj[u+1]; j++) {
+ k = cmap[ladjncy[j]];
+ if (k != cfirstvtx+cnvtxs) { /* If this is not an internal edge */
+ l = k&mask;
+ if (htable[l] == -1) { /* Seeing this for first time */
+ htable[l] = k;
+ htableidx[l] = cnedges+nedges;
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = adjwgt[j];
+ }
+ else if (htable[l] == k) {
+ cadjwgt[htableidx[l]] += adjwgt[j];
+ }
+ else { /* Now you have to go and do a search. Expensive case */
+ for (l=0; l<nedges; l++) {
+ if (cadjncy[cnedges+l] == k)
+ break;
+ }
+ if (l < nedges) {
+ cadjwgt[cnedges+l] += adjwgt[j];
+ }
+ else {
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = adjwgt[j];
+ }
+ }
+ }
+ }
+ }
+ else { /* Remote vertex */
+ u = perm[BSearch(graph->nrecv, recvind, u)];
+ for (h=0; h<ncon; h++)
+ /* Remember that the +1 stores the vertex weight */
+ cvwgt[cnvtxs*ncon+h] += rgraph[(u+1)+h];
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+ cvsize[cnvtxs] += rgraph[u+1+ncon];
+ chome[cnvtxs] = rgraph[u+2+ncon];
+ }
+ for (j=0; j<rgraph[u]; j++) {
+ k = rgraph[u+3+ncon+2*j];
+ if (k != cfirstvtx+cnvtxs) { /* If this is not an internal edge */
+ l = k&mask;
+ if (htable[l] == -1) { /* Seeing this for first time */
+ htable[l] = k;
+ htableidx[l] = cnedges+nedges;
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = rgraph[u+3+ncon+2*j+1];
+ }
+ else if (htable[l] == k) {
+ cadjwgt[htableidx[l]] += rgraph[u+3+ncon+2*j+1];
+ }
+ else { /* Now you have to go and do a search. Expensive case */
+ for (l=0; l<nedges; l++) {
+ if (cadjncy[cnedges+l] == k)
+ break;
+ }
+ if (l < nedges) {
+ cadjwgt[cnedges+l] += rgraph[u+3+ncon+2*j+1];
+ }
+ else {
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = rgraph[u+3+ncon+2*j+1];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ cnedges += nedges;
+ for (j=cxadj[cnvtxs]; j<cnedges; j++)
+ htable[cadjncy[j]&mask] = -1; /* reset the htable */
+ cxadj[++cnvtxs] = cnedges;
+ }
+ }
+
+ cgraph->nedges = cnedges;
+
+ /* ADD: In order to keep from having to change this too much */
+ /* ADD: I kept vwgt array and recomputed nvwgt for each coarser graph */
+ for (j=0; j<cnvtxs; j++)
+ for (h=0; h<ncon; h++)
+ cgraph->nvwgt[j*ncon+h] = (float)(cvwgt[j*ncon+h])/(float)(ctrl->tvwgts[h]);
+
+ cgraph->adjncy = idxmalloc(cnedges, "CreateCoarserGraph: cadjncy");
+ cgraph->adjwgt = idxmalloc(cnedges, "CreateCoarserGraph: cadjwgt");
+ idxcopy(cnedges, cadjncy, cgraph->adjncy);
+ idxcopy(cnedges, cadjwgt, cgraph->adjwgt);
+ free(cadjncy);
+
+ free(perm);
+
+ if (rgraph != (idxtype *)wspace->degrees)
+ GKfree((void **)&rgraph, (void **)&sgraph, LTERM);
+
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/comm.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/comm.c
new file mode 100644
index 0000000..fb18789
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/comm.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * comm.c
+ *
+ * This function provides various high level communication functions
+ *
+ * $Id: comm.c,v 1.2 2003/07/21 17:18:48 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+
+
+/*************************************************************************
+* This function performs the gather/scatter for the boundary vertices
+**************************************************************************/
+void CommInterfaceData(CtrlType *ctrl, GraphType *graph, idxtype *data,
+ idxtype *sendvector, idxtype *recvvector)
+{
+ int i, k, nnbrs, firstvtx;
+ idxtype *peind, *sendptr, *sendind, *recvptr, *recvind;
+
+ firstvtx = graph->vtxdist[ctrl->mype];
+ nnbrs = graph->nnbrs;
+ peind = graph->peind;
+ sendptr = graph->sendptr;
+ sendind = graph->sendind;
+ recvptr = graph->recvptr;
+ recvind = graph->recvind;
+
+ /* Issue the receives first */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Irecv((void *)(recvvector+recvptr[i]), recvptr[i+1]-recvptr[i], IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ /* Issue the sends next */
+ k = sendptr[nnbrs];
+ for (i=0; i<k; i++)
+ sendvector[i] = data[sendind[i]-firstvtx];
+
+ for (i=0; i<nnbrs; i++) {
+ MPI_Isend((void *)(sendvector+sendptr[i]), sendptr[i+1]-sendptr[i], IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ }
+
+ /* OK, now get into the loop waiting for the operations to finish */
+ MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+ MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+
+}
+
+
+
+/*************************************************************************
+* This function performs the gather/scatter for the boundary vertices
+**************************************************************************/
+void CommChangedInterfaceData(CtrlType *ctrl, GraphType *graph,
+ int nchanged, idxtype *changed, idxtype *data,
+ KeyValueType *sendpairs, KeyValueType *recvpairs, idxtype *psendptr)
+{
+ int i, j, k, n, penum, nnbrs, firstvtx, nrecv;
+ idxtype *peind, *sendptr, *recvptr, *recvind, *pexadj, *peadjncy, *peadjloc;
+ KeyValueType *pairs;
+
+ firstvtx = graph->vtxdist[ctrl->mype];
+ nnbrs = graph->nnbrs;
+ nrecv = graph->nrecv;
+ peind = graph->peind;
+ sendptr = graph->sendptr;
+ recvptr = graph->recvptr;
+ recvind = graph->recvind;
+ pexadj = graph->pexadj;
+ peadjncy = graph->peadjncy;
+ peadjloc = graph->peadjloc;
+
+ /* Issue the receives first */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Irecv((void *)(recvpairs+recvptr[i]), 2*(recvptr[i+1]-recvptr[i]), IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ if (nchanged != 0) {
+ idxcopy(ctrl->npes, sendptr, psendptr);
+
+ /* Copy the changed values into the sendvector */
+ for (i=0; i<nchanged; i++) {
+ j = changed[i];
+ for (k=pexadj[j]; k<pexadj[j+1]; k++) {
+ penum = peadjncy[k];
+ sendpairs[psendptr[penum]].key = peadjloc[k];
+ sendpairs[psendptr[penum]].val = data[j];
+ psendptr[penum]++;
+ }
+ }
+
+ for (i=0; i<nnbrs; i++) {
+ MPI_Isend((void *)(sendpairs+sendptr[i]), 2*(psendptr[i]-sendptr[i]), IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ }
+ }
+ else {
+ for (i=0; i<nnbrs; i++)
+ MPI_Isend((void *)(sendpairs), 0, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ }
+
+ /* OK, now get into the loop waiting for the operations to finish */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Wait(ctrl->rreq+i, &(ctrl->status));
+ MPI_Get_count(&ctrl->status, IDX_DATATYPE, &n);
+ if (n != 0) {
+ n = n/2;
+ pairs = recvpairs+graph->recvptr[i];
+ for (k=0; k<n; k++)
+ data[pairs[k].key] = pairs[k].val;
+ }
+ }
+
+ MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+}
+
+
+
+/*************************************************************************
+* This function computes the max of a single element
+**************************************************************************/
+int GlobalSEMax(CtrlType *ctrl, int value)
+{
+ int max;
+
+ MPI_Allreduce((void *)&value, (void *)&max, 1, MPI_INT, MPI_MAX, ctrl->comm);
+
+ return max;
+}
+
+/*************************************************************************
+* This function computes the max of a single element
+**************************************************************************/
+double GlobalSEMaxDouble(CtrlType *ctrl, double value)
+{
+ double max;
+
+ MPI_Allreduce((void *)&value, (void *)&max, 1, MPI_DOUBLE, MPI_MAX, ctrl->comm);
+
+ return max;
+}
+
+
+
+/*************************************************************************
+* This function computes the max of a single element
+**************************************************************************/
+int GlobalSEMin(CtrlType *ctrl, int value)
+{
+ int min;
+
+ MPI_Allreduce((void *)&value, (void *)&min, 1, MPI_INT, MPI_MIN, ctrl->comm);
+
+ return min;
+}
+
+/*************************************************************************
+* This function computes the max of a single element
+**************************************************************************/
+int GlobalSESum(CtrlType *ctrl, int value)
+{
+ int sum;
+
+ MPI_Allreduce((void *)&value, (void *)&sum, 1, MPI_INT, MPI_SUM, ctrl->comm);
+
+ return sum;
+}
+
+
+/*************************************************************************
+* This function computes the max of a single element
+**************************************************************************/
+float GlobalSEMaxFloat(CtrlType *ctrl, float value)
+{
+ float max;
+
+ MPI_Allreduce((void *)&value, (void *)&max, 1, MPI_FLOAT, MPI_MAX, ctrl->comm);
+
+ return max;
+}
+
+
+
+/*************************************************************************
+* This function computes the max of a single element
+**************************************************************************/
+float GlobalSEMinFloat(CtrlType *ctrl, float value)
+{
+ float min;
+
+ MPI_Allreduce((void *)&value, (void *)&min, 1, MPI_FLOAT, MPI_MIN, ctrl->comm);
+
+ return min;
+}
+
+/*************************************************************************
+* This function computes the max of a single element
+**************************************************************************/
+float GlobalSESumFloat(CtrlType *ctrl, float value)
+{
+ float sum;
+
+ MPI_Allreduce((void *)&value, (void *)&sum, 1, MPI_FLOAT, MPI_SUM, ctrl->comm);
+
+ return sum;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/csrmatch.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/csrmatch.c
new file mode 100644
index 0000000..ace7998
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/csrmatch.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * csrmatch.c
+ *
+ * This file contains the code that computes matchings
+ *
+ * Started 7/23/97
+ * George
+ *
+ * $Id: csrmatch.c,v 1.2 2003/07/21 17:18:48 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+
+/*************************************************************************
+* This function finds a matching using the HEM heuristic
+**************************************************************************/
+void CSR_Match_SHEM(MatrixType *matrix, idxtype *match, idxtype *mlist,
+ idxtype *skip, int ncon)
+{
+ int h, i, ii, j;
+ int nrows, edge, maxidx, count;
+ float maxwgt;
+ idxtype *rowptr, *colind;
+ float *transfer;
+ KVType *links;
+
+ nrows = matrix->nrows;
+ rowptr = matrix->rowptr;
+ colind = matrix->colind;
+ transfer = matrix->transfer;
+
+ idxset(nrows, UNMATCHED, match);
+
+ links = (KVType *)GKmalloc(sizeof(KVType)*nrows, "links");
+ for (i=0; i<nrows; i++) {
+ links[i].key = i;
+ links[i].val = 0.0;
+ }
+
+ for (i=0; i<nrows; i++)
+ for (j=rowptr[i]; j<rowptr[i+1]; j++)
+ for (h=0; h<ncon; h++)
+ if (links[i].val < fabs(transfer[j*ncon+h]))
+ links[i].val = fabs(transfer[j*ncon+h]);
+
+ qsort(links, nrows, sizeof(KVType), myvalkeycompare);
+
+ count = 0;
+ for (ii=0; ii<nrows; ii++) {
+ i = links[ii].key;
+
+ if (match[i] == UNMATCHED) {
+ maxidx = i;
+ maxwgt = 0.0;
+
+ /* Find a heavy-edge matching */
+ for (j=rowptr[i]; j<rowptr[i+1]; j++) {
+ edge = colind[j];
+ if (match[edge] == UNMATCHED && edge != i && skip[j] == 0) {
+ for (h=0; h<ncon; h++)
+ if (maxwgt < fabs(transfer[j*ncon+h]))
+ break;
+
+ if (h != ncon) {
+ maxwgt = fabs(transfer[j*ncon+h]);
+ maxidx = edge;
+ }
+ }
+ }
+
+ if (maxidx != i) {
+ match[i] = maxidx;
+ match[maxidx] = i;
+ mlist[count++] = amax(i, maxidx);
+ mlist[count++] = amin(i, maxidx);
+ }
+ }
+ }
+
+ GKfree((void **)&links, LTERM);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/debug.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/debug.c
new file mode 100644
index 0000000..ebdf69c
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/debug.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * debug.c
+ *
+ * This file contains various functions that are used to display debuging
+ * information
+ *
+ * Started 10/20/96
+ * George
+ *
+ * $Id: debug.c,v 1.2 2003/07/21 17:18:48 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function prints a vector stored in each processor
+**************************************************************************/
+void PrintVector(CtrlType *ctrl, int n, int first, idxtype *vec, char *title)
+{
+ int i, penum;
+
+ for (penum=0; penum<ctrl->npes; penum++) {
+ if (ctrl->mype == penum) {
+ if (ctrl->mype == 0)
+ printf("%s\n", title);
+ printf("\t%3d. ", ctrl->mype);
+ for (i=0; i<n; i++)
+ printf("[%d %hd] ", first+i, vec[i]);
+ printf("\n");
+ fflush(stdout);
+ }
+ MPI_Barrier(ctrl->comm);
+ }
+}
+
+
+/*************************************************************************
+* This function prints a vector stored in each processor
+**************************************************************************/
+void PrintVector2(CtrlType *ctrl, int n, int first, idxtype *vec, char *title)
+{
+ int i, penum;
+
+ for (penum=0; penum<ctrl->npes; penum++) {
+ if (ctrl->mype == penum) {
+ if (ctrl->mype == 0)
+ printf("%s\n", title);
+ printf("\t%3d. ", ctrl->mype);
+ for (i=0; i<n; i++)
+ printf("[%d %d.%hd] ", first+i, (vec[i]>=KEEP_BIT ? 1 : 0), (vec[i]>=KEEP_BIT ? vec[i]-KEEP_BIT : vec[i]));
+ printf("\n");
+ fflush(stdout);
+ }
+ MPI_Barrier(ctrl->comm);
+ }
+}
+
+
+/*************************************************************************
+* This function prints a vector stored in each processor
+**************************************************************************/
+void PrintPairs(CtrlType *ctrl, int n, KeyValueType *pairs, char *title)
+{
+ int i, penum;
+
+ for (penum=0; penum<ctrl->npes; penum++) {
+ if (ctrl->mype == penum) {
+ if (ctrl->mype == 0)
+ printf("%s\n", title);
+ printf("\t%3d. ", ctrl->mype);
+ for (i=0; i<n; i++)
+ printf("[%d %hd,%hd] ", i, pairs[i].key, pairs[i].val);
+ printf("\n");
+ fflush(stdout);
+ }
+ MPI_Barrier(ctrl->comm);
+ }
+}
+
+
+
+/*************************************************************************
+* This function prints the local portion of the graph stored at each
+* processor
+**************************************************************************/
+void PrintGraph(CtrlType *ctrl, GraphType *graph)
+{
+ int i, j, penum;
+ int firstvtx;
+
+ MPI_Barrier(ctrl->comm);
+
+ firstvtx = graph->vtxdist[ctrl->mype];
+
+ for (penum=0; penum<ctrl->npes; penum++) {
+ if (ctrl->mype == penum) {
+ printf("\t%d", penum);
+ for (i=0; i<graph->nvtxs; i++) {
+ if (i==0)
+ printf("\t%2d %2d\t", firstvtx+i, graph->vwgt[i]);
+ else
+ printf("\t\t%2d %2d\t", firstvtx+i, graph->vwgt[i]);
+ for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++)
+ printf("[%d %d] ", graph->adjncy[j], graph->adjwgt[j]);
+ printf("\n");
+ }
+ fflush(stdout);
+ }
+ MPI_Barrier(ctrl->comm);
+ }
+}
+
+
+/*************************************************************************
+* This function prints the local portion of the graph stored at each
+* processor along with degree information during refinement
+**************************************************************************/
+void PrintGraph2(CtrlType *ctrl, GraphType *graph)
+{
+ int i, j, penum;
+ int firstvtx;
+
+ MPI_Barrier(ctrl->comm);
+
+ firstvtx = graph->vtxdist[ctrl->mype];
+
+ for (penum=0; penum<ctrl->npes; penum++) {
+ if (ctrl->mype == penum) {
+ printf("\t%d", penum);
+ for (i=0; i<graph->nvtxs; i++) {
+ if (i==0)
+ printf("\t%2d %2d [%d %d %d]\t", firstvtx+i, graph->vwgt[i], graph->where[i], graph->rinfo[i].id, graph->rinfo[i].ed);
+ else
+ printf("\t\t%2d %2d [%d %d %d]\t", firstvtx+i, graph->vwgt[i], graph->where[i], graph->rinfo[i].id, graph->rinfo[i].ed);
+ for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++)
+ printf("[%d %d] ", graph->adjncy[j], graph->adjwgt[j]);
+ printf("\n");
+ }
+ fflush(stdout);
+ }
+ MPI_Barrier(ctrl->comm);
+ }
+}
+
+
+/*************************************************************************
+* This function prints the information computed during setup
+**************************************************************************/
+void PrintSetUpInfo(CtrlType *ctrl, GraphType *graph)
+{
+ int i, j, penum;
+
+ MPI_Barrier(ctrl->comm);
+
+ for (penum=0; penum<ctrl->npes; penum++) {
+ if (ctrl->mype == penum) {
+ printf("PE: %d, nnbrs: %d\n", ctrl->mype, graph->nnbrs);
+ printf("\tSending...\n");
+ for (i=0; i<graph->nnbrs; i++) {
+ printf("\t\tTo: %d: ", graph->peind[i]);
+ for (j=graph->sendptr[i]; j<graph->sendptr[i+1]; j++)
+ printf("%d ", graph->sendind[j]);
+ printf("\n");
+ }
+ printf("\tReceiving...\n");
+ for (i=0; i<graph->nnbrs; i++) {
+ printf("\t\tFrom: %d: ", graph->peind[i]);
+ for (j=graph->recvptr[i]; j<graph->recvptr[i+1]; j++)
+ printf("%d ", graph->recvind[j]);
+ printf("\n");
+ }
+ printf("\n");
+ }
+ MPI_Barrier(ctrl->comm);
+ }
+
+}
+
+
+/*************************************************************************
+* This function prints information about the graphs that were sent/received
+**************************************************************************/
+void PrintTransferedGraphs(CtrlType *ctrl, int nnbrs, idxtype *peind, idxtype *slens,
+ idxtype *rlens, idxtype *sgraph, idxtype *rgraph)
+{
+ int i, ii, jj, ll, penum;
+
+ MPI_Barrier(ctrl->comm);
+ for (penum=0; penum<ctrl->npes; penum++) {
+ if (ctrl->mype == penum) {
+ printf("PE: %d, nnbrs: %d", ctrl->mype, nnbrs);
+ for (ll=i=0; i<nnbrs; i++) {
+ if (slens[i+1]-slens[i] > 0) {
+ printf("\n\tTo %d\t", peind[i]);
+ for (ii=slens[i]; ii<slens[i+1]; ii++) {
+ printf("%d %d %d, ", sgraph[ll], sgraph[ll+1], sgraph[ll+2]);
+ for (jj=0; jj<sgraph[ll+1]; jj++)
+ printf("[%d %d] ", sgraph[ll+3+2*jj], sgraph[ll+3+2*jj+1]);
+ printf("\n\t\t");
+ ll += 3+2*sgraph[ll+1];
+ }
+ }
+ }
+
+ for (ll=i=0; i<nnbrs; i++) {
+ if (rlens[i+1]-rlens[i] > 0) {
+ printf("\n\tFrom %d\t", peind[i]);
+ for (ii=rlens[i]; ii<rlens[i+1]; ii++) {
+ printf("%d %d %d, ", rgraph[ll], rgraph[ll+1], rgraph[ll+2]);
+ for (jj=0; jj<rgraph[ll+1]; jj++)
+ printf("[%d %d] ", rgraph[ll+3+2*jj], rgraph[ll+3+2*jj+1]);
+ printf("\n\t\t");
+ ll += 3+2*rgraph[ll+1];
+ }
+ }
+ }
+ printf("\n");
+ }
+ MPI_Barrier(ctrl->comm);
+ }
+
+}
+
+
+/*************************************************************************
+* This function writes a graph in the format used by serial METIS
+**************************************************************************/
+void WriteMetisGraph(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt)
+{
+ int i, j;
+ FILE *fp;
+
+ fp = fopen("test.graph", "w");
+
+ fprintf(fp, "%d %d 11", nvtxs, xadj[nvtxs]/2);
+ for (i=0; i<nvtxs; i++) {
+ fprintf(fp, "\n%d ", vwgt[i]);
+ for (j=xadj[i]; j<xadj[i+1]; j++)
+ fprintf(fp, " %d %d", adjncy[j]+1, adjwgt[j]);
+ }
+ fclose(fp);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/defs.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/defs.h
new file mode 100644
index 0000000..3d47f1d
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/defs.h
@@ -0,0 +1,102 @@
+/*
+ * 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.4 2003/07/22 20:29:05 karypis Exp $
+ *
+ */
+
+
+#define GLOBAL_DBGLVL 0
+#define GLOBAL_SEED 15
+
+#define MC_FLOW_BALANCE_THRESHOLD 0.2
+#define MOC_GD_GRANULARITY_FACTOR 1.0
+#define RIP_SPLIT_FACTOR 8
+#define MAX_NPARTS_MULTIPLIER 20
+
+#define STATIC_PARTITION 1
+#define ADAPTIVE_PARTITION 2
+#define REFINE_PARTITION 3
+#define MESH_PARTITION 4
+
+#define REDIST_WGT 2.0
+#define MAXNVWGT_FACTOR 2.0
+
+#define MAXNCON 12
+#define MAXNOBJ 12
+#define N_MOC_REDO_PASSES 10
+#define N_MOC_GR_PASSES 8
+#define NREMAP_PASSES 8
+#define N_MOC_GD_PASSES 6
+#define N_MOC_BAL_PASSES 4
+#define NMATCH_PASSES 4
+
+#define COUPLED 1
+#define DISCOUPLED 2
+
+#define MAX_NCON_FOR_DIFFUSION 2
+#define SMALLGRAPH 10000
+
+#define LTERM (void **) 0 /* List terminator for GKfree() */
+
+#define NGD_PASSES 20
+
+#define OPTION_IPART 1
+#define OPTION_FOLDF 2
+#define OPTION_DBGLVL 3
+
+#define PMV3_OPTION_DBGLVL 1
+#define PMV3_OPTION_SEED 2
+#define PMV3_OPTION_IPART 3
+#define PMV3_OPTION_PSR 3
+
+#define XYZ_XCOORD 1
+#define XYZ_SPFILL 2
+
+/* Type of initial vertex separator algorithms */
+#define ISEP_EDGE 1
+#define ISEP_NODE 2
+
+#define UNMATCHED -1
+#define MAYBE_MATCHED -2
+#define TOO_HEAVY -3
+
+
+#define HTABLE_EMPTY -1
+
+#define NGR_PASSES 4 /* Number of greedy refinement passes */
+#define NIPARTS 8 /* Number of random initial partitions */
+#define NLGR_PASSES 5 /* Number of GR refinement during IPartition */
+
+#define SMALLFLOAT 0.00001
+/* #define KEEP_BIT (idxtype)536870912 */ /* 1<<29 */
+#define KEEP_BIT ((idxtype)(1<<((sizeof(idxtype)*8)-2)))
+
+#define MAX_PES 8192
+#define MAX_NPARTS 67108864
+
+#define COARSEN_FRACTION 0.75 /* Node reduction between succesive coarsening levels */
+#define COARSEN_FRACTION2 0.55 /* Node reduction between succesive coarsening levels */
+#define UNBALANCE_FRACTION 1.05
+#define ORDER_UNBALANCE_FRACTION 1.05
+
+#define MAXVWGT_FACTOR 1.4
+
+#define MATCH_LOCAL 1
+#define MATCH_GLOBAL 2
+
+/* Debug Levels */
+#define DBG_TIME 1 /* Perform timing analysis */
+#define DBG_INFO 2 /* Perform timing analysis */
+#define DBG_PROGRESS 4 /* Show the coarsening progress */
+#define DBG_REFINEINFO 8 /* Show info on communication during folding */
+#define DBG_MATCHINFO 16 /* Show info on matching */
+#define DBG_RMOVEINFO 32 /* Show info on communication during folding */
+#define DBG_REMAP 64 /* Determines if remapping will take place */
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/diffutil.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/diffutil.c
new file mode 100644
index 0000000..f31da64
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/diffutil.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * wavefrontK.c
+ *
+ * This file contains code for the initial directed diffusion at the coarsest
+ * graph
+ *
+ * Started 5/19/97, Kirk, George
+ *
+ * $Id: diffutil.c,v 1.2 2003/07/21 17:18:48 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function computes the load for each subdomain
+**************************************************************************/
+void SetUpConnectGraph(GraphType *graph, MatrixType *matrix, idxtype *workspace)
+{
+ int i, ii, j, jj, k, l;
+ int nvtxs, nrows;
+ idxtype *xadj, *adjncy, *where;
+ idxtype *rowptr, *colind;
+ idxtype *pcounts, *perm, *marker;
+ float *values;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ where = graph->where;
+
+ nrows = matrix->nrows;
+ rowptr = matrix->rowptr;
+ colind = matrix->colind;
+ values = matrix->values;
+
+ perm = workspace;
+ marker = idxset(nrows, -1, workspace+nvtxs);
+ pcounts = idxset(nrows+1, 0, workspace+nvtxs+nrows);
+
+ for (i=0; i<nvtxs; i++)
+ pcounts[where[i]]++;
+ MAKECSR(i, nrows, pcounts);
+
+ for (i=0; i<nvtxs; i++)
+ perm[pcounts[where[i]]++] = i;
+
+ for (i=nrows; i>0; i--)
+ pcounts[i] = pcounts[i-1];
+ pcounts[0] = 0;
+
+ /************************/
+ /* Construct the matrix */
+ /************************/
+ rowptr[0] = k = 0;
+ for (ii=0; ii<nrows; ii++) {
+ colind[k++] = ii;
+ marker[ii] = ii;
+
+ for (jj=pcounts[ii]; jj<pcounts[ii+1]; jj++) {
+ i = perm[jj];
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ l = where[adjncy[j]];
+ if (marker[l] != ii) {
+ colind[k] = l;
+ values[k++] = -1.0;
+ marker[l] = ii;
+ }
+ }
+ }
+ values[rowptr[ii]] = (float)(k-rowptr[ii]-1);
+ rowptr[ii+1] = k;
+ }
+ matrix->nnzs = rowptr[nrows];
+
+ return;
+}
+
+
+/*************************************************************************
+* This function computes movement statistics for adaptive refinement
+* schemes
+**************************************************************************/
+void Mc_ComputeMoveStatistics(CtrlType *ctrl, GraphType *graph, int *nmoved, int *maxin, int *maxout)
+{
+ int i, nvtxs, nparts, myhome;
+ idxtype *vwgt, *where;
+ idxtype *lend, *gend, *lleft, *gleft, *lstart, *gstart;
+
+ nvtxs = graph->nvtxs;
+ vwgt = graph->vwgt;
+ where = graph->where;
+ nparts = ctrl->nparts;
+
+ lstart = idxsmalloc(nparts, 0, "ComputeMoveStatistics: lstart");
+ gstart = idxsmalloc(nparts, 0, "ComputeMoveStatistics: gstart");
+ lleft = idxsmalloc(nparts, 0, "ComputeMoveStatistics: lleft");
+ gleft = idxsmalloc(nparts, 0, "ComputeMoveStatistics: gleft");
+ lend = idxsmalloc(nparts, 0, "ComputeMoveStatistics: lend");
+ gend = idxsmalloc(nparts, 0, "ComputeMoveStatistics: gend");
+
+ for (i=0; i<nvtxs; i++) {
+ myhome = (ctrl->ps_relation == COUPLED) ? ctrl->mype : graph->home[i];
+ lstart[myhome] += (graph->vsize == NULL) ? 1 : graph->vsize[i];
+ lend[where[i]] += (graph->vsize == NULL) ? 1 : graph->vsize[i];
+ if (where[i] != myhome)
+ lleft[myhome] += (graph->vsize == NULL) ? 1 : graph->vsize[i];
+ }
+
+ /* PrintVector(ctrl, ctrl->npes, 0, lend, "Lend: "); */
+
+ MPI_Allreduce((void *)lstart, (void *)gstart, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+ MPI_Allreduce((void *)lleft, (void *)gleft, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+ MPI_Allreduce((void *)lend, (void *)gend, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+
+ *nmoved = idxsum(nparts, gleft);
+ *maxout = gleft[idxamax(nparts, gleft)];
+ for (i=0; i<nparts; i++)
+ lstart[i] = gend[i]+gleft[i]-gstart[i];
+ *maxin = lstart[idxamax(nparts, lstart)];
+
+ GKfree((void **)&lstart, (void **)&gstart, (void **)&lleft, (void **)&gleft, (void **)&lend, (void **)&gend, LTERM);
+}
+
+/*************************************************************************
+* This function computes the TotalV of a serial graph.
+**************************************************************************/
+int Mc_ComputeSerialTotalV(GraphType *graph, idxtype *home)
+{
+ int i;
+ int totalv = 0;
+
+ for (i=0; i<graph->nvtxs; i++) {
+ if (graph->where[i] != home[i])
+ totalv += (graph->vsize == NULL) ? graph->vwgt[i*graph->ncon] : graph->vsize[i];
+ }
+
+ return totalv;
+}
+
+
+
+/*************************************************************************
+* This function computes the load for each subdomain
+**************************************************************************/
+void ComputeLoad(GraphType *graph, int nparts, float *load, float *tpwgts, int index)
+{
+ int i;
+ int nvtxs, ncon;
+ idxtype *where;
+ float *nvwgt;
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ where = graph->where;
+ nvwgt = graph->nvwgt;
+
+ sset(nparts, 0.0, load);
+
+ for (i=0; i<nvtxs; i++)
+ load[where[i]] += nvwgt[i*ncon+index];
+
+ ASSERTS(fabs(ssum(nparts, load)-1.0) < 0.001);
+
+ for (i=0; i<nparts; i++) {
+ load[i] -= tpwgts[i*ncon+index];
+ }
+
+ return;
+}
+
+
+/*************************************************************************
+* This function implements the CG solver used during the directed diffusion
+**************************************************************************/
+void ConjGrad2(MatrixType *A, float *b, float *x, float tol, float *workspace)
+{
+ int i, k, n;
+ float *p, *r, *q, *z, *M;
+ float alpha, beta, rho, rho_1 = -1.0, error, bnrm2, tmp;
+ idxtype *rowptr, *colind;
+ float *values;
+
+ n = A->nrows;
+ rowptr = A->rowptr;
+ colind = A->colind;
+ values = A->values;
+
+ /* Initial Setup */
+ p = workspace;
+ r = workspace + n;
+ q = workspace + 2*n;
+ z = workspace + 3*n;
+ M = workspace + 4*n;
+
+ for (i=0; i<n; i++) {
+ x[i] = 0.0;
+ if (values[rowptr[i]] != 0.0)
+ M[i] = 1.0/values[rowptr[i]];
+ else
+ M[i] = 0.0;
+ }
+
+ /* r = b - Ax */
+ mvMult2(A, x, r);
+ for (i=0; i<n; i++)
+ r[i] = b[i]-r[i];
+
+ bnrm2 = snorm2(n, b);
+ if (bnrm2 > 0.0) {
+ error = snorm2(n, r) / bnrm2;
+
+ if (error > tol) {
+ /* Begin Iterations */
+ for (k=0; k<n; k++) {
+ for (i=0; i<n; i++)
+ z[i] = r[i]*M[i];
+
+ rho = sdot(n, r, z);
+
+ if (k == 0)
+ scopy(n, z, p);
+ else {
+ if (rho_1 != 0.0)
+ beta = rho/rho_1;
+ else
+ beta = 0.0;
+ for (i=0; i<n; i++)
+ p[i] = z[i] + beta*p[i];
+ }
+
+ mvMult2(A, p, q); /* q = A*p */
+
+ tmp = sdot(n, p, q);
+ if (tmp != 0.0)
+ alpha = rho/tmp;
+ else
+ alpha = 0.0;
+ saxpy(n, alpha, p, x); /* x = x + alpha*p */
+ saxpy(n, -alpha, q, r); /* r = r - alpha*q */
+ error = snorm2(n, r) / bnrm2;
+ if (error < tol)
+ break;
+
+ rho_1 = rho;
+ }
+ }
+ }
+}
+
+
+/*************************************************************************
+* This function performs Matrix-Vector multiplication
+**************************************************************************/
+void mvMult2(MatrixType *A, float *v, float *w)
+{
+ int i, j;
+
+ for (i = 0; i < A->nrows; i++)
+ w[i] = 0.0;
+
+ for (i = 0; i < A->nrows; i++)
+ for (j = A->rowptr[i]; j < A->rowptr[i+1]; j++)
+ w[i] += A->values[j] * v[A->colind[j]];
+
+ return;
+ }
+
+
+/*************************************************************************
+* This function sets up the transfer vectors
+**************************************************************************/
+void ComputeTransferVector(int ncon, MatrixType *matrix, float *solution,
+ float *transfer, int index)
+{
+ int j, k;
+ int nrows;
+ idxtype *rowptr, *colind;
+
+ nrows = matrix->nrows;
+ rowptr = matrix->rowptr;
+ colind = matrix->colind;
+
+ for (j=0; j<nrows; j++) {
+ for (k=rowptr[j]+1; k<rowptr[j+1]; k++) {
+ if (solution[j] > solution[colind[k]]) {
+ transfer[k*ncon+index] = solution[j] - solution[colind[k]];
+ }
+ else {
+ transfer[k*ncon+index] = 0.0;
+ }
+ }
+ }
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/fpqueue.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/fpqueue.c
new file mode 100644
index 0000000..11c617f
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/fpqueue.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * fpqueue.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: fpqueue.c,v 1.2 2003/07/21 17:18:48 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function initializes the data structures of the priority queue
+**************************************************************************/
+void FPQueueInit(FPQueueType *queue, int maxnodes)
+{
+ queue->nnodes = 0;
+ queue->maxnodes = maxnodes;
+ queue->heap = NULL;
+ queue->locator = NULL;
+
+ queue->heap = (FKeyValueType *) malloc(sizeof(FKeyValueType)*maxnodes);
+ queue->locator = (idxtype *) malloc(sizeof(idxtype)*maxnodes);
+
+ idxset(maxnodes, -1, queue->locator);
+
+}
+
+
+/*************************************************************************
+* This function resets the buckets
+**************************************************************************/
+void FPQueueReset(FPQueueType *queue)
+{
+ queue->nnodes = 0;
+
+ idxset(queue->maxnodes, -1, queue->locator);
+
+}
+
+
+/*************************************************************************
+* This function frees the buckets
+**************************************************************************/
+void FPQueueFree(FPQueueType *queue)
+{
+
+ free(queue->heap);
+ free(queue->locator);
+
+ queue->maxnodes = 0;
+}
+
+
+/*************************************************************************
+* This function returns the number of nodes in the queue
+**************************************************************************/
+int FPQueueGetSize(FPQueueType *queue)
+{
+ return queue->nnodes;
+}
+
+
+/*************************************************************************
+* This function adds a node of certain gain into a partition
+**************************************************************************/
+int FPQueueInsert(FPQueueType *queue, int node, float gain)
+{
+ int i, j;
+ idxtype *locator;
+ FKeyValueType *heap;
+
+ ASSERTS(CheckHeapFloat(queue));
+
+ heap = queue->heap;
+ locator = queue->locator;
+
+ ASSERTS(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;
+ }
+ ASSERTS(i >= 0);
+ heap[i].key = gain;
+ heap[i].val = node;
+ locator[node] = i;
+
+ ASSERTS(CheckHeapFloat(queue));
+
+ return 0;
+}
+
+
+/*************************************************************************
+* This function deletes a node from a partition and reinserts it with
+* an updated gain
+**************************************************************************/
+int FPQueueDelete(FPQueueType *queue, int node)
+{
+ int i, j;
+ float newgain, oldgain;
+ idxtype *locator;
+ FKeyValueType *heap;
+
+ heap = queue->heap;
+ locator = queue->locator;
+
+ ASSERTS(locator[node] != -1);
+ ASSERTS(heap[locator[node]].val == node);
+
+ ASSERTS(CheckHeapFloat(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;
+ }
+
+ ASSERTS(CheckHeapFloat(queue));
+
+ return 0;
+}
+
+
+
+/*************************************************************************
+* This function deletes a node from a partition and reinserts it with
+* an updated gain
+**************************************************************************/
+int FPQueueUpdate(FPQueueType *queue, int node, float oldgain, float newgain)
+{
+ int i, j;
+ idxtype *locator;
+ FKeyValueType *heap;
+
+ if (oldgain == newgain)
+ return 0;
+
+ heap = queue->heap;
+ locator = queue->locator;
+
+ ASSERTS(locator[node] != -1);
+ ASSERTS(heap[locator[node]].val == node);
+ ASSERTS(fabs(heap[locator[node]].key - oldgain) < SMALLFLOAT);
+ ASSERTS(CheckHeapFloat(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;
+
+ ASSERTS(CheckHeapFloat(queue));
+
+ return 0;
+}
+
+
+
+/*************************************************************************
+* This function deletes a node from a partition and reinserts it with
+* an updated gain
+**************************************************************************/
+void FPQueueUpdateUp(FPQueueType *queue, int node, float oldgain, float newgain)
+{
+ int i, j;
+ idxtype *locator;
+ FKeyValueType *heap;
+
+ if (oldgain == newgain)
+ return;
+
+ heap = queue->heap;
+ locator = queue->locator;
+
+ ASSERTS(locator[node] != -1);
+ ASSERTS(heap[locator[node]].val == node);
+ ASSERTS(heap[locator[node]].key == oldgain);
+ ASSERTS(CheckHeapFloat(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;
+
+ ASSERTS(CheckHeapFloat(queue));
+
+}
+
+
+/*************************************************************************
+* This function returns the vertex with the largest gain from a partition
+* and removes the node from the bucket list
+**************************************************************************/
+int FPQueueGetMax(FPQueueType *queue)
+{
+ int vtx, i, j, node;
+ float gain;
+ idxtype *locator;
+ FKeyValueType *heap;
+
+ if (queue->nnodes == 0)
+ return -1;
+
+ queue->nnodes--;
+
+ 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;
+ }
+
+ ASSERTS(CheckHeapFloat(queue));
+ return vtx;
+}
+
+
+/*************************************************************************
+* This function returns the vertex with the largest gain from a partition
+**************************************************************************/
+int FPQueueSeeMaxVtx(FPQueueType *queue)
+{
+ int vtx;
+
+ if (queue->nnodes == 0)
+ return -1;
+
+ vtx = queue->heap[0].val;
+
+ return vtx;
+}
+
+
+/*************************************************************************
+* This function returns the vertex with the largest gain from a partition
+**************************************************************************/
+float FPQueueSeeMaxGain(FPQueueType *queue)
+{
+ float gain;
+
+ if (queue->nnodes == 0)
+ return 0.0;
+
+ gain = queue->heap[0].key;
+
+ return gain;
+}
+
+
+/*************************************************************************
+* This function returns the vertex with the largest gain from a partition
+**************************************************************************/
+float FPQueueGetKey(FPQueueType *queue)
+{
+ int key;
+
+ if (queue->nnodes == 0)
+ return -1;
+
+ key = queue->heap[0].key;
+
+ return key;
+}
+
+/*************************************************************************
+* This function returns the number of nodes in the queue
+**************************************************************************/
+int FPQueueGetQSize(FPQueueType *queue)
+{
+ return queue->nnodes;
+}
+
+
+
+
+
+
+/*************************************************************************
+* This functions checks the consistency of the heap
+**************************************************************************/
+int CheckHeapFloat(FPQueueType *queue)
+{
+ int i, j, nnodes;
+ idxtype *locator;
+ FKeyValueType *heap;
+
+ heap = queue->heap;
+ locator = queue->locator;
+ nnodes = queue->nnodes;
+
+ if (nnodes == 0)
+ return 1;
+
+ ASSERTS(locator[heap[0].val] == 0);
+ for (i=1; i<nnodes; i++) {
+ ASSERTS(locator[heap[i].val] == i);
+ ASSERTS(heap[i].key <= heap[(i-1)/2].key);
+ }
+ for (i=1; i<nnodes; i++)
+ ASSERTS(heap[i].key <= heap[0].key);
+
+ for (j=i=0; i<queue->maxnodes; i++) {
+ if (locator[i] != -1)
+ j++;
+ }
+ ASSERTS(j == nnodes);
+
+ return 1;
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/frename.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/frename.c
new file mode 100644
index 0000000..551dd59
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/frename.c
@@ -0,0 +1,322 @@
+/*
+ * frename.c
+ *
+ * This file contains some renaming routines to deal with different
+ * Fortran compilers.
+ *
+ * Started 6/1/98
+ * George
+ *
+ * $Id: frename.c,v 1.4 2003/07/30 18:37:58 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+/*************************************************************************
+* Renaming macro (at least to save some typing :))
+**************************************************************************/
+#define FRENAME(name0, name1, name2, name3, name4, dargs, cargs) \
+ void name1 dargs { name0 cargs; } \
+ void name2 dargs { name0 cargs; } \
+ void name3 dargs { name0 cargs; } \
+ void name4 dargs { name0 cargs; }
+
+
+
+
+
+
+
+
+/*************************************************************************
+* Renames for Release 3.0 API
+**************************************************************************/
+FRENAME(ParMETIS_V3_AdaptiveRepart,
+ PARMETIS_V3_ADAPTIVEREPART,
+ parmetis_v3_adaptiverepart,
+ parmetis_v3_adaptiverepart_,
+ parmetis_v3_adaptiverepart__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
+ idxtype *vsize, idxtype *adjwgt, int *wgtflag, int *numflag, int *ncon,
+ int *nparts, float *tpwgts, float *ubvec, float *ipc2redist,
+ int *options, int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, vsize, adjwgt, wgtflag, numflag, ncon,
+ nparts, tpwgts, ubvec, ipc2redist, options, edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_V3_PartGeomKway,
+ PARMETIS_V3_PARTGEOMKWAY,
+ parmetis_v3_partgeomkway,
+ parmetis_v3_partgeomkway_,
+ parmetis_v3_partgeomkway__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
+ idxtype *adjwgt, int *wgtflag, int *numflag, int *ndims, float *xyz,
+ int *ncon, int *nparts, float *tpwgts, float *ubvec, int *options,
+ int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, ndims, xyz,
+ ncon, nparts, tpwgts, ubvec, options, edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_V3_PartGeom,
+ PARMETIS_V3_PARTGEOM,
+ parmetis_v3_partgeom,
+ parmetis_v3_partgeom_,
+ parmetis_v3_partgeom__,
+ (idxtype *vtxdist, int *ndims, float *xyz, idxtype *part, MPI_Comm *comm),
+ (vtxdist, ndims, xyz, part, comm)
+)
+
+FRENAME(ParMETIS_V3_PartKway,
+ PARMETIS_V3_PARTKWAY,
+ parmetis_v3_partkway,
+ parmetis_v3_partkway_,
+ parmetis_v3_partkway__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *ncon, int *nparts, float *tpwgts, float *ubvec,
+ int *options, int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, ncon, nparts, tpwgts,
+ ubvec, options, edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_V3_Mesh2Dual,
+ PARMETIS_V3_MESH2DUAL,
+ parmetis_v3_mesh2dual,
+ parmetis_v3_mesh2dual_,
+ parmetis_v3_mesh2dual__,
+ (idxtype *elmdist, idxtype *eptr, idxtype *eind, int *numflag, int *ncommonnodes,
+ idxtype **xadj, idxtype **adjncy, MPI_Comm *comm),
+ (elmdist, eptr, eind, numflag, ncommonnodes, xadj, adjncy, comm)
+)
+
+FRENAME(ParMETIS_V3_PartMeshKway,
+ PARMETIS_V3_PARTMESHKWAY,
+ parmetis_v3_partmeshkway,
+ parmetis_v3_partmeshkway_,
+ parmetis_v3_partmeshkway__,
+ (idxtype *elmdist, idxtype *eptr, idxtype *eind, idxtype *elmwgt, int *wgtflag,
+ int *numflag, int *ncon, int *ncommonnodes, int *nparts, float *tpwgts,
+ float *ubvec, int *options, int *edgecut, idxtype *part, MPI_Comm *comm),
+ (elmdist, eptr, eind, elmwgt, wgtflag, numflag, ncon, ncommonnodes, nparts, tpwgts,
+ ubvec, options, edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_V3_NodeND,
+ PARMETIS_V3_NODEND,
+ parmetis_v3_nodend,
+ parmetis_v3_nodend_,
+ parmetis_v3_nodend__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, int *numflag, int *options,
+ idxtype *order, idxtype *sizes, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, numflag, options, order, sizes, comm)
+)
+
+FRENAME(ParMETIS_V3_RefineKway,
+ PARMETIS_V3_REFINEKWAY,
+ parmetis_v3_refinekway,
+ parmetis_v3_refinekway_,
+ parmetis_v3_refinekway__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *ncon, int *nparts, float *tpwgts, float *ubvec,
+ int *options, int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, ncon, nparts, tpwgts,
+ ubvec, options, edgecut, part, comm)
+)
+
+
+/*************************************************************************
+* Renames for Release 2.0 API
+**************************************************************************/
+FRENAME(ParMETIS_PartKway,
+ PARMETIS_PARTKWAY,
+ parmetis_partkway,
+ parmetis_partkway_,
+ parmetis_partkway__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part,
+ MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut,
+ part, comm)
+)
+
+FRENAME(ParMETIS_PartGeomKway,
+ PARMETIS_PARTGEOMKWAY,
+ parmetis_partgeomkway,
+ parmetis_partgeomkway_,
+ parmetis_partgeomkway__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *ndims, float *xyz, int *nparts, int *options,
+ int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, ndims, xyz, nparts, options,
+ edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_PartGeom,
+ PARMETIS_PARTGEOM,
+ parmetis_partgeom,
+ parmetis_partgeom_,
+ parmetis_partgeom__,
+ (idxtype *vtxdist, int *ndims, float *xyz, idxtype *part, MPI_Comm *comm),
+ (vtxdist, ndims, xyz, part, comm)
+)
+
+FRENAME(ParMETIS_PartGeomRefine,
+ PARMETIS_PARTGEOMREFINE,
+ parmetis_partgeomrefine,
+ parmetis_partgeomrefine_,
+ parmetis_partgeomrefine__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *ndims, float *xyz, int *options, int *edgecut,
+ idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, ndims, xyz, options,
+ edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_RefineKway,
+ PARMETIS_REFINEKWAY,
+ parmetis_refinekway,
+ parmetis_refinekway_,
+ parmetis_refinekway__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *options, int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, options, edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_RepartLDiffusion,
+ PARMETIS_REPARTLDIFUSSION,
+ parmetis_repartldiffusion,
+ parmetis_repartldiffusion_,
+ parmetis_repartldiffusion__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *options, int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, options, edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_RepartGDiffusion,
+ PARMETIS_REPARTGDIFFUSION,
+ parmetis_repartgdiffusion,
+ parmetis_repartgdiffusion_,
+ parmetis_repartgdiffusion__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *options, int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, options, edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_RepartRemap,
+ PARMETIS_REPARTREMAP,
+ parmetis_repartremap,
+ parmetis_repartremap_,
+ parmetis_repartremap__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *options, int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, options, edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_RepartMLRemap,
+ PARMETIS_REPARTMLREMAP,
+ parmetis_repartmlremap,
+ parmetis_repartmlremap_,
+ parmetis_repartmlremap__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt,
+ int *wgtflag, int *numflag, int *options, int *edgecut, idxtype *part, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, options, edgecut, part, comm)
+)
+
+FRENAME(ParMETIS_NodeND,
+ PARMETIS_NODEND,
+ parmetis_nodend,
+ parmetis_nodend_,
+ parmetis_nodend__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, int *numflag, int *options,
+ idxtype *order, idxtype *sizes, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, numflag, options, order, sizes, comm)
+)
+
+FRENAME(ParMETIS_SerialNodeND,
+ PARMETIS_SERIALNODEND,
+ parmetis_serialnodend,
+ parmetis_serialnodend_,
+ parmetis_serialnodend__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, int *numflag, int *options,
+ idxtype *order, idxtype *sizes, MPI_Comm *comm),
+ (vtxdist, xadj, adjncy, numflag, options, order, sizes, comm)
+)
+
+
+
+
+/*************************************************************************
+* Renames for Release 1.0 API
+**************************************************************************/
+FRENAME(PARKMETIS,
+ PARKMETIS_,
+ parkmetis,
+ parkmetis_,
+ parkmetis__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ idxtype *part, int *options, MPI_Comm comm),
+ (vtxdist, xadj, vwgt, adjncy, adjwgt, part, options, comm)
+)
+
+FRENAME(PARGKMETIS,
+ PARGKMETIS_,
+ pargkmetis,
+ pargkmetis_,
+ pargkmetis__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ int ndims, float *xyz, idxtype *part, int *options, MPI_Comm comm),
+ (vtxdist, xadj, vwgt, adjncy, adjwgt, ndims, xyz, part, options, comm)
+)
+
+FRENAME(PARGRMETIS,
+ PARGRMETIS_,
+ pargrmetis,
+ pargrmetis_,
+ pargrmetis__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ int ndims, float *xyz, idxtype *part, int *options, MPI_Comm comm),
+ (vtxdist, xadj, vwgt, adjncy, adjwgt, ndims, xyz, part, options, comm)
+)
+
+FRENAME(PARGMETIS,
+ PARGMETIS_,
+ pargmetis,
+ pargmetis_,
+ pargmetis__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, int ndims, float *xyz,
+ idxtype *part, int *options, MPI_Comm comm),
+ (vtxdist, xadj, adjncy, ndims, xyz, part, options, comm)
+)
+
+FRENAME(PARRMETIS,
+ PARRMETIS_,
+ parrmetis,
+ parrmetis_,
+ parrmetis__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ idxtype *part, int *options, MPI_Comm comm),
+ (vtxdist, xadj, vwgt, adjncy, adjwgt, part, options, comm)
+)
+
+FRENAME(PARUAMETIS,
+ PARUAMETIS_,
+ paruametis,
+ paruametis_,
+ paruametis__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ idxtype *part, int *options, MPI_Comm comm),
+ (vtxdist, xadj, vwgt, adjncy, adjwgt, part, options, comm)
+)
+
+FRENAME(PARDAMETIS,
+ PARDAMETIS_,
+ pardametis,
+ pardametis_,
+ pardametis__,
+ (idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ idxtype *part, int *options, MPI_Comm comm),
+ (vtxdist, xadj, vwgt, adjncy, adjwgt, part, options, comm)
+)
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/gkmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/gkmetis.c
new file mode 100644
index 0000000..8eb2382
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/gkmetis.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * gkmetis.c
+ *
+ * This is the entry point of parallel geometry based partitioning
+ * routines
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: gkmetis.c,v 1.8 2003/07/31 16:23:30 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel kmetis algorithm that uses
+* coordinates to compute an initial graph distribution.
+************************************************************************************/
+void ParMETIS_V3_PartGeomKway(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy,
+ idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *ndims,
+ float *xyz, int *ncon, int *nparts, float *tpwgts, float *ubvec,
+ int *options, int *edgecut, idxtype *part, MPI_Comm *comm)
+{
+ int h, i, j;
+ int nvtxs = -1, npes, mype;
+ int uwgtflag, cut, gcut, maxnvtxs;
+ int ltvwgts[MAXNCON];
+ int moptions[10];
+ CtrlType ctrl;
+ idxtype *uvwgt;
+ WorkSpaceType wspace;
+ GraphType *graph, *mgraph;
+ float avg, maximb, balance, *mytpwgts;
+ int seed, dbglvl = 0;
+ int iwgtflag, inumflag, incon, inparts, ioptions[10];
+ float *itpwgts, iubvec[MAXNCON];
+
+ MPI_Comm_size(*comm, &npes);
+ MPI_Comm_rank(*comm, &mype);
+
+ /********************************/
+ /* Try and take care bad inputs */
+ /********************************/
+ if (options != NULL && options[0] == 1)
+ dbglvl = options[PMV3_OPTION_DBGLVL];
+
+ CheckInputs(STATIC_PARTITION, npes, dbglvl, wgtflag, &iwgtflag, numflag, &inumflag,
+ ncon, &incon, nparts, &inparts, tpwgts, &itpwgts, ubvec, iubvec,
+ NULL, NULL, options, ioptions, part, comm);
+
+
+ /*********************************/
+ /* Take care the nparts = 1 case */
+ /*********************************/
+ if (inparts <= 1) {
+ idxset(vtxdist[mype+1]-vtxdist[mype], 0, part);
+ *edgecut = 0;
+ return;
+ }
+
+ /******************************/
+ /* Take care of npes = 1 case */
+ /******************************/
+ if (npes == 1 && inparts > 1) {
+ moptions[0] = 0;
+ nvtxs = vtxdist[1];
+
+ if (incon == 1) {
+ METIS_WPartGraphKway(&nvtxs, xadj, adjncy, vwgt, adjwgt, &iwgtflag, &inumflag,
+ &inparts, itpwgts, moptions, edgecut, part);
+ }
+ else {
+ /* ADD: this is because METIS does not support tpwgts for all constraints */
+ mytpwgts = fmalloc(inparts, "mytpwgts");
+ for (i=0; i<inparts; i++)
+ mytpwgts[i] = itpwgts[i*incon];
+
+ moptions[7] = -1;
+ METIS_mCPartGraphRecursive2(&nvtxs, &incon, xadj, adjncy, vwgt, adjwgt, &iwgtflag,
+ &inumflag, &inparts, mytpwgts, moptions, edgecut, part);
+
+ free(mytpwgts);
+ }
+
+ return;
+ }
+
+
+ if (inumflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 1);
+
+ /*****************************/
+ /* Set up control structures */
+ /*****************************/
+ if (ioptions[0] == 1) {
+ dbglvl = ioptions[PMV3_OPTION_DBGLVL];
+ seed = ioptions[PMV3_OPTION_SEED];
+ }
+ else {
+ dbglvl = GLOBAL_DBGLVL;
+ seed = GLOBAL_SEED;
+ }
+ SetUpCtrl(&ctrl, npes, dbglvl, *comm);
+ ctrl.CoarsenTo = amin(vtxdist[npes]+1, 25*incon*amax(npes, inparts));
+ ctrl.seed = (seed == 0) ? mype : seed*mype;
+ ctrl.sync = GlobalSEMax(&ctrl, seed);
+ ctrl.partType = STATIC_PARTITION;
+ ctrl.ps_relation = -1;
+ ctrl.tpwgts = itpwgts;
+ scopy(incon, iubvec, ctrl.ubvec);
+
+ uwgtflag = iwgtflag|2;
+ uvwgt = idxsmalloc(vtxdist[mype+1]-vtxdist[mype], 1, "uvwgt");
+ graph = Moc_SetUpGraph(&ctrl, 1, vtxdist, xadj, uvwgt, adjncy, adjwgt, &uwgtflag);
+ free(graph->nvwgt); graph->nvwgt = NULL;
+
+ PreAllocateMemory(&ctrl, graph, &wspace);
+
+ /*=================================================================
+ * Compute the initial npes-way partitioning geometric partitioning
+ =================================================================*/
+ IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
+
+ Coordinate_Partition(&ctrl, graph, *ndims, xyz, 1, &wspace);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl));
+
+ /*=================================================================
+ * Move the graph according to the partitioning
+ =================================================================*/
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.MoveTmr));
+
+ free(uvwgt);
+ graph->vwgt = ((iwgtflag&2) != 0) ? vwgt : idxsmalloc(graph->nvtxs*incon, 1, "vwgt");
+ graph->ncon = incon;
+ j = ctrl.nparts;
+ ctrl.nparts = ctrl.npes;
+ mgraph = Moc_MoveGraph(&ctrl, graph, &wspace);
+ ctrl.nparts = j;
+
+ /**********************************************************/
+ /* Do the same functionality as Moc_SetUpGraph for mgraph */
+ /**********************************************************/
+ /* compute tvwgts */
+ for (j=0; j<incon; j++)
+ ltvwgts[j] = 0;
+
+ for (i=0; i<graph->nvtxs; i++)
+ for (j=0; j<incon; j++)
+ ltvwgts[j] += mgraph->vwgt[i*incon+j];
+
+ for (j=0; j<incon; j++)
+ ctrl.tvwgts[j] = GlobalSESum(&ctrl, ltvwgts[j]);
+
+ /* check for zero wgt constraints */
+ for (i=0; i<incon; i++) {
+ /* ADD: take care of the case in which tvwgts is zero */
+ if (ctrl.tvwgts[i] == 0) {
+ if (ctrl.mype == 0) printf("ERROR: sum weight for constraint %d is zero\n", i);
+ MPI_Finalize();
+ exit(-1);
+ }
+ }
+
+ /* compute nvwgt */
+ mgraph->nvwgt = fmalloc(mgraph->nvtxs*incon, "mgraph->nvwgt");
+ for (i=0; i<mgraph->nvtxs; i++)
+ for (j=0; j<incon; j++)
+ mgraph->nvwgt[i*incon+j] = (float)(mgraph->vwgt[i*incon+j]) / (float)(ctrl.tvwgts[j]);
+
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.MoveTmr));
+
+ if (ctrl.dbglvl&DBG_INFO) {
+ cut = 0;
+ for (i=0; i<graph->nvtxs; i++)
+ for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++)
+ if (graph->where[i] != graph->where[graph->adjncy[j]])
+ cut += graph->adjwgt[j];
+ gcut = GlobalSESum(&ctrl, cut)/2;
+ maxnvtxs = GlobalSEMax(&ctrl, mgraph->nvtxs);
+ balance = (float)(maxnvtxs)/((float)(graph->gnvtxs)/(float)(npes));
+ rprintf(&ctrl, "XYZ Cut: %6d \tBalance: %6.3f [%d %d %d]\n",
+ gcut, balance, maxnvtxs, graph->gnvtxs, npes);
+
+ }
+
+ /*=================================================================
+ * Set up the newly moved graph
+ =================================================================*/
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
+
+ ctrl.nparts = inparts;
+ FreeWSpace(&wspace);
+ PreAllocateMemory(&ctrl, mgraph, &wspace);
+
+ /*=======================================================
+ * Now compute the partition of the moved graph
+ =======================================================*/
+ if (vtxdist[npes] < SMALLGRAPH || vtxdist[npes] < npes*20 || GlobalSESum(&ctrl, mgraph->nedges) == 0) {
+ IFSET(ctrl.dbglvl, DBG_INFO, rprintf(&ctrl, "Partitioning a graph of size %d serially\n", vtxdist[npes]));
+ PartitionSmallGraph(&ctrl, mgraph, &wspace);
+ }
+ else {
+ Moc_Global_Partition(&ctrl, mgraph, &wspace);
+ }
+ ParallelReMapGraph(&ctrl, mgraph, &wspace);
+
+ /* Invert the ordering back to the original graph */
+ ctrl.nparts = npes;
+ ProjectInfoBack(&ctrl, graph, part, mgraph->where, &wspace);
+
+ *edgecut = mgraph->mincut;
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
+
+ /*******************/
+ /* Print out stats */
+ /*******************/
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+
+ if (ctrl.dbglvl&DBG_INFO) {
+ rprintf(&ctrl, "Final %d-way CUT: %6d \tBalance: ", inparts, mgraph->mincut);
+ avg = 0.0;
+ for (h=0; h<incon; h++) {
+ maximb = 0.0;
+ for (i=0; i<inparts; i++)
+ maximb = amax(maximb, mgraph->gnpwgts[i*incon+h]/itpwgts[i*incon+h]);
+ avg += maximb;
+ rprintf(&ctrl, "%.3f ", maximb);
+ }
+ rprintf(&ctrl, " avg: %.3f\n", avg/(float)incon);
+ }
+
+ GKfree((void **)&itpwgts, LTERM);
+ FreeGraph(mgraph);
+ FreeInitialGraphAndRemap(graph, iwgtflag);
+ FreeWSpace(&wspace);
+ FreeCtrl(&ctrl);
+
+ if (inumflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 0);
+
+}
+
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel ordering algorithm.
+* This function assumes that the graph is already nice partitioned among the
+* processors and then proceeds to perform recursive bisection.
+************************************************************************************/
+void ParMETIS_V3_PartGeom(idxtype *vtxdist, int *ndims, float *xyz, idxtype *part, MPI_Comm *comm)
+{
+ int i, npes, mype, nvtxs, firstvtx, dbglvl;
+ idxtype *xadj, *adjncy;
+ CtrlType ctrl;
+ WorkSpaceType wspace;
+ GraphType *graph;
+ int zeroflg = 0;
+
+ MPI_Comm_size(*comm, &npes);
+ MPI_Comm_rank(*comm, &mype);
+
+ if (npes == 1) {
+ idxset(vtxdist[mype+1]-vtxdist[mype], 0, part);
+ return;
+ }
+
+ /* Setup a fake graph to allow the rest of the code to work unchanged */
+ dbglvl = 0;
+
+ nvtxs = vtxdist[mype+1]-vtxdist[mype];
+ firstvtx = vtxdist[mype];
+ xadj = idxmalloc(nvtxs+1, "ParMETIS_PartGeom: xadj");
+ adjncy = idxmalloc(nvtxs, "ParMETIS_PartGeom: adjncy");
+ for (i=0; i<nvtxs; i++) {
+ xadj[i] = i;
+ adjncy[i] = firstvtx + (i+1)%nvtxs;
+ }
+ xadj[nvtxs] = nvtxs;
+
+ /* Proceed with the rest of the code */
+ SetUpCtrl(&ctrl, npes, dbglvl, *comm);
+ ctrl.seed = mype;
+ ctrl.CoarsenTo = amin(vtxdist[npes]+1, 25*npes);
+
+ graph = Moc_SetUpGraph(&ctrl, 1, vtxdist, xadj, NULL, adjncy, NULL, &zeroflg);
+
+ PreAllocateMemory(&ctrl, graph, &wspace);
+
+ /*=======================================================
+ * Compute the initial geometric partitioning
+ =======================================================*/
+ IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
+
+ Coordinate_Partition(&ctrl, graph, *ndims, xyz, 0, &wspace);
+
+ idxcopy(graph->nvtxs, graph->where, part);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl));
+
+ FreeInitialGraphAndRemap(graph, 0);
+ FreeWSpace(&wspace);
+ FreeCtrl(&ctrl);
+
+ GKfree((void **)&xadj, (void **)&adjncy, LTERM);
+}
+
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/grsetup.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/grsetup.c
new file mode 100644
index 0000000..7f10a8f
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/grsetup.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mgrsetup.c
+ *
+ * This file contain various graph setting up routines
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: grsetup.c,v 1.7 2003/07/23 00:54:55 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+/*************************************************************************
+* This function setsup the CtrlType structure
+**************************************************************************/
+GraphType *Moc_SetUpGraph(CtrlType *ctrl, int ncon, idxtype *vtxdist, idxtype *xadj,
+ idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt, int *wgtflag)
+{
+ int i, j;
+ GraphType *graph;
+ int ltvwgts[MAXNCON];
+
+ graph = CreateGraph();
+ graph->level = 0;
+ graph->gnvtxs = vtxdist[ctrl->npes];
+ graph->nvtxs = vtxdist[ctrl->mype+1]-vtxdist[ctrl->mype];
+ graph->ncon = ncon;
+ graph->nedges = xadj[graph->nvtxs];
+ graph->xadj = xadj;
+ graph->vwgt = vwgt;
+ graph->adjncy = adjncy;
+ graph->adjwgt = adjwgt;
+ graph->vtxdist = vtxdist;
+
+
+ if (((*wgtflag)&2) == 0)
+ graph->vwgt = idxsmalloc(graph->nvtxs*ncon, 1, "Par_KMetis: vwgt");
+
+ if (((*wgtflag)&1) == 0)
+ graph->adjwgt = idxsmalloc(graph->nedges, 1, "Par_KMetis: adjwgt");
+
+ /* compute tvwgts */
+ for (j=0; j<ncon; j++)
+ ltvwgts[j] = 0;
+
+ for (i=0; i<graph->nvtxs; i++)
+ for (j=0; j<ncon; j++)
+ ltvwgts[j] += graph->vwgt[i*ncon+j];
+
+ for (j=0; j<ncon; j++)
+ ctrl->tvwgts[j] = GlobalSESum(ctrl, ltvwgts[j]);
+
+ /* check for zero wgt constraints */
+ for (i=0; i<ncon; i++) {
+ /* ADD: take care of the case in which tvwgts is zero */
+ if (ctrl->tvwgts[i] == 0) {
+ rprintf(ctrl, "ERROR: sum weight for constraint %d is zero\n", i);
+ MPI_Finalize();
+ exit(-1);
+ }
+ }
+
+ /* compute nvwgts */
+ graph->nvwgt = fmalloc(graph->nvtxs*ncon, "graph->nvwgt");
+ for (i=0; i<graph->nvtxs; i++) {
+ for (j=0; j<ncon; j++)
+ graph->nvwgt[i*ncon+j] = (float)(graph->vwgt[i*ncon+j]) / (float)(ctrl->tvwgts[j]);
+ }
+
+ srand(ctrl->seed);
+
+ return graph;
+}
+
+
+/*************************************************************************
+* This function setsup the CtrlType structure
+**************************************************************************/
+void SetUpCtrl(CtrlType *ctrl, int nparts, int dbglvl, MPI_Comm comm)
+{
+
+ MPI_Comm_dup(comm, &(ctrl->gcomm));
+ MPI_Comm_rank(ctrl->gcomm, &ctrl->mype);
+ MPI_Comm_size(ctrl->gcomm, &ctrl->npes);
+
+ ctrl->dbglvl = dbglvl;
+ ctrl->nparts = nparts; /* Set the # of partitions is de-coupled from the # of domains */
+ ctrl->comm = ctrl->gcomm;
+ ctrl->xyztype = XYZ_SPFILL;
+
+ srand(ctrl->mype);
+}
+
+
+/*************************************************************************
+* This function changes the numbering from 1 to 0 or 0 to 1
+**************************************************************************/
+void ChangeNumbering(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *part, int npes, int mype, int from)
+{
+ int i, nvtxs, nedges;
+
+ if (from == 1) { /* Change it from 1 to 0 */
+ for (i=0; i<npes+1; i++)
+ vtxdist[i]--;
+
+ nvtxs = vtxdist[mype+1]-vtxdist[mype];
+ for (i=0; i<nvtxs+1; i++)
+ xadj[i]--;
+
+ nedges = xadj[nvtxs];
+ for (i=0; i<nedges; i++)
+ adjncy[i]--;
+ }
+ else { /* Change it from 0 to 1 */
+ nvtxs = vtxdist[mype+1]-vtxdist[mype];
+ nedges = xadj[nvtxs];
+
+ for (i=0; i<npes+1; i++)
+ vtxdist[i]++;
+
+ for (i=0; i<nvtxs+1; i++)
+ xadj[i]++;
+
+ for (i=0; i<nedges; i++)
+ adjncy[i]++;
+
+ for (i=0; i<nvtxs; i++)
+ part[i]++;
+
+ }
+}
+
+
+/*************************************************************************
+* This function changes the numbering from 1 to 0 or 0 to 1
+**************************************************************************/
+void ChangeNumberingMesh(idxtype *elmdist, idxtype *elements, idxtype *xadj,
+ idxtype *adjncy, idxtype *part, int npes, int mype,
+ int elmntlen, int from)
+{
+ int i, nelms, nedges;
+
+ if (from == 1) { /* Change it from 1 to 0 */
+ for (i=0; i<npes+1; i++)
+ elmdist[i]--;
+
+ for (i=0; i<elmntlen; i++)
+ elements[i]--;
+ }
+ else { /* Change it from 0 to 1 */
+ nelms = elmdist[mype+1]-elmdist[mype];
+ nedges = xadj[nelms];
+
+ for (i=0; i<npes+1; i++)
+ elmdist[i]++;
+
+ for (i=0; i<elmntlen; i++)
+ elements[i]++;
+
+ for (i=0; i<nelms+1; i++)
+ xadj[i]++;
+
+ for (i=0; i<nedges; i++)
+ adjncy[i]++;
+
+ if (part != NULL)
+ for (i=0; i<nelms; i++)
+ part[i]++;
+ }
+}
+
+
+/*************************************************************************
+* This function changes the numbering from 1 to 0 or 0 to 1
+**************************************************************************/
+void ChangeNumberingMesh2(idxtype *elmdist, idxtype *eptr, idxtype *eind,
+ idxtype *xadj, idxtype *adjncy, idxtype *part,
+ int npes, int mype, int from)
+{
+ int i, nelms;
+
+ nelms = elmdist[mype+1]-elmdist[mype];
+
+ if (from == 1) { /* Change it from 1 to 0 */
+ for (i=0; i<npes+1; i++)
+ elmdist[i]--;
+
+ for (i=0; i<nelms+1; i++)
+ eptr[i]--;
+
+ for (i=0; i<eptr[nelms]; i++)
+ eind[i]--;
+ }
+ else { /* Change it from 0 to 1 */
+ for (i=0; i<npes+1; i++)
+ elmdist[i]++;
+
+ for (i=0; i<nelms+1; i++)
+ eptr[i]++;
+
+ for (i=0; i<eptr[nelms]; i++)
+ eind[i]++;
+
+ for (i=0; i<nelms+1; i++)
+ xadj[i]++;
+
+ for (i=0; i<xadj[nelms]; i++)
+ adjncy[i]++;
+
+ if (part != NULL)
+ for (i=0; i<nelms; i++)
+ part[i]++;
+ }
+}
+
+
+
+
+/*************************************************************************
+* This function randomly permutes the locally stored adjacency lists
+**************************************************************************/
+void GraphRandomPermute(GraphType *graph)
+{
+ int i, j, k, tmp;
+
+ for (i=0; i<graph->nvtxs; i++) {
+ for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) {
+ k = graph->xadj[i] + RandomInRange(graph->xadj[i+1]-graph->xadj[i]);
+ SWAP(graph->adjncy[j], graph->adjncy[k], tmp);
+ SWAP(graph->adjwgt[j], graph->adjwgt[k], tmp);
+ }
+ }
+}
+
+
+/*************************************************************************
+* This function computes movement statistics for adaptive refinement
+* schemes
+**************************************************************************/
+void ComputeMoveStatistics(CtrlType *ctrl, GraphType *graph, int *nmoved, int *maxin, int *maxout)
+{
+ int i, j, nvtxs;
+ idxtype *vwgt, *where;
+ idxtype *lpvtxs, *gpvtxs;
+
+ nvtxs = graph->nvtxs;
+ vwgt = graph->vwgt;
+ where = graph->where;
+
+ lpvtxs = idxsmalloc(ctrl->nparts, 0, "ComputeMoveStatistics: lpvtxs");
+ gpvtxs = idxsmalloc(ctrl->nparts, 0, "ComputeMoveStatistics: gpvtxs");
+
+ for (j=i=0; i<nvtxs; i++) {
+ lpvtxs[where[i]]++;
+ if (where[i] != ctrl->mype)
+ j++;
+ }
+
+ /* PrintVector(ctrl, ctrl->npes, 0, lpvtxs, "Lpvtxs: "); */
+
+ MPI_Allreduce((void *)lpvtxs, (void *)gpvtxs, ctrl->nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+
+ *nmoved = GlobalSESum(ctrl, j);
+ *maxout = GlobalSEMax(ctrl, j);
+ *maxin = GlobalSEMax(ctrl, gpvtxs[ctrl->mype]-(nvtxs-j));
+
+ GKfree((void **)&lpvtxs, (void **)&gpvtxs, LTERM);
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/iidxsort.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/iidxsort.c
new file mode 100644
index 0000000..869748c
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/iidxsort.c
@@ -0,0 +1,152 @@
+#include <parmetislib.h>
+
+
+/* Byte-wise swap two items of size SIZE. */
+#define QSSWAP(a, b, stmp) do { stmp = (a); (a) = (b); (b) = stmp; } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+ This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 20
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct {
+ idxtype *lo;
+ idxtype *hi;
+} stack_node;
+
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+#define STACK_SIZE (8 * sizeof(unsigned long int))
+#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
+#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
+#define STACK_NOT_EMPTY (stack < top)
+
+
+void iidxsort(int total_elems, idxtype *pbase)
+{
+ idxtype pivot, stmp;
+
+ if (total_elems == 0)
+ /* Avoid lossage with unsigned arithmetic below. */
+ return;
+
+ if (total_elems > MAX_THRESH) {
+ idxtype *lo = pbase;
+ idxtype *hi = &lo[total_elems - 1];
+ stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
+ stack_node *top = stack + 1;
+
+ while (STACK_NOT_EMPTY) {
+ idxtype *left_ptr;
+ idxtype *right_ptr;
+ idxtype *mid = lo + ((hi - lo) >> 1);
+
+
+ if (*mid < *lo)
+ QSSWAP(*mid, *lo, stmp);
+ if (*hi < *mid)
+ QSSWAP(*mid, *hi, stmp);
+ else
+ goto jump_over;
+ if (*mid < *lo)
+ QSSWAP(*mid, *lo, stmp);
+
+jump_over:;
+ pivot = *mid;
+ left_ptr = lo + 1;
+ right_ptr = hi - 1;
+
+ /* Here's the famous ``collapse the walls'' section of quicksort.
+ Gotta like those tight inner loops! They are the main reason
+ that this algorithm runs much faster than others. */
+ do {
+ while (*left_ptr < pivot)
+ left_ptr++;
+
+ while (pivot < *right_ptr)
+ right_ptr--;
+
+ if (left_ptr < right_ptr) {
+ QSSWAP (*left_ptr, *right_ptr, stmp);
+ left_ptr++;
+ right_ptr--;
+ }
+ else if (left_ptr == right_ptr) {
+ left_ptr++;
+ right_ptr--;
+ break;
+ }
+ } while (left_ptr <= right_ptr);
+
+ /* Set up pointers for next iteration. First determine whether
+ left and right partitions are below the threshold size. If so,
+ ignore one or both. Otherwise, push the larger partition's
+ bounds on the stack and continue sorting the smaller one. */
+
+ if ((size_t) (right_ptr - lo) <= MAX_THRESH) {
+ if ((size_t) (hi - left_ptr) <= MAX_THRESH)
+ /* Ignore both small partitions. */
+ POP (lo, hi);
+ else
+ /* Ignore small left partition. */
+ lo = left_ptr;
+ }
+ else if ((size_t) (hi - left_ptr) <= MAX_THRESH)
+ /* Ignore small right partition. */
+ hi = right_ptr;
+ else if ((right_ptr - lo) > (hi - left_ptr)) {
+ /* Push larger left partition indices. */
+ PUSH (lo, right_ptr);
+ lo = left_ptr;
+ }
+ else {
+ /* Push larger right partition indices. */
+ PUSH (left_ptr, hi);
+ hi = right_ptr;
+ }
+ }
+ }
+
+ /* Once the BASE_PTR array is partially sorted by quicksort the rest
+ is completely sorted using insertion sort, since this is efficient
+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+ of the array to sort, and END_PTR points at the very last element in
+ the array (*not* one beyond it!). */
+
+ {
+ idxtype *end_ptr = &pbase[total_elems - 1];
+ idxtype *tmp_ptr = pbase;
+ idxtype *thresh = (end_ptr < pbase + MAX_THRESH ? end_ptr : pbase + MAX_THRESH);
+ register idxtype *run_ptr;
+
+ /* Find smallest element in first threshold and place it at the
+ array's beginning. This is the smallest array element,
+ and the operation speeds up insertion sort's inner loop. */
+
+
+ for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++)
+ if (*run_ptr < *tmp_ptr)
+ tmp_ptr = run_ptr;
+
+ if (tmp_ptr != pbase)
+ QSSWAP(*tmp_ptr, *pbase, stmp);
+
+ /* Insertion sort, running from left-hand-side up to right-hand-side. */
+ run_ptr = pbase + 1;
+ while (++run_ptr <= end_ptr) {
+ tmp_ptr = run_ptr - 1;
+ while (*run_ptr < *tmp_ptr)
+ tmp_ptr--;
+
+ tmp_ptr++;
+ if (tmp_ptr != run_ptr) {
+ idxtype elmnt = *run_ptr;
+ idxtype *mptr;
+
+ for (mptr=run_ptr; mptr>tmp_ptr; mptr--)
+ *mptr = *(mptr-1);
+ *mptr = elmnt;
+ }
+ }
+ }
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/iintsort.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/iintsort.c
new file mode 100644
index 0000000..fb0e840
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/iintsort.c
@@ -0,0 +1,157 @@
+#include <parmetislib.h>
+
+
+/* Byte-wise swap two items of size SIZE. */
+#define QSSWAP(a, b, stmp) do { stmp = (a); (a) = (b); (b) = stmp; } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+ This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 20
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct {
+ int *lo;
+ int *hi;
+} stack_node;
+
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+#define STACK_SIZE (8 * sizeof(unsigned long int))
+#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
+#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
+#define STACK_NOT_EMPTY (stack < top)
+
+
+void iintsort(int total_elems, int *pbase)
+{
+ int pivot, stmp;
+
+ if (total_elems == 0)
+ /* Avoid lossage with unsigned arithmetic below. */
+ return;
+
+ if (total_elems > MAX_THRESH) {
+ int *lo = pbase;
+ int *hi = &lo[total_elems - 1];
+ stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
+ stack_node *top = stack + 1;
+
+ while (STACK_NOT_EMPTY) {
+ int *left_ptr;
+ int *right_ptr;
+
+ /* Select median value from among LO, MID, and HI. Rearrange
+ LO and HI so the three values are sorted. This lowers the
+ probability of picking a pathological pivot value and
+ skips a comparison for both the LEFT_PTR and RIGHT_PTR. */
+
+ int *mid = lo + ((hi - lo) >> 1);
+
+ if (*mid < *lo)
+ QSSWAP(*mid, *lo, stmp);
+ if (*hi < *mid)
+ QSSWAP(*mid, *hi, stmp);
+ else
+ goto jump_over;
+ if (*mid < *lo)
+ QSSWAP(*mid, *lo, stmp);
+
+jump_over:;
+ pivot = *mid;
+ left_ptr = lo + 1;
+ right_ptr = hi - 1;
+
+ /* Here's the famous ``collapse the walls'' section of quicksort.
+ Gotta like those tight inner loops! They are the main reason
+ that this algorithm runs much faster than others. */
+ do {
+ while (*left_ptr < pivot)
+ left_ptr++;
+
+ while (pivot < *right_ptr)
+ right_ptr--;
+
+ if (left_ptr < right_ptr) {
+ QSSWAP (*left_ptr, *right_ptr, stmp);
+ left_ptr++;
+ right_ptr--;
+ }
+ else if (left_ptr == right_ptr) {
+ left_ptr++;
+ right_ptr--;
+ break;
+ }
+ } while (left_ptr <= right_ptr);
+
+ /* Set up pointers for next iteration. First determine whether
+ left and right partitions are below the threshold size. If so,
+ ignore one or both. Otherwise, push the larger partition's
+ bounds on the stack and continue sorting the smaller one. */
+
+ if ((size_t) (right_ptr - lo) <= MAX_THRESH) {
+ if ((size_t) (hi - left_ptr) <= MAX_THRESH)
+ /* Ignore both small partitions. */
+ POP (lo, hi);
+ else
+ /* Ignore small left partition. */
+ lo = left_ptr;
+ }
+ else if ((size_t) (hi - left_ptr) <= MAX_THRESH)
+ /* Ignore small right partition. */
+ hi = right_ptr;
+ else if ((right_ptr - lo) > (hi - left_ptr)) {
+ /* Push larger left partition indices. */
+ PUSH (lo, right_ptr);
+ lo = left_ptr;
+ }
+ else {
+ /* Push larger right partition indices. */
+ PUSH (left_ptr, hi);
+ hi = right_ptr;
+ }
+ }
+ }
+
+ /* Once the BASE_PTR array is partially sorted by quicksort the rest
+ is completely sorted using insertion sort, since this is efficient
+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+ of the array to sort, and END_PTR points at the very last element in
+ the array (*not* one beyond it!). */
+
+ {
+ int *end_ptr = &pbase[total_elems - 1];
+ int *tmp_ptr = pbase;
+ int *thresh = (end_ptr < pbase + MAX_THRESH ? end_ptr : pbase + MAX_THRESH);
+ register int *run_ptr;
+
+ /* Find smallest element in first threshold and place it at the
+ array's beginning. This is the smallest array element,
+ and the operation speeds up insertion sort's inner loop. */
+
+
+ for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++)
+ if (*run_ptr < *tmp_ptr)
+ tmp_ptr = run_ptr;
+
+ if (tmp_ptr != pbase)
+ QSSWAP(*tmp_ptr, *pbase, stmp);
+
+ /* Insertion sort, running from left-hand-side up to right-hand-side. */
+ run_ptr = pbase + 1;
+ while (++run_ptr <= end_ptr) {
+ tmp_ptr = run_ptr - 1;
+ while (*run_ptr < *tmp_ptr)
+ tmp_ptr--;
+
+ tmp_ptr++;
+ if (tmp_ptr != run_ptr) {
+ int elmnt = *run_ptr;
+ int *mptr;
+
+ for (mptr=run_ptr; mptr>tmp_ptr; mptr--)
+ *mptr = *(mptr-1);
+ *mptr = elmnt;
+ }
+ }
+ }
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ikeysort.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ikeysort.c
new file mode 100644
index 0000000..14b4241
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ikeysort.c
@@ -0,0 +1,151 @@
+#include <parmetislib.h>
+
+
+/* Byte-wise swap two items of size SIZE. */
+#define QSSWAP(a, b, stmp) do { stmp = (a); (a) = (b); (b) = stmp; } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+ This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 20
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct {
+ KeyValueType *lo;
+ KeyValueType *hi;
+} stack_node;
+
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+#define STACK_SIZE (8 * sizeof(unsigned long int))
+#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
+#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
+#define STACK_NOT_EMPTY (stack < top)
+
+
+void ikeysort(int total_elems, KeyValueType *pbase)
+{
+ KeyValueType pivot, stmp;
+
+ if (total_elems == 0)
+ /* Avoid lossage with unsigned arithmetic below. */
+ return;
+
+ if (total_elems > MAX_THRESH) {
+ KeyValueType *lo = pbase;
+ KeyValueType *hi = &lo[total_elems - 1];
+ stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
+ stack_node *top = stack + 1;
+
+ while (STACK_NOT_EMPTY) {
+ KeyValueType *left_ptr;
+ KeyValueType *right_ptr;
+ KeyValueType *mid = lo + ((hi - lo) >> 1);
+
+ if (mid->key < lo->key)
+ QSSWAP(*mid, *lo, stmp);
+ if (hi->key < mid->key)
+ QSSWAP(*mid, *hi, stmp);
+ else
+ goto jump_over;
+ if (mid->key < lo->key)
+ QSSWAP(*mid, *lo, stmp);
+
+jump_over:;
+ pivot = *mid;
+ left_ptr = lo + 1;
+ right_ptr = hi - 1;
+
+ /* Here's the famous ``collapse the walls'' section of quicksort.
+ Gotta like those tight inner loops! They are the main reason
+ that this algorithm runs much faster than others. */
+ do {
+ while (left_ptr->key < pivot.key)
+ left_ptr++;
+
+ while (pivot.key < right_ptr->key)
+ right_ptr--;
+
+ if (left_ptr < right_ptr) {
+ QSSWAP (*left_ptr, *right_ptr, stmp);
+ left_ptr++;
+ right_ptr--;
+ }
+ else if (left_ptr == right_ptr) {
+ left_ptr++;
+ right_ptr--;
+ break;
+ }
+ } while (left_ptr <= right_ptr);
+
+ /* Set up pointers for next iteration. First determine whether
+ left and right partitions are below the threshold size. If so,
+ ignore one or both. Otherwise, push the larger partition's
+ bounds on the stack and continue sorting the smaller one. */
+
+ if ((size_t) (right_ptr - lo) <= MAX_THRESH) {
+ if ((size_t) (hi - left_ptr) <= MAX_THRESH)
+ /* Ignore both small partitions. */
+ POP (lo, hi);
+ else
+ /* Ignore small left partition. */
+ lo = left_ptr;
+ }
+ else if ((size_t) (hi - left_ptr) <= MAX_THRESH)
+ /* Ignore small right partition. */
+ hi = right_ptr;
+ else if ((right_ptr - lo) > (hi - left_ptr)) {
+ /* Push larger left partition indices. */
+ PUSH (lo, right_ptr);
+ lo = left_ptr;
+ }
+ else {
+ /* Push larger right partition indices. */
+ PUSH (left_ptr, hi);
+ hi = right_ptr;
+ }
+ }
+ }
+
+ /* Once the BASE_PTR array is partially sorted by quicksort the rest
+ is completely sorted using insertion sort, since this is efficient
+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+ of the array to sort, and END_PTR points at the very last element in
+ the array (*not* one beyond it!). */
+
+ {
+ KeyValueType *end_ptr = &pbase[total_elems - 1];
+ KeyValueType *tmp_ptr = pbase;
+ KeyValueType *thresh = (end_ptr < pbase + MAX_THRESH ? end_ptr : pbase + MAX_THRESH);
+ register KeyValueType *run_ptr;
+
+ /* Find smallest element in first threshold and place it at the
+ array's beginning. This is the smallest array element,
+ and the operation speeds up insertion sort's inner loop. */
+
+ for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++)
+ if (run_ptr->key < tmp_ptr->key)
+ tmp_ptr = run_ptr;
+
+ if (tmp_ptr != pbase)
+ QSSWAP(*tmp_ptr, *pbase, stmp);
+
+ /* Insertion sort, running from left-hand-side up to right-hand-side. */
+ run_ptr = pbase + 1;
+ while (++run_ptr <= end_ptr) {
+ tmp_ptr = run_ptr - 1;
+ while (run_ptr->key < tmp_ptr->key)
+ tmp_ptr--;
+
+ tmp_ptr++;
+ if (tmp_ptr != run_ptr) {
+ KeyValueType elmnt = *run_ptr;
+ KeyValueType *mptr;
+
+ for (mptr=run_ptr; mptr>tmp_ptr; mptr--)
+ *mptr = *(mptr-1);
+ *mptr = elmnt;
+ }
+ }
+ }
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ikeyvalsort.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ikeyvalsort.c
new file mode 100644
index 0000000..59dce52
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ikeyvalsort.c
@@ -0,0 +1,151 @@
+#include <parmetislib.h>
+
+
+/* Byte-wise swap two items of size SIZE. */
+#define QSSWAP(a, b, stmp) do { stmp = (a); (a) = (b); (b) = stmp; } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+ This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 20
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct {
+ KeyValueType *lo;
+ KeyValueType *hi;
+} stack_node;
+
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+#define STACK_SIZE (8 * sizeof(unsigned long int))
+#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
+#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
+#define STACK_NOT_EMPTY (stack < top)
+
+
+void ikeyvalsort(int total_elems, KeyValueType *pbase)
+{
+ KeyValueType pivot, stmp;
+
+ if (total_elems == 0)
+ /* Avoid lossage with unsigned arithmetic below. */
+ return;
+
+ if (total_elems > MAX_THRESH) {
+ KeyValueType *lo = pbase;
+ KeyValueType *hi = &lo[total_elems - 1];
+ stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
+ stack_node *top = stack + 1;
+
+ while (STACK_NOT_EMPTY) {
+ KeyValueType *left_ptr;
+ KeyValueType *right_ptr;
+ KeyValueType *mid = lo + ((hi - lo) >> 1);
+
+ if (mid->key < lo->key || (mid->key == lo->key && mid->val < lo->val))
+ QSSWAP(*mid, *lo, stmp);
+ if (hi->key < mid->key || (hi->key == mid->key && hi->val < mid->val))
+ QSSWAP(*mid, *hi, stmp);
+ else
+ goto jump_over;
+ if (mid->key < lo->key || (mid->key == lo->key && mid->val < lo->val))
+ QSSWAP(*mid, *lo, stmp);
+
+jump_over:;
+ pivot = *mid;
+ left_ptr = lo + 1;
+ right_ptr = hi - 1;
+
+ /* Here's the famous ``collapse the walls'' section of quicksort.
+ Gotta like those tight inner loops! They are the main reason
+ that this algorithm runs much faster than others. */
+ do {
+ while (left_ptr->key < pivot.key || (left_ptr->key == pivot.key && left_ptr->val < pivot.val))
+ left_ptr++;
+
+ while (pivot.key < right_ptr->key || (pivot.key == right_ptr->key && pivot.val < right_ptr->val))
+ right_ptr--;
+
+ if (left_ptr < right_ptr) {
+ QSSWAP (*left_ptr, *right_ptr, stmp);
+ left_ptr++;
+ right_ptr--;
+ }
+ else if (left_ptr == right_ptr) {
+ left_ptr++;
+ right_ptr--;
+ break;
+ }
+ } while (left_ptr <= right_ptr);
+
+ /* Set up pointers for next iteration. First determine whether
+ left and right partitions are below the threshold size. If so,
+ ignore one or both. Otherwise, push the larger partition's
+ bounds on the stack and continue sorting the smaller one. */
+
+ if ((size_t) (right_ptr - lo) <= MAX_THRESH) {
+ if ((size_t) (hi - left_ptr) <= MAX_THRESH)
+ /* Ignore both small partitions. */
+ POP (lo, hi);
+ else
+ /* Ignore small left partition. */
+ lo = left_ptr;
+ }
+ else if ((size_t) (hi - left_ptr) <= MAX_THRESH)
+ /* Ignore small right partition. */
+ hi = right_ptr;
+ else if ((right_ptr - lo) > (hi - left_ptr)) {
+ /* Push larger left partition indices. */
+ PUSH (lo, right_ptr);
+ lo = left_ptr;
+ }
+ else {
+ /* Push larger right partition indices. */
+ PUSH (left_ptr, hi);
+ hi = right_ptr;
+ }
+ }
+ }
+
+ /* Once the BASE_PTR array is partially sorted by quicksort the rest
+ is completely sorted using insertion sort, since this is efficient
+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+ of the array to sort, and END_PTR points at the very last element in
+ the array (*not* one beyond it!). */
+
+ {
+ KeyValueType *end_ptr = &pbase[total_elems - 1];
+ KeyValueType *tmp_ptr = pbase;
+ KeyValueType *thresh = (end_ptr < pbase + MAX_THRESH ? end_ptr : pbase + MAX_THRESH);
+ register KeyValueType *run_ptr;
+
+ /* Find smallest element in first threshold and place it at the
+ array's beginning. This is the smallest array element,
+ and the operation speeds up insertion sort's inner loop. */
+
+ for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++)
+ if (run_ptr->key < tmp_ptr->key || (run_ptr->key == tmp_ptr->key && run_ptr->val < tmp_ptr->val))
+ tmp_ptr = run_ptr;
+
+ if (tmp_ptr != pbase)
+ QSSWAP(*tmp_ptr, *pbase, stmp);
+
+ /* Insertion sort, running from left-hand-side up to right-hand-side. */
+ run_ptr = pbase + 1;
+ while (++run_ptr <= end_ptr) {
+ tmp_ptr = run_ptr - 1;
+ while (run_ptr->key < tmp_ptr->key || (run_ptr->key == tmp_ptr->key && run_ptr->val < tmp_ptr->val))
+ tmp_ptr--;
+
+ tmp_ptr++;
+ if (tmp_ptr != run_ptr) {
+ KeyValueType elmnt = *run_ptr;
+ KeyValueType *mptr;
+
+ for (mptr=run_ptr; mptr>tmp_ptr; mptr--)
+ *mptr = *(mptr-1);
+ *mptr = elmnt;
+ }
+ }
+ }
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initbalance.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initbalance.c
new file mode 100644
index 0000000..9ec7a31
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initbalance.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * initbalance.c
+ *
+ * This file contains code that computes an initial partitioning
+ *
+ * Started 3/4/96
+ * George
+ *
+ * $Id: initbalance.c,v 1.4 2003/07/30 21:18:52 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function is the entry point of the initial balancing algorithm.
+* This algorithm assembles the graph to all the processors and preceeds
+* with the balancing step.
+**************************************************************************/
+void Balance_Partition(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, j, mype, npes, nvtxs, nedges, ncon;
+ idxtype *vtxdist, *xadj, *adjncy, *adjwgt, *vwgt, *vsize;
+ idxtype *part, *lwhere, *home;
+ GraphType *agraph, cgraph;
+ CtrlType myctrl;
+ int lnparts, fpart, fpe, lnpes, ngroups, srnpes, srmype;
+ int twoparts=2, numflag = 0, wgtflag = 3, moptions[10], edgecut, max_cut;
+ int sr_pe, gd_pe, sr, gd, who_wins, *rcounts, *rdispls;
+ float my_cut, my_totalv, my_cost = -1.0, my_balance = -1.0, wsum;
+ float rating, max_rating, your_cost = -1.0, your_balance = -1.0;
+ float lbvec[MAXNCON], lbsum, min_lbsum, *mytpwgts, mytpwgts2[2], buffer[2];
+ MPI_Status status;
+ MPI_Comm ipcomm, srcomm;
+ struct {
+ float cost;
+ int rank;
+ } lpecost, gpecost;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
+
+ vtxdist = graph->vtxdist;
+ agraph = Moc_AssembleAdaptiveGraph(ctrl, graph, wspace);
+ nvtxs = cgraph.nvtxs = agraph->nvtxs;
+ nedges = cgraph.nedges = agraph->nedges;
+ ncon = cgraph.ncon = agraph->ncon;
+
+ xadj = cgraph.xadj = idxmalloc(nvtxs*(5+ncon)+1+nedges*2, "U_IP: xadj");
+ vwgt = cgraph.vwgt = xadj + nvtxs+1;
+ vsize = cgraph.vsize = xadj + nvtxs*(1+ncon)+1;
+ cgraph.where = agraph->where = part = xadj + nvtxs*(2+ncon)+1;
+ lwhere = xadj + nvtxs*(3+ncon)+1;
+ home = xadj + nvtxs*(4+ncon)+1;
+ adjncy = cgraph.adjncy = xadj + nvtxs*(5+ncon)+1;
+ adjwgt = cgraph.adjwgt = xadj + nvtxs*(5+ncon)+1 + nedges;
+
+ /* ADD: this assumes that tpwgts for all constraints is the same */
+ /* ADD: this is necessary because serial metis does not support the general case */
+ mytpwgts = fsmalloc(ctrl->nparts, 0.0, "mytpwgts");
+ for (i=0; i<ctrl->nparts; i++)
+ for (j=0; j<ncon; j++)
+ mytpwgts[i] += ctrl->tpwgts[i*ncon+j];
+ for (i=0; i<ctrl->nparts; i++)
+ mytpwgts[i] /= (float)ncon;
+
+ idxcopy(nvtxs+1, agraph->xadj, xadj);
+ idxcopy(nvtxs*ncon, agraph->vwgt, vwgt);
+ idxcopy(nvtxs, agraph->vsize, vsize);
+ idxcopy(nedges, agraph->adjncy, adjncy);
+ idxcopy(nedges, agraph->adjwgt, adjwgt);
+
+ /****************************************/
+ /****************************************/
+ if (ctrl->ps_relation == DISCOUPLED) {
+ rcounts = imalloc(ctrl->npes, "rcounts");
+ rdispls = imalloc(ctrl->npes+1, "rdispls");
+
+ for (i=0; i<ctrl->npes; i++) {
+ rdispls[i] = rcounts[i] = vtxdist[i+1]-vtxdist[i];
+ }
+ MAKECSR(i, ctrl->npes, rdispls);
+
+ MPI_Allgatherv((void *)graph->home, graph->nvtxs, IDX_DATATYPE,
+ (void *)part, rcounts, rdispls, IDX_DATATYPE, ctrl->comm);
+
+ for (i=0; i<agraph->nvtxs; i++)
+ home[i] = part[i];
+
+ GKfree((void **)&rcounts, (void **)&rdispls, LTERM);
+ }
+ else {
+ for (i=0; i<ctrl->npes; i++)
+ for (j=vtxdist[i]; j<vtxdist[i+1]; j++)
+ part[j] = home[j] = i;
+ }
+
+ /* Ensure that the initial partitioning is legal */
+ for (i=0; i<agraph->nvtxs; i++) {
+ if (part[i] >= ctrl->nparts)
+ part[i] = home[i] = part[i] % ctrl->nparts;
+ if (part[i] < 0)
+ part[i] = home[i] = (-1*part[i]) % ctrl->nparts;
+ }
+ /****************************************/
+ /****************************************/
+
+ IFSET(ctrl->dbglvl, DBG_REFINEINFO, Moc_ComputeSerialBalance(ctrl, agraph, agraph->where, lbvec));
+ IFSET(ctrl->dbglvl, DBG_REFINEINFO, rprintf(ctrl, "input cut: %d, balance: ", ComputeSerialEdgeCut(agraph)));
+ for (i=0; i<agraph->ncon; i++)
+ IFSET(ctrl->dbglvl, DBG_REFINEINFO, rprintf(ctrl, "%.3f ", lbvec[i]));
+ IFSET(ctrl->dbglvl, DBG_REFINEINFO, rprintf(ctrl, "\n"));
+
+ /****************************************/
+ /* Split the processors into two groups */
+ /****************************************/
+ sr = (ctrl->mype % 2 == 0) ? 1 : 0;
+ gd = (ctrl->mype % 2 == 1) ? 1 : 0;
+
+ if (graph->ncon > MAX_NCON_FOR_DIFFUSION || ctrl->npes == 1) {
+ sr = 1;
+ gd = 0;
+ }
+
+ sr_pe = 0;
+ gd_pe = 1;
+
+ MPI_Comm_split(ctrl->gcomm, sr, 0, &ipcomm);
+ MPI_Comm_rank(ipcomm, &mype);
+ MPI_Comm_size(ipcomm, &npes);
+
+ myctrl.dbglvl = 0;
+ myctrl.mype = mype;
+ myctrl.npes = npes;
+ myctrl.comm = ipcomm;
+ myctrl.sync = ctrl->sync;
+ myctrl.seed = ctrl->seed;
+ myctrl.nparts = ctrl->nparts;
+ myctrl.ipc_factor = ctrl->ipc_factor;
+ myctrl.redist_factor = ctrl->redist_base;
+ myctrl.partType = ADAPTIVE_PARTITION;
+ myctrl.ps_relation = DISCOUPLED;
+ myctrl.tpwgts = ctrl->tpwgts;
+ icopy(ncon, ctrl->tvwgts, myctrl.tvwgts);
+ icopy(ncon, ctrl->ubvec, myctrl.ubvec);
+
+ if (sr == 1) {
+ /*******************************************/
+ /* Half of the processors do scratch-remap */
+ /*******************************************/
+ ngroups = amax(amin(RIP_SPLIT_FACTOR, npes), 1);
+ MPI_Comm_split(ipcomm, mype % ngroups, 0, &srcomm);
+ MPI_Comm_rank(srcomm, &srmype);
+ MPI_Comm_size(srcomm, &srnpes);
+
+ moptions[0] = 0;
+ moptions[7] = ctrl->sync + (mype % ngroups) + 1;
+
+ idxset(nvtxs, 0, lwhere);
+ lnparts = ctrl->nparts;
+ fpart = fpe = 0;
+ lnpes = srnpes;
+ while (lnpes > 1 && lnparts > 1) {
+ ASSERT(ctrl, agraph->nvtxs > 1);
+ /* Determine the weights of the partitions */
+ mytpwgts2[0] = ssum(lnparts/2, mytpwgts+fpart);
+ mytpwgts2[1] = 1.0-mytpwgts2[0];
+
+
+ if (agraph->ncon == 1) {
+ METIS_WPartGraphKway2(&agraph->nvtxs, agraph->xadj, agraph->adjncy, agraph->vwgt,
+ agraph->adjwgt, &wgtflag, &numflag, &twoparts, mytpwgts2, moptions, &edgecut,
+ part);
+ }
+ else {
+ METIS_mCPartGraphRecursive2(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy,
+ agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag, &twoparts, mytpwgts2,
+ moptions, &edgecut, part);
+ }
+
+ wsum = ssum(lnparts/2, mytpwgts+fpart);
+ sscale(lnparts/2, 1.0/wsum, mytpwgts+fpart);
+ sscale(lnparts-lnparts/2, 1.0/(1.0-wsum), mytpwgts+fpart+lnparts/2);
+
+ /* I'm picking the left branch */
+ if (srmype < fpe+lnpes/2) {
+ Moc_KeepPart(agraph, wspace, part, 0);
+ lnpes = lnpes/2;
+ lnparts = lnparts/2;
+ }
+ else {
+ Moc_KeepPart(agraph, wspace, part, 1);
+ fpart = fpart + lnparts/2;
+ fpe = fpe + lnpes/2;
+ lnpes = lnpes - lnpes/2;
+ lnparts = lnparts - lnparts/2;
+ }
+ }
+
+ /* In case srnpes is greater than or equal to nparts */
+ if (lnparts == 1) {
+ /* Only the first process will assign labels (for the reduction to work) */
+ if (srmype == fpe) {
+ for (i=0; i<agraph->nvtxs; i++)
+ lwhere[agraph->label[i]] = fpart;
+ }
+ }
+ /* In case srnpes is smaller than nparts */
+ else {
+ if (ncon == 1)
+ METIS_WPartGraphKway2(&agraph->nvtxs, agraph->xadj, agraph->adjncy, agraph->vwgt,
+ agraph->adjwgt, &wgtflag, &numflag, &lnparts, mytpwgts+fpart, moptions,
+ &edgecut, part);
+ else
+ METIS_mCPartGraphRecursive2(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy,
+ agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag, &lnparts, mytpwgts+fpart,
+ moptions, &edgecut, part);
+
+ for (i=0; i<agraph->nvtxs; i++)
+ lwhere[agraph->label[i]] = fpart + part[i];
+ }
+
+ MPI_Allreduce((void *)lwhere, (void *)part, nvtxs, IDX_DATATYPE, MPI_SUM, srcomm);
+
+ edgecut = ComputeSerialEdgeCut(&cgraph);
+ Moc_ComputeSerialBalance(ctrl, &cgraph, part, lbvec);
+ lbsum = ssum(ncon, lbvec);
+ MPI_Allreduce((void *)&edgecut, (void *)&max_cut, 1, MPI_INT, MPI_MAX, ipcomm);
+ MPI_Allreduce((void *)&lbsum, (void *)&min_lbsum, 1, MPI_FLOAT, MPI_MIN, ipcomm);
+ lpecost.rank = ctrl->mype;
+ lpecost.cost = lbsum;
+ if (min_lbsum < UNBALANCE_FRACTION * (float)(ncon)) {
+ if (lbsum < UNBALANCE_FRACTION * (float)(ncon))
+ lpecost.cost = (float)edgecut;
+ else
+ lpecost.cost = (float)max_cut + lbsum;
+ }
+ MPI_Allreduce((void *)&lpecost, (void *)&gpecost, 1, MPI_FLOAT_INT, MPI_MINLOC, ipcomm);
+
+ if (ctrl->mype == gpecost.rank && ctrl->mype != sr_pe) {
+ MPI_Send((void *)part, nvtxs, IDX_DATATYPE, sr_pe, 1, ctrl->comm);
+ }
+
+ if (ctrl->mype != gpecost.rank && ctrl->mype == sr_pe) {
+ MPI_Recv((void *)part, nvtxs, IDX_DATATYPE, gpecost.rank, 1, ctrl->comm, &status);
+ }
+
+ if (ctrl->mype == sr_pe) {
+ idxcopy(nvtxs, part, lwhere);
+ SerialRemap(&cgraph, ctrl->nparts, home, lwhere, part, ctrl->tpwgts);
+ }
+
+ MPI_Comm_free(&srcomm);
+ }
+ /**************************************/
+ /* The other half do global diffusion */
+ /**************************************/
+ else {
+ /******************************************************************/
+ /* The next stmt is required to balance out the sr MPI_Comm_split */
+ /******************************************************************/
+ MPI_Comm_split(ipcomm, MPI_UNDEFINED, 0, &srcomm);
+
+ if (ncon == 1) {
+ rating = WavefrontDiffusion(&myctrl, agraph, home);
+ Moc_ComputeSerialBalance(ctrl, &cgraph, part, lbvec);
+ lbsum = ssum(ncon, lbvec);
+
+ /* Determine which PE computed the best partitioning */
+ MPI_Allreduce((void *)&rating, (void *)&max_rating, 1, MPI_FLOAT, MPI_MAX, ipcomm);
+ MPI_Allreduce((void *)&lbsum, (void *)&min_lbsum, 1, MPI_FLOAT, MPI_MIN, ipcomm);
+
+ lpecost.rank = ctrl->mype;
+ lpecost.cost = lbsum;
+ if (min_lbsum < UNBALANCE_FRACTION * (float)(ncon)) {
+ if (lbsum < UNBALANCE_FRACTION * (float)(ncon))
+ lpecost.cost = rating;
+ else
+ lpecost.cost = max_rating + lbsum;
+ }
+
+ MPI_Allreduce((void *)&lpecost, (void *)&gpecost, 1, MPI_FLOAT_INT, MPI_MINLOC, ipcomm);
+
+ /* Now send this to the coordinating processor */
+ if (ctrl->mype == gpecost.rank && ctrl->mype != gd_pe)
+ MPI_Send((void *)part, nvtxs, IDX_DATATYPE, gd_pe, 1, ctrl->comm);
+
+ if (ctrl->mype != gpecost.rank && ctrl->mype == gd_pe)
+ MPI_Recv((void *)part, nvtxs, IDX_DATATYPE, gpecost.rank, 1, ctrl->comm, &status);
+
+ if (ctrl->mype == gd_pe) {
+ idxcopy(nvtxs, part, lwhere);
+ SerialRemap(&cgraph, ctrl->nparts, home, lwhere, part, ctrl->tpwgts);
+ }
+ }
+ else {
+ Moc_Diffusion(&myctrl, agraph, graph->vtxdist, agraph->where, home, wspace, N_MOC_GD_PASSES);
+ }
+ }
+
+ if (graph->ncon <= MAX_NCON_FOR_DIFFUSION) {
+ if (ctrl->mype == sr_pe || ctrl->mype == gd_pe) {
+ /********************************************************************/
+ /* The coordinators from each group decide on the best partitioning */
+ /********************************************************************/
+ my_cut = (float) ComputeSerialEdgeCut(&cgraph);
+ my_totalv = (float) Mc_ComputeSerialTotalV(&cgraph, home);
+ Moc_ComputeSerialBalance(ctrl, &cgraph, part, lbvec);
+ my_balance = ssum(cgraph.ncon, lbvec);
+ my_balance /= (float) cgraph.ncon;
+ my_cost = ctrl->ipc_factor * my_cut + REDIST_WGT * ctrl->redist_base * my_totalv;
+
+ IFSET(ctrl->dbglvl, DBG_REFINEINFO, printf("%s initial cut: %.1f, totalv: %.1f, balance: %.3f\n",
+ (ctrl->mype == sr_pe ? "scratch-remap" : "diffusion"), my_cut, my_totalv, my_balance));
+
+ if (ctrl->mype == gd_pe) {
+ buffer[0] = my_cost;
+ buffer[1] = my_balance;
+ MPI_Send((void *)buffer, 2, MPI_FLOAT, sr_pe, 1, ctrl->comm);
+ }
+ else {
+ MPI_Recv((void *)buffer, 2, MPI_FLOAT, gd_pe, 1, ctrl->comm, &status);
+ your_cost = buffer[0];
+ your_balance = buffer[1];
+ }
+ }
+
+ if (ctrl->mype == sr_pe) {
+ who_wins = gd_pe;
+ if ((my_balance < 1.1 && your_balance > 1.1) ||
+ (my_balance < 1.1 && your_balance < 1.1 && my_cost < your_cost) ||
+ (my_balance > 1.1 && your_balance > 1.1 && my_balance < your_balance)) {
+ who_wins = sr_pe;
+ }
+ }
+
+ MPI_Bcast((void *)&who_wins, 1, MPI_INT, sr_pe, ctrl->comm);
+ }
+ else {
+ who_wins = sr_pe;
+ }
+
+ MPI_Bcast((void *)part, nvtxs, IDX_DATATYPE, who_wins, ctrl->comm);
+ idxcopy(graph->nvtxs, part+vtxdist[ctrl->mype], graph->where);
+
+ MPI_Comm_free(&ipcomm);
+ GKfree((void **)&xadj, (void **)&mytpwgts, LTERM);
+
+/* For whatever reason, FreeGraph crashes here...so explicitly free the memory.
+ FreeGraph(agraph);
+*/
+ GKfree((void **)&agraph->xadj, (void **)&agraph->adjncy, (void **)&agraph->vwgt, (void **)&agraph->nvwgt, LTERM);
+ GKfree((void **)&agraph->vsize, (void **)&agraph->adjwgt, (void **)&agraph->label, LTERM);
+ GKfree((void **)&agraph, LTERM);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
+
+}
+
+
+/* NOTE: this subroutine should work for static, adaptive, single-, and multi-contraint */
+/*************************************************************************
+* This function assembles the graph into a single processor
+**************************************************************************/
+GraphType *Moc_AssembleAdaptiveGraph(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, j, k, l, gnvtxs, nvtxs, ncon, gnedges, nedges, gsize;
+ idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *vtxdist, *imap;
+ idxtype *axadj, *aadjncy, *aadjwgt, *avwgt, *avsize = NULL, *alabel;
+ idxtype *mygraph, *ggraph;
+ int *rcounts, *rdispls, mysize;
+ float *anvwgt;
+ GraphType *agraph;
+
+ gnvtxs = graph->gnvtxs;
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ nedges = graph->xadj[nvtxs];
+ xadj = graph->xadj;
+ vwgt = graph->vwgt;
+ vsize = graph->vsize;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ vtxdist = graph->vtxdist;
+ imap = graph->imap;
+
+ /*************************************************************/
+ /* Determine the # of idxtype to receive from each processor */
+ /*************************************************************/
+ rcounts = imalloc(ctrl->npes, "AssembleGraph: rcounts");
+ switch (ctrl->partType) {
+ case STATIC_PARTITION:
+ mysize = (1+ncon)*nvtxs + 2*nedges;
+ break;
+ case ADAPTIVE_PARTITION:
+ case REFINE_PARTITION:
+ mysize = (2+ncon)*nvtxs + 2*nedges;
+ break;
+ default:
+ printf("WARNING: bad value for ctrl->partType %d\n", ctrl->partType);
+ break;
+ }
+ MPI_Allgather((void *)(&mysize), 1, MPI_INT, (void *)rcounts, 1, MPI_INT, ctrl->comm);
+
+ rdispls = imalloc(ctrl->npes+1, "AssembleGraph: rdispls");
+ rdispls[0] = 0;
+ for (i=1; i<ctrl->npes+1; i++)
+ rdispls[i] = rdispls[i-1] + rcounts[i-1];
+
+ /* Construct the one-array storage format of the assembled graph */
+ mygraph = (mysize <= wspace->maxcore ? wspace->core : idxmalloc(mysize, "AssembleGraph: mygraph"));
+ for (k=i=0; i<nvtxs; i++) {
+ mygraph[k++] = xadj[i+1]-xadj[i];
+ for (j=0; j<ncon; j++)
+ mygraph[k++] = vwgt[i*ncon+j];
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION)
+ mygraph[k++] = vsize[i];
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ mygraph[k++] = imap[adjncy[j]];
+ mygraph[k++] = adjwgt[j];
+ }
+ }
+ ASSERT(ctrl, mysize == k);
+
+ /**************************************/
+ /* Assemble and send the entire graph */
+ /**************************************/
+ gsize = rdispls[ctrl->npes];
+ ggraph = (gsize <= wspace->maxcore-mysize ? wspace->core+mysize : idxmalloc(gsize, "AssembleGraph: ggraph"));
+ MPI_Allgatherv((void *)mygraph, mysize, IDX_DATATYPE, (void *)ggraph, rcounts, rdispls, IDX_DATATYPE, ctrl->comm);
+
+ GKfree((void **)&rcounts, (void **)&rdispls, LTERM);
+ if (mysize > wspace->maxcore)
+ free(mygraph);
+
+ agraph = CreateGraph();
+ agraph->nvtxs = gnvtxs;
+ switch (ctrl->partType) {
+ case STATIC_PARTITION:
+ agraph->nedges = gnedges = (gsize-(1+ncon)*gnvtxs)/2;
+ break;
+ case ADAPTIVE_PARTITION:
+ case REFINE_PARTITION:
+ agraph->nedges = gnedges = (gsize-(2+ncon)*gnvtxs)/2;
+ break;
+ default:
+ printf("WARNING: bad value for ctrl->partType %d\n", ctrl->partType);
+ agraph->nedges = gnedges = -1;
+ break;
+ }
+
+ agraph->ncon = ncon;
+
+ /*******************************************/
+ /* Allocate memory for the assembled graph */
+ /*******************************************/
+ axadj = agraph->xadj = idxmalloc(gnvtxs+1, "AssembleGraph: axadj");
+ avwgt = agraph->vwgt = idxmalloc(gnvtxs*ncon, "AssembleGraph: avwgt");
+ anvwgt = agraph->nvwgt = fmalloc(gnvtxs*ncon, "AssembleGraph: anvwgt");
+ aadjncy = agraph->adjncy = idxmalloc(gnedges, "AssembleGraph: adjncy");
+ aadjwgt = agraph->adjwgt = idxmalloc(gnedges, "AssembleGraph: adjwgt");
+ alabel = agraph->label = idxmalloc(gnvtxs, "AssembleGraph: alabel");
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION)
+ avsize = agraph->vsize = idxmalloc(gnvtxs, "AssembleGraph: avsize");
+
+ for (k=j=i=0; i<gnvtxs; i++) {
+ axadj[i] = ggraph[k++];
+ for (l=0; l<ncon; l++)
+ avwgt[i*ncon+l] = ggraph[k++];
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION)
+ avsize[i] = ggraph[k++];
+ for (l=0; l<axadj[i]; l++) {
+ aadjncy[j] = ggraph[k++];
+ aadjwgt[j] = ggraph[k++];
+ j++;
+ }
+ }
+
+ /*********************************/
+ /* Now fix up the received graph */
+ /*********************************/
+ MAKECSR(i, gnvtxs, axadj);
+
+ for (i=0; i<gnvtxs; i++)
+ for (j=0; j<ncon; j++)
+ anvwgt[i*ncon+j] = (float)(agraph->vwgt[i*ncon+j]) / (float)(ctrl->tvwgts[j]);
+
+ for (i=0; i<gnvtxs; i++)
+ alabel[i] = i;
+
+ if (gsize > wspace->maxcore-mysize)
+ free(ggraph);
+
+ return agraph;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initmsection.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initmsection.c
new file mode 100644
index 0000000..63c7c35
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initmsection.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * initmsection.c
+ *
+ * This file contains code that performs the k-way multisection
+ *
+ * Started 6/3/97
+ * George
+ *
+ * $Id: initmsection.c,v 1.2 2003/07/21 17:18:49 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+
+#define DEBUG_IPART_
+
+
+
+/*************************************************************************
+* This function is the entry point of the initial partitioning algorithm.
+* This algorithm assembles the graph to all the processors and preceed
+* serially.
+**************************************************************************/
+void InitMultisection(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, lpecut[2], gpecut[2], mypart, moptions[10];
+ idxtype *vtxdist, *gwhere = NULL, *part, *label;
+ GraphType *agraph;
+ int *sendcounts, *displs;
+ MPI_Comm newcomm, labelcomm;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
+
+ /* Assemble the graph and do the necessary pre-processing */
+ agraph = AssembleMultisectedGraph(ctrl, graph, wspace);
+ part = agraph->where;
+ agraph->where = NULL;
+
+ /* Split the processors into groups so that each one can do a bisection */
+ mypart = ctrl->mype%(ctrl->nparts/2);
+ MPI_Comm_split(ctrl->comm, mypart, 0, &newcomm);
+
+ /* Each processor keeps the graphs that it only needs and bisects it */
+ agraph->ncon = 1; /* needed for Moc_KeepPart */
+ Moc_KeepPart(agraph, wspace, part, mypart);
+ label = agraph->label; /* Save this because ipart may need it */
+ agraph->label = NULL;
+
+ /* Bisect the graph and construct the separator */
+ switch (ctrl->ipart) {
+ case ISEP_EDGE:
+ moptions[0] = 1;
+ moptions[1] = 3;
+ moptions[2] = 1;
+ moptions[3] = 1;
+ moptions[4] = 0;
+ moptions[7] = ctrl->mype;
+
+ agraph->where = idxmalloc(agraph->nvtxs, "InitMultisection: agraph->where");
+
+ METIS_EdgeComputeSeparator(&agraph->nvtxs, agraph->xadj, agraph->adjncy,
+ agraph->vwgt, agraph->adjwgt, moptions, &agraph->mincut, agraph->where);
+ break;
+ case ISEP_NODE:
+ moptions[0] = 1;
+ moptions[1] = 3;
+ moptions[2] = 1;
+ moptions[3] = 2;
+ moptions[4] = 0;
+ moptions[7] = ctrl->mype;
+
+ agraph->where = idxmalloc(agraph->nvtxs, "InitMultisection: agraph->where");
+
+ METIS_NodeComputeSeparator(&agraph->nvtxs, agraph->xadj, agraph->adjncy, agraph->vwgt,
+ agraph->adjwgt, moptions, &agraph->mincut, agraph->where);
+ break;
+ default:
+ errexit("Unknown ISEP type!\n");
+ }
+
+ for (i=0; i<agraph->nvtxs; i++) {
+ ASSERT(ctrl, agraph->where[i]>=0 && agraph->where[i]<=2);
+ if (agraph->where[i] == 2)
+ agraph->where[i] = ctrl->nparts+2*mypart;
+ else
+ agraph->where[i] += 2*mypart;
+ }
+
+ /* Determine which PE got the minimum cut */
+ lpecut[0] = agraph->mincut;
+ MPI_Comm_rank(newcomm, lpecut+1);
+ MPI_Allreduce(lpecut, gpecut, 1, MPI_2INT, MPI_MINLOC, newcomm);
+
+ /* myprintf(ctrl, "Nvtxs: %d, Mincut: %d, GMincut: %d, %d\n", agraph->nvtxs, agraph->mincut, gpecut[0], gpecut[1]); */
+
+ /* Send the best where to the root processor of this partition */
+ if (lpecut[1] == gpecut[1] && gpecut[1] != 0)
+ MPI_Send((void *)agraph->where, agraph->nvtxs, IDX_DATATYPE, 0, 1, newcomm);
+ if (lpecut[1] == 0 && gpecut[1] != 0)
+ MPI_Recv((void *)agraph->where, agraph->nvtxs, IDX_DATATYPE, gpecut[1], 1, newcomm, &ctrl->status);
+
+ /* Create a communicator that stores all the i-th processors of the newcomm */
+ MPI_Comm_split(ctrl->comm, lpecut[1], 0, &labelcomm);
+
+ /* Map the separator back to agraph. This is inefficient! */
+ if (lpecut[1] == 0) {
+ gwhere = idxsmalloc(graph->gnvtxs, 0, "InitMultisection: gwhere");
+ for (i=0; i<agraph->nvtxs; i++)
+ gwhere[label[i]] = agraph->where[i];
+ }
+
+ free(agraph->where);
+ agraph->where = part;
+
+ if (lpecut[1] == 0) {
+ MPI_Reduce((void *)gwhere, (void *)agraph->where, graph->gnvtxs, IDX_DATATYPE, MPI_SUM, 0, labelcomm);
+ free(gwhere);
+ }
+
+ /* The minimum PE performs the Scatter */
+ vtxdist = graph->vtxdist;
+ ASSERT(ctrl, graph->where != NULL);
+ free(graph->where); /* Remove the propagated down where info */
+ graph->where = idxmalloc(graph->nvtxs+graph->nrecv, "InitPartition: where");
+
+ sendcounts = imalloc(ctrl->npes, "InitPartitionNew: sendcounts");
+ displs = imalloc(ctrl->npes, "InitPartitionNew: displs");
+
+ for (i=0; i<ctrl->npes; i++) {
+ sendcounts[i] = vtxdist[i+1]-vtxdist[i];
+ displs[i] = vtxdist[i];
+ }
+
+ MPI_Scatterv((void *)agraph->where, sendcounts, displs, IDX_DATATYPE,
+ (void *)graph->where, graph->nvtxs, IDX_DATATYPE, 0, ctrl->comm);
+
+ GKfree((void **)&sendcounts, (void **)&displs, (void **)&label, LTERM);
+
+ FreeGraph(agraph);
+
+ MPI_Comm_free(&newcomm);
+ MPI_Comm_free(&labelcomm);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
+
+}
+
+
+
+
+/*************************************************************************
+* This function assembles the graph into a single processor
+**************************************************************************/
+GraphType *AssembleMultisectedGraph(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, j, k, l, gnvtxs, nvtxs, gnedges, nedges, gsize;
+ idxtype *xadj, *vwgt, *where, *adjncy, *adjwgt, *vtxdist, *imap;
+ idxtype *axadj, *aadjncy, *aadjwgt, *avwgt, *awhere, *alabel;
+ idxtype *mygraph, *ggraph;
+ int *recvcounts, *displs, mysize;
+ GraphType *agraph;
+
+ gnvtxs = graph->gnvtxs;
+ nvtxs = graph->nvtxs;
+ nedges = graph->xadj[nvtxs];
+ xadj = graph->xadj;
+ vwgt = graph->vwgt;
+ where = graph->where;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ vtxdist = graph->vtxdist;
+ imap = graph->imap;
+
+ /* Determine the # of idxtype to receive from each processor */
+ recvcounts = imalloc(ctrl->npes, "AssembleGraph: recvcounts");
+ mysize = 3*nvtxs + 2*nedges;
+ MPI_Allgather((void *)(&mysize), 1, MPI_INT, (void *)recvcounts, 1, MPI_INT, ctrl->comm);
+
+ displs = imalloc(ctrl->npes+1, "AssembleGraph: displs");
+ displs[0] = 0;
+ for (i=1; i<ctrl->npes+1; i++)
+ displs[i] = displs[i-1] + recvcounts[i-1];
+
+ /* Construct the one-array storage format of the assembled graph */
+ mygraph = (mysize <= wspace->maxcore ? wspace->core : idxmalloc(mysize, "AssembleGraph: mygraph"));
+ for (k=i=0; i<nvtxs; i++) {
+ mygraph[k++] = xadj[i+1]-xadj[i];
+ mygraph[k++] = vwgt[i];
+ mygraph[k++] = where[i];
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ mygraph[k++] = imap[adjncy[j]];
+ mygraph[k++] = adjwgt[j];
+ }
+ }
+ ASSERT(ctrl, mysize == k);
+
+ /* Assemble the entire graph */
+ gsize = displs[ctrl->npes];
+ ggraph = (gsize <= wspace->maxcore-mysize ? wspace->core+mysize : idxmalloc(gsize, "AssembleGraph: ggraph"));
+ MPI_Allgatherv((void *)mygraph, mysize, IDX_DATATYPE, (void *)ggraph, recvcounts, displs, IDX_DATATYPE, ctrl->comm);
+
+ GKfree((void **)&recvcounts, (void **)&displs, LTERM);
+ if (mysize > wspace->maxcore)
+ free(mygraph);
+
+ agraph = CreateGraph();
+ agraph->nvtxs = gnvtxs;
+ agraph->nedges = gnedges = (gsize-3*gnvtxs)/2;
+
+ /* Allocate memory for the assembled graph */
+ axadj = agraph->xadj = idxmalloc(gnvtxs+1, "AssembleGraph: axadj");
+ avwgt = agraph->vwgt = idxmalloc(gnvtxs, "AssembleGraph: avwgt");
+ awhere = agraph->where = idxmalloc(gnvtxs, "AssembleGraph: awhere");
+ aadjncy = agraph->adjncy = idxmalloc(gnedges, "AssembleGraph: adjncy");
+ aadjwgt = agraph->adjwgt = idxmalloc(gnedges, "AssembleGraph: adjwgt");
+ alabel = agraph->label = idxmalloc(gnvtxs, "AssembleGraph: alabel");
+
+ for (k=j=i=0; i<gnvtxs; i++) {
+ axadj[i] = ggraph[k++];
+ avwgt[i] = ggraph[k++];
+ awhere[i] = ggraph[k++];
+ for (l=0; l<axadj[i]; l++) {
+ aadjncy[j] = ggraph[k++];
+ aadjwgt[j] = ggraph[k++];
+ j++;
+ }
+ }
+
+ /* Now fix up the received graph */
+ MAKECSR(i, gnvtxs, axadj);
+
+ for (i=0; i<gnvtxs; i++)
+ alabel[i] = i;
+
+ if (gsize > wspace->maxcore-mysize)
+ free(ggraph);
+
+ return agraph;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initpart.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initpart.c
new file mode 100644
index 0000000..40b8d95
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/initpart.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * initpart.c
+ *
+ * This file contains code that performs log(p) parallel multilevel
+ * recursive bissection
+ *
+ * Started 3/4/96
+ * George
+ *
+ * $Id: initpart.c,v 1.2 2003/07/21 17:18:49 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+
+#define DEBUG_IPART_
+
+
+
+/*************************************************************************
+* This function is the entry point of the initial partition algorithm
+* that does recursive bissection.
+* This algorithm assembles the graph to all the processors and preceeds
+* by parallelizing the recursive bisection step.
+**************************************************************************/
+void Moc_InitPartition_RB(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, j;
+ int ncon, mype, npes, gnvtxs, ngroups;
+ idxtype *xadj, *adjncy, *adjwgt, *vwgt;
+ idxtype *part, *gwhere0, *gwhere1;
+ idxtype *tmpwhere, *tmpvwgt, *tmpxadj, *tmpadjncy, *tmpadjwgt;
+ GraphType *agraph;
+ int lnparts, fpart, fpe, lnpes;
+ int twoparts=2, numflag = 0, wgtflag = 3, moptions[10], edgecut, max_cut;
+ float *mytpwgts, mytpwgts2[2], lbvec[MAXNCON], lbsum, min_lbsum, wsum;
+ MPI_Comm ipcomm;
+ struct {
+ float sum;
+ int rank;
+ } lpesum, gpesum;
+
+ ncon = graph->ncon;
+ ngroups = amax(amin(RIP_SPLIT_FACTOR, ctrl->npes), 1);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
+
+ agraph = Moc_AssembleAdaptiveGraph(ctrl, graph, wspace);
+ part = idxmalloc(agraph->nvtxs, "Moc_IP_RB: part");
+ xadj = idxmalloc(agraph->nvtxs+1, "Moc_IP_RB: xadj");
+ adjncy = idxmalloc(agraph->nedges, "Moc_IP_RB: adjncy");
+ adjwgt = idxmalloc(agraph->nedges, "Moc_IP_RB: adjwgt");
+ vwgt = idxmalloc(agraph->nvtxs*ncon, "Moc_IP_RB: vwgt");
+
+ idxcopy(agraph->nvtxs*ncon, agraph->vwgt, vwgt);
+ idxcopy(agraph->nvtxs+1, agraph->xadj, xadj);
+ idxcopy(agraph->nedges, agraph->adjncy, adjncy);
+ idxcopy(agraph->nedges, agraph->adjwgt, adjwgt);
+
+ MPI_Comm_split(ctrl->gcomm, ctrl->mype % ngroups, 0, &ipcomm);
+ MPI_Comm_rank(ipcomm, &mype);
+ MPI_Comm_size(ipcomm, &npes);
+
+ gnvtxs = agraph->nvtxs;
+
+ gwhere0 = idxsmalloc(gnvtxs, 0, "Moc_IP_RB: gwhere0");
+ gwhere1 = idxmalloc(gnvtxs, "Moc_IP_RB: gwhere1");
+
+ /* ADD: this assumes that tpwgts for all constraints is the same */
+ /* ADD: this is necessary because serial metis does not support the general case */
+ mytpwgts = fsmalloc(ctrl->nparts, 0.0, "mytpwgts");
+ for (i=0; i<ctrl->nparts; i++)
+ for (j=0; j<ncon; j++)
+ mytpwgts[i] += ctrl->tpwgts[i*ncon+j];
+ for (i=0; i<ctrl->nparts; i++)
+ mytpwgts[i] /= (float)ncon;
+
+ /* Go into the recursive bisection */
+ /* ADD: consider changing this to breadth-first type bisection */
+ moptions[0] = 0;
+ moptions[7] = ctrl->sync + (ctrl->mype % ngroups) + 1;
+
+ lnparts = ctrl->nparts;
+ fpart = fpe = 0;
+ lnpes = npes;
+ while (lnpes > 1 && lnparts > 1) {
+ /* Determine the weights of the partitions */
+ mytpwgts2[0] = ssum(lnparts/2, mytpwgts+fpart);
+ mytpwgts2[1] = 1.0-mytpwgts2[0];
+
+ if (ncon == 1)
+ METIS_WPartGraphKway2(&agraph->nvtxs, agraph->xadj, agraph->adjncy,
+ agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag, &twoparts, mytpwgts2,
+ moptions, &edgecut, part);
+ else {
+ METIS_mCPartGraphRecursive2(&agraph->nvtxs, &ncon, agraph->xadj,
+ agraph->adjncy, agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag,
+ &twoparts, mytpwgts2, moptions, &edgecut, part);
+ }
+
+ wsum = ssum(lnparts/2, mytpwgts+fpart);
+ sscale(lnparts/2, 1.0/wsum, mytpwgts+fpart);
+ sscale(lnparts-lnparts/2, 1.0/(1.0-wsum), mytpwgts+fpart+lnparts/2);
+
+ /* I'm picking the left branch */
+ if (mype < fpe+lnpes/2) {
+ Moc_KeepPart(agraph, wspace, part, 0);
+ lnpes = lnpes/2;
+ lnparts = lnparts/2;
+ }
+ else {
+ Moc_KeepPart(agraph, wspace, part, 1);
+ fpart = fpart + lnparts/2;
+ fpe = fpe + lnpes/2;
+ lnpes = lnpes - lnpes/2;
+ lnparts = lnparts - lnparts/2;
+ }
+ }
+
+ /* In case npes is greater than or equal to nparts */
+ if (lnparts == 1) {
+ /* Only the first process will assign labels (for the reduction to work) */
+ if (mype == fpe) {
+ for (i=0; i<agraph->nvtxs; i++)
+ gwhere0[agraph->label[i]] = fpart;
+ }
+ }
+ /* In case npes is smaller than nparts */
+ else {
+ if (ncon == 1)
+ METIS_WPartGraphKway2(&agraph->nvtxs, agraph->xadj, agraph->adjncy,
+ agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag, &lnparts, mytpwgts+fpart,
+ moptions, &edgecut, part);
+ else
+ METIS_mCPartGraphRecursive2(&agraph->nvtxs, &ncon, agraph->xadj,
+ agraph->adjncy, agraph->vwgt, agraph->adjwgt, &wgtflag, &numflag,
+ &lnparts, mytpwgts+fpart, moptions, &edgecut, part);
+
+ for (i=0; i<agraph->nvtxs; i++)
+ gwhere0[agraph->label[i]] = fpart + part[i];
+ }
+
+ MPI_Allreduce((void *)gwhere0, (void *)gwhere1, gnvtxs, IDX_DATATYPE, MPI_SUM, ipcomm);
+
+ if (ngroups > 1) {
+ tmpxadj = agraph->xadj;
+ tmpadjncy = agraph->adjncy;
+ tmpadjwgt = agraph->adjwgt;
+ tmpvwgt = agraph->vwgt;
+ tmpwhere = agraph->where;
+ agraph->xadj = xadj;
+ agraph->adjncy = adjncy;
+ agraph->adjwgt = adjwgt;
+ agraph->vwgt = vwgt;
+ agraph->where = gwhere1;
+ agraph->vwgt = vwgt;
+ agraph->nvtxs = gnvtxs;
+ Moc_ComputeSerialBalance(ctrl, agraph, gwhere1, lbvec);
+ lbsum = ssum(ncon, lbvec);
+
+ edgecut = ComputeSerialEdgeCut(agraph);
+ MPI_Allreduce((void *)&edgecut, (void *)&max_cut, 1, MPI_INT, MPI_MAX, ctrl->gcomm);
+ MPI_Allreduce((void *)&lbsum, (void *)&min_lbsum, 1, MPI_FLOAT, MPI_MIN, ctrl->gcomm);
+
+ lpesum.sum = lbsum;
+ if (min_lbsum < UNBALANCE_FRACTION * (float)(ncon)) {
+ if (lbsum < UNBALANCE_FRACTION * (float)(ncon))
+ lpesum.sum = (float) (edgecut);
+ else
+ lpesum.sum = (float) (max_cut);
+ }
+
+ MPI_Comm_rank(ctrl->gcomm, &(lpesum.rank));
+ MPI_Allreduce((void *)&lpesum, (void *)&gpesum, 1, MPI_FLOAT_INT, MPI_MINLOC, ctrl->gcomm);
+ MPI_Bcast((void *)gwhere1, gnvtxs, IDX_DATATYPE, gpesum.rank, ctrl->gcomm);
+
+ agraph->xadj = tmpxadj;
+ agraph->adjncy = tmpadjncy;
+ agraph->adjwgt = tmpadjwgt;
+ agraph->vwgt = tmpvwgt;
+ agraph->where = tmpwhere;
+ }
+
+ idxcopy(graph->nvtxs, gwhere1+graph->vtxdist[ctrl->mype], graph->where);
+
+ FreeGraph(agraph);
+ MPI_Comm_free(&ipcomm);
+ GKfree((void **)&gwhere0, (void **)&gwhere1, (void **)&mytpwgts, (void **)&part, (void **)&xadj, (void **)&adjncy, (void **)&adjwgt, (void **)&vwgt, LTERM);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
+
+}
+
+
+/*************************************************************************
+* This function keeps one parts
+**************************************************************************/
+void Moc_KeepPart(GraphType *graph, WorkSpaceType *wspace, idxtype *part, int mypart)
+{
+ int h, i, j, k;
+ int nvtxs, ncon, mynvtxs, mynedges;
+ idxtype *xadj, *vwgt, *adjncy, *adjwgt, *label;
+ idxtype *rename;
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ vwgt = graph->vwgt;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ label = graph->label;
+
+ rename = idxmalloc(nvtxs, "Moc_KeepPart: rename");
+
+ for (mynvtxs=0, i=0; i<nvtxs; i++) {
+ if (part[i] == mypart)
+ rename[i] = mynvtxs++;
+ }
+
+ for (mynvtxs=0, mynedges=0, j=xadj[0], i=0; i<nvtxs; i++) {
+ if (part[i] == mypart) {
+ for (; j<xadj[i+1]; j++) {
+ k = adjncy[j];
+ if (part[k] == mypart) {
+ adjncy[mynedges] = rename[k];
+ adjwgt[mynedges++] = adjwgt[j];
+ }
+ }
+ j = xadj[i+1]; /* Save xadj[i+1] for later use */
+
+ for (h=0; h<ncon; h++)
+ vwgt[mynvtxs*ncon+h] = vwgt[i*ncon+h];
+ label[mynvtxs] = label[i];
+ xadj[++mynvtxs] = mynedges;
+
+ }
+ else {
+ j = xadj[i+1]; /* Save xadj[i+1] for later use */
+ }
+ }
+
+ graph->nvtxs = mynvtxs;
+ graph->nedges = mynedges;
+
+ free(rename);
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kmetis.c
new file mode 100644
index 0000000..2ad20e3
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kmetis.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * kmetis.c
+ *
+ * This is the entry point of Moc_PARMETIS_PartGraphKway
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: kmetis.c,v 1.9 2003/07/31 16:27:27 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel k-way multilevel partitionioner.
+* This function assumes nothing about the graph distribution.
+* It is the general case.
+************************************************************************************/
+void ParMETIS_V3_PartKway(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
+ idxtype *adjwgt, int *wgtflag, int *numflag, int *ncon, int *nparts,
+ float *tpwgts, float *ubvec, int *options, int *edgecut, idxtype *part,
+ MPI_Comm *comm)
+{
+ int h, i;
+ int nvtxs = -1, npes, mype;
+ CtrlType ctrl;
+ WorkSpaceType wspace;
+ GraphType *graph;
+ float avg, maximb, *mytpwgts;
+ int moptions[10];
+ int seed, dbglvl = 0;
+ int iwgtflag, inumflag, incon, inparts, ioptions[10];
+ float *itpwgts, iubvec[MAXNCON];
+
+ MPI_Comm_size(*comm, &npes);
+ MPI_Comm_rank(*comm, &mype);
+
+
+ /********************************/
+ /* Try and take care bad inputs */
+ /********************************/
+ if (options != NULL && options[0] == 1)
+ dbglvl = options[PMV3_OPTION_DBGLVL];
+
+ CheckInputs(STATIC_PARTITION, npes, dbglvl, wgtflag, &iwgtflag, numflag, &inumflag, ncon,
+ &incon, nparts, &inparts, tpwgts, &itpwgts, ubvec, iubvec, NULL, NULL,
+ options, ioptions, part, comm);
+
+
+ /*********************************/
+ /* Take care the nparts = 1 case */
+ /*********************************/
+ if (inparts <= 1) {
+ idxset(vtxdist[mype+1]-vtxdist[mype], 0, part);
+ *edgecut = 0;
+ return;
+ }
+
+ /******************************/
+ /* Take care of npes = 1 case */
+ /******************************/
+ if (npes == 1 && inparts > 1) {
+ moptions[0] = 0;
+ nvtxs = vtxdist[1];
+
+ if (incon == 1) {
+ METIS_WPartGraphKway(&nvtxs, xadj, adjncy, vwgt, adjwgt, &iwgtflag, &inumflag,
+ &inparts, itpwgts, moptions, edgecut, part);
+ }
+ else {
+ /* ADD: this is because METIS does not support tpwgts for all constraints */
+ mytpwgts = fmalloc(inparts, "mytpwgts");
+ for (i=0; i<inparts; i++)
+ mytpwgts[i] = itpwgts[i*incon];
+
+ moptions[7] = -1;
+ METIS_mCPartGraphRecursive2(&nvtxs, &incon, xadj, adjncy, vwgt, adjwgt, &iwgtflag,
+ &inumflag, &inparts, mytpwgts, moptions, edgecut, part);
+
+ free(mytpwgts);
+ }
+
+ return;
+ }
+
+
+ if (inumflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 1);
+
+ /*****************************/
+ /* Set up control structures */
+ /*****************************/
+ if (ioptions[0] == 1) {
+ dbglvl = ioptions[PMV3_OPTION_DBGLVL];
+ seed = ioptions[PMV3_OPTION_SEED];
+ }
+ else {
+ dbglvl = GLOBAL_DBGLVL;
+ seed = GLOBAL_SEED;
+ }
+ SetUpCtrl(&ctrl, inparts, dbglvl, *comm);
+ ctrl.CoarsenTo = amin(vtxdist[npes]+1, 25*incon*amax(npes, inparts));
+ ctrl.seed = (seed == 0) ? mype : seed*mype;
+ ctrl.sync = GlobalSEMax(&ctrl, seed);
+ ctrl.partType = STATIC_PARTITION;
+ ctrl.ps_relation = -1;
+ ctrl.tpwgts = itpwgts;
+ scopy(incon, iubvec, ctrl.ubvec);
+
+ graph = Moc_SetUpGraph(&ctrl, incon, vtxdist, xadj, vwgt, adjncy, adjwgt, &iwgtflag);
+
+ PreAllocateMemory(&ctrl, graph, &wspace);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
+
+ /*******************************************/
+ /* Check for funny cases */
+ /* -graph with no edges */
+ /* -graph with self edges */
+ /* -graph with poor vertex distribution */
+ /* -graph with less than 2*npe nodes */
+ /*******************************************/
+ if (vtxdist[npes] < SMALLGRAPH || vtxdist[npes] < npes*20 || GlobalSESum(&ctrl, graph->nedges) == 0) {
+ IFSET(ctrl.dbglvl, DBG_INFO, rprintf(&ctrl, "Partitioning a graph of size %d serially\n", vtxdist[npes]));
+ PartitionSmallGraph(&ctrl, graph, &wspace);
+ }
+ else {
+ /***********************/
+ /* Partition the graph */
+ /***********************/
+ Moc_Global_Partition(&ctrl, graph, &wspace);
+ ParallelReMapGraph(&ctrl, graph, &wspace);
+ }
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
+
+ idxcopy(graph->nvtxs, graph->where, part);
+ *edgecut = graph->mincut;
+
+ /*******************/
+ /* Print out stats */
+ /*******************/
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+
+ if (ctrl.dbglvl&DBG_INFO) {
+ rprintf(&ctrl, "Final %d-way CUT: %6d \tBalance: ", inparts, graph->mincut);
+ avg = 0.0;
+ for (h=0; h<incon; h++) {
+ maximb = 0.0;
+ for (i=0; i<inparts; i++)
+ maximb = amax(maximb, graph->gnpwgts[i*incon+h]/itpwgts[i*incon+h]);
+ avg += maximb;
+ rprintf(&ctrl, "%.3f ", maximb);
+ }
+ rprintf(&ctrl, " avg: %.3f\n", avg/(float)incon);
+ }
+
+ GKfree((void **)&itpwgts, (void **)&graph->lnpwgts, (void **)&graph->gnpwgts, (void **)&graph->nvwgt, LTERM);
+ FreeInitialGraphAndRemap(graph, iwgtflag);
+ FreeWSpace(&wspace);
+ FreeCtrl(&ctrl);
+
+ if (inumflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 0);
+
+}
+
+
+
+/*************************************************************************
+* This function is the driver to the multi-constraint partitioning algorithm.
+**************************************************************************/
+void Moc_Global_Partition(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, ncon, nparts;
+ float ftmp, ubavg, lbavg, lbvec[MAXNCON];
+
+ ncon = graph->ncon;
+ nparts = ctrl->nparts;
+ ubavg = savg(graph->ncon, ctrl->ubvec);
+
+ SetUp(ctrl, graph, wspace);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ rprintf(ctrl, "[%6d %8d %5d %5d] [%d] [", graph->gnvtxs, GlobalSESum(ctrl, graph->nedges),
+ GlobalSEMin(ctrl, graph->nvtxs), GlobalSEMax(ctrl, graph->nvtxs), ctrl->CoarsenTo);
+ for (i=0; i<ncon; i++)
+ rprintf(ctrl, " %.3f", GlobalSEMinFloat(ctrl,graph->nvwgt[samin_strd(graph->nvtxs, graph->nvwgt+i, ncon)*ncon+i]));
+ rprintf(ctrl, "] [");
+ for (i=0; i<ncon; i++)
+ rprintf(ctrl, " %.3f", GlobalSEMaxFloat(ctrl, graph->nvwgt[samax_strd(graph->nvtxs, graph->nvwgt+i, ncon)*ncon+i]));
+ rprintf(ctrl, "]\n");
+ }
+
+ if (graph->gnvtxs < 1.3*ctrl->CoarsenTo ||
+ (graph->finer != NULL &&
+ graph->gnvtxs > graph->finer->gnvtxs*COARSEN_FRACTION)) {
+
+ /* Done with coarsening. Find a partition */
+ graph->where = idxmalloc(graph->nvtxs+graph->nrecv, "graph->where");
+ Moc_InitPartition_RB(ctrl, graph, wspace);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, balance: ", graph->gnvtxs);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+
+ /* In case no coarsening took place */
+ if (graph->finer == NULL) {
+ Moc_ComputePartitionParams(ctrl, graph, wspace);
+ Moc_KWayFM(ctrl, graph, wspace, NGR_PASSES);
+ }
+ }
+ else {
+ Moc_GlobalMatch_Balance(ctrl, graph, wspace);
+
+ Moc_Global_Partition(ctrl, graph->coarser, wspace);
+
+ Moc_ProjectPartition(ctrl, graph, wspace);
+ Moc_ComputePartitionParams(ctrl, graph, wspace);
+
+ if (graph->ncon > 1 && graph->level < 3) {
+ for (i=0; i<ncon; i++) {
+ ftmp = ssum_strd(nparts, graph->gnpwgts+i, ncon);
+ if (ftmp != 0.0)
+ lbvec[i] = (float)(nparts) *
+ graph->gnpwgts[samax_strd(nparts, graph->gnpwgts+i, ncon)*ncon+i]/ftmp;
+ else
+ lbvec[i] = 1.0;
+ }
+ lbavg = savg(graph->ncon, lbvec);
+
+ if (lbavg > ubavg + 0.035) {
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, cut: %8d, balance: ", graph->gnvtxs, graph->mincut);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+
+ Moc_KWayBalance(ctrl, graph, wspace, graph->ncon);
+ }
+ }
+
+ Moc_KWayFM(ctrl, graph, wspace, NGR_PASSES);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, cut: %8d, balance: ", graph->gnvtxs, graph->mincut);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+
+ if (graph->level != 0)
+ GKfree((void **)&graph->lnpwgts, (void **)&graph->gnpwgts, LTERM);
+ }
+
+ return;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwaybalance.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwaybalance.c
new file mode 100644
index 0000000..003ec7c
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwaybalance.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mkwaybalance.c
+ *
+ * This file contains code that performs the k-way refinement
+ *
+ * Started 3/1/96
+ * George
+ *
+ * $Id: kwaybalance.c,v 1.2 2003/07/21 17:18:49 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+#define ProperSide(c, from, other) \
+ (((c) == 0 && (from)-(other) < 0) || ((c) == 1 && (from)-(other) > 0))
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void Moc_KWayBalance(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace, int npasses)
+{
+ int h, i, ii, iii, j, k, c;
+ int pass, nvtxs, nedges, ncon;
+ int nmoves, nmoved, nswaps;
+/* int gnswaps; */
+ int me, firstvtx, lastvtx, yourlastvtx;
+ int from, to = -1, oldto, oldcut, mydomain, yourdomain, imbalanced;
+ int npes = ctrl->npes, mype = ctrl->mype, nparts = ctrl->nparts;
+ int nlupd, nsupd, nnbrs, nchanged;
+ idxtype *xadj, *ladjncy, *adjwgt, *vtxdist;
+ idxtype *where, *tmp_where, *moved;
+ float *lnpwgts, *gnpwgts;
+ idxtype *update, *supdate, *rupdate, *pe_updates;
+ idxtype *changed, *perm, *pperm, *htable;
+ idxtype *peind, *recvptr, *sendptr;
+ KeyValueType *swchanges, *rwchanges;
+ RInfoType *rinfo, *myrinfo, *tmp_myrinfo, *tmp_rinfo;
+ EdgeType *tmp_edegrees, *my_edegrees, *your_edegrees;
+ float lbvec[MAXNCON], *nvwgt, *badmaxpwgt, *ubvec, *tpwgts, lbavg, ubavg;
+ int *nupds_pe;
+/* int ndirty, nclean, dptr; */
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->KWayTmr));
+
+ /*************************/
+ /* set up common aliases */
+ /*************************/
+ nvtxs = graph->nvtxs;
+ nedges = graph->nedges;
+ ncon = graph->ncon;
+
+ vtxdist = graph->vtxdist;
+ xadj = graph->xadj;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+
+ firstvtx = vtxdist[mype];
+ lastvtx = vtxdist[mype+1];
+
+ where = graph->where;
+ rinfo = graph->rinfo;
+ lnpwgts = graph->lnpwgts;
+ gnpwgts = graph->gnpwgts;
+ ubvec = ctrl->ubvec;
+ tpwgts = ctrl->tpwgts;
+
+ nnbrs = graph->nnbrs;
+ peind = graph->peind;
+ recvptr = graph->recvptr;
+ sendptr = graph->sendptr;
+
+ changed = idxmalloc(nvtxs, "KWR: changed");
+ rwchanges = wspace->pairs;
+ swchanges = rwchanges + recvptr[nnbrs];
+
+ /************************************/
+ /* set up important data structures */
+ /************************************/
+ perm = idxmalloc(nvtxs, "KWR: perm");
+ pperm = idxmalloc(nparts, "KWR: pperm");
+
+ update = idxmalloc(nvtxs, "KWR: update");
+ supdate = wspace->indices;
+ rupdate = supdate + recvptr[nnbrs];
+ nupds_pe = imalloc(npes, "KWR: nupds_pe");
+ htable = idxsmalloc(nvtxs+graph->nrecv, 0, "KWR: lhtable");
+ badmaxpwgt = fmalloc(nparts*ncon, "badmaxpwgt");
+
+ for (i=0; i<nparts; i++) {
+ for (h=0; h<ncon; h++) {
+ badmaxpwgt[i*ncon+h] = ubvec[h]*tpwgts[i*ncon+h];
+ }
+ }
+
+ moved = idxmalloc(nvtxs, "KWR: moved");
+ tmp_where = idxmalloc(nvtxs+graph->nrecv, "KWR: tmp_where");
+ tmp_rinfo = (RInfoType *)GKmalloc(sizeof(RInfoType)*nvtxs, "KWR: tmp_rinfo");
+ tmp_edegrees = (EdgeType *)GKmalloc(sizeof(EdgeType)*nedges, "KWR: tmp_edegrees");
+
+ idxcopy(nvtxs+graph->nrecv, where, tmp_where);
+ for (i=0; i<nvtxs; i++) {
+ tmp_rinfo[i].id = rinfo[i].id;
+ tmp_rinfo[i].ed = rinfo[i].ed;
+ tmp_rinfo[i].ndegrees = rinfo[i].ndegrees;
+ tmp_rinfo[i].degrees = tmp_edegrees+xadj[i];
+
+ for (j=0; j<rinfo[i].ndegrees; j++) {
+ tmp_rinfo[i].degrees[j].edge = rinfo[i].degrees[j].edge;
+ tmp_rinfo[i].degrees[j].ewgt = rinfo[i].degrees[j].ewgt;
+ }
+ }
+
+ nswaps = 0;
+ /*********************************************************/
+ /* perform a small number of passes through the vertices */
+ /*********************************************************/
+ for (pass=0; pass<npasses; pass++) {
+ oldcut = graph->mincut;
+ if (mype == 0)
+ RandomPermute(nparts, pperm, 1);
+ MPI_Bcast((void *)pperm, nparts, IDX_DATATYPE, 0, ctrl->comm);
+ FastRandomPermute(nvtxs, perm, 1);
+
+ /*****************************/
+ /* move dirty vertices first */
+ /*****************************/
+/*
+ ndirty = 0;
+ for (i=0; i<nvtxs; i++)
+ if (where[i] != mype)
+ ndirty++;
+
+ dptr = 0;
+ for (i=0; i<nvtxs; i++)
+ if (where[i] != mype)
+ perm[dptr++] = i;
+ else
+ perm[ndirty++] = i;
+
+ ASSERT(ctrl, ndirty == nvtxs);
+ ndirty = dptr;
+ nclean = nvtxs-dptr;
+ FastRandomPermute(ndirty, perm, 0);
+ FastRandomPermute(nclean, perm+ndirty, 0);
+*/
+
+ /* check to see if the partitioning is imbalanced */
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ ubavg = savg(ncon, ubvec);
+ lbavg = savg(ncon, lbvec);
+ imbalanced = (lbavg > ubavg) ? 1 : 0;
+
+ for (c=0; c<2; c++) {
+ nmoved = 0;
+
+ /**********************************************/
+ /* PASS ONE -- record stats for desired moves */
+ /**********************************************/
+ for (iii=0; iii<nvtxs; iii++) {
+ i = perm[iii];
+ from = tmp_where[i];
+ nvwgt = graph->nvwgt+i*ncon;
+
+ for (h=0; h<ncon; h++)
+ if (fabs(nvwgt[h]-gnpwgts[from*ncon+h]) < SMALLFLOAT)
+ break;
+
+ if (h < ncon) {
+ continue;
+ }
+
+ /* check for a potential improvement */
+ if (tmp_rinfo[i].ed >= tmp_rinfo[i].id) {
+ my_edegrees = tmp_rinfo[i].degrees;
+
+ for (k=0; k<tmp_rinfo[i].ndegrees; k++) {
+ to = my_edegrees[k].edge;
+ if (ProperSide(c, pperm[from], pperm[to]) &&
+ IsHBalanceBetterFT(ncon, gnpwgts+from*ncon, gnpwgts+to*ncon, nvwgt, ubvec)) {
+ break;
+ }
+ }
+ oldto = to;
+
+ /* check if a subdomain was found that fits */
+ if (k < tmp_rinfo[i].ndegrees) {
+ for (j=k+1; j<tmp_rinfo[i].ndegrees; j++) {
+ to = my_edegrees[j].edge;
+ if (ProperSide(c, pperm[from], pperm[to]) &&
+ IsHBalanceBetterTT(ncon, gnpwgts+oldto*ncon, gnpwgts+to*ncon, nvwgt, ubvec)){
+ k = j;
+ oldto = my_edegrees[k].edge;
+ }
+ }
+ to = oldto;
+
+ if (iii % npes == 0) {
+ /****************************************/
+ /* Update tmp arrays of the moved vertex */
+ /****************************************/
+ tmp_where[i] = to;
+ moved[nmoved++] = i;
+ for (h=0; h<ncon; h++) {
+ lnpwgts[to*ncon+h] += nvwgt[h];
+ lnpwgts[from*ncon+h] -= nvwgt[h];
+ gnpwgts[to*ncon+h] += nvwgt[h];
+ gnpwgts[from*ncon+h] -= nvwgt[h];
+ }
+
+ tmp_rinfo[i].ed += tmp_rinfo[i].id-my_edegrees[k].ewgt;
+ SWAP(tmp_rinfo[i].id, my_edegrees[k].ewgt, j);
+ if (my_edegrees[k].ewgt == 0) {
+ tmp_rinfo[i].ndegrees--;
+ my_edegrees[k].edge = my_edegrees[tmp_rinfo[i].ndegrees].edge;
+ my_edegrees[k].ewgt = my_edegrees[tmp_rinfo[i].ndegrees].ewgt;
+ }
+ else {
+ my_edegrees[k].edge = from;
+ }
+
+ /* Update the degrees of adjacent vertices */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ /* no need to bother about vertices on different pe's */
+ if (ladjncy[j] >= nvtxs)
+ continue;
+
+ me = ladjncy[j];
+ mydomain = tmp_where[me];
+
+ myrinfo = tmp_rinfo+me;
+ your_edegrees = myrinfo->degrees;
+
+ if (mydomain == from) {
+ INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
+ }
+ else {
+ if (mydomain == to) {
+ INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
+ }
+ }
+
+ /* Remove contribution from the .ed of 'from' */
+ if (mydomain != from) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == from) {
+ if (your_edegrees[k].ewgt == adjwgt[j]) {
+ myrinfo->ndegrees--;
+ your_edegrees[k].edge = your_edegrees[myrinfo->ndegrees].edge;
+ your_edegrees[k].ewgt = your_edegrees[myrinfo->ndegrees].ewgt;
+ }
+ else {
+ your_edegrees[k].ewgt -= adjwgt[j];
+ }
+ break;
+ }
+ }
+ }
+
+ /* Add contribution to the .ed of 'to' */
+ if (mydomain != to) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == to) {
+ your_edegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ your_edegrees[myrinfo->ndegrees].edge = to;
+ your_edegrees[myrinfo->ndegrees++].ewgt = adjwgt[j];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*************************************************/
+ /* PASS TWO -- commit the remainder of the moves */
+ /*************************************************/
+ nlupd = nsupd = nmoves = nchanged = 0;
+ for (iii=0; iii<nmoved; iii++) {
+ i = moved[iii];
+ if (i == -1)
+ continue;
+
+ where[i] = tmp_where[i];
+
+ /* Make sure to update the vertex information */
+ if (htable[i] == 0) {
+ /* make sure you do the update */
+ htable[i] = 1;
+ update[nlupd++] = i;
+ }
+
+ /* Put the vertices adjacent to i into the update array */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = ladjncy[j];
+ if (htable[k] == 0) {
+ htable[k] = 1;
+ if (k<nvtxs)
+ update[nlupd++] = k;
+ else
+ supdate[nsupd++] = k;
+ }
+ }
+ nmoves++;
+ nswaps++;
+
+ /* check number of zero-gain moves */
+ for (k=0; k<rinfo[i].ndegrees; k++)
+ if (rinfo[i].degrees[k].edge == to)
+ break;
+
+ if (graph->pexadj[i+1]-graph->pexadj[i] > 0)
+ changed[nchanged++] = i;
+ }
+
+ /* Tell interested pe's the new where[] info for the interface vertices */
+ CommChangedInterfaceData(ctrl, graph, nchanged, changed, where,
+ swchanges, rwchanges, wspace->pv4);
+
+
+ IFSET(ctrl->dbglvl, DBG_RMOVEINFO,
+ rprintf(ctrl, "\t[%d %d], [%.4f], [%d %d %d]\n",
+ pass, c, badmaxpwgt[0],
+ GlobalSESum(ctrl, nmoves),
+ GlobalSESum(ctrl, nsupd),
+ GlobalSESum(ctrl, nlupd)));
+
+ /*-------------------------------------------------------------
+ / Time to communicate with processors to send the vertices
+ / whose degrees need to be update.
+ /-------------------------------------------------------------*/
+ /* Issue the receives first */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Irecv((void *)(rupdate+sendptr[i]), sendptr[i+1]-sendptr[i], IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ /* Issue the sends next. This needs some preporcessing */
+ for (i=0; i<nsupd; i++) {
+ htable[supdate[i]] = 0;
+ supdate[i] = graph->imap[supdate[i]];
+ }
+ iidxsort(nsupd, supdate);
+
+ for (j=i=0; i<nnbrs; i++) {
+ yourlastvtx = vtxdist[peind[i]+1];
+ for (k=j; k<nsupd && supdate[k] < yourlastvtx; k++);
+ MPI_Isend((void *)(supdate+j), k-j, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ j = k;
+ }
+
+ /* OK, now get into the loop waiting for the send/recv operations to finish */
+ MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+ for (i=0; i<nnbrs; i++)
+ MPI_Get_count(ctrl->statuses+i, IDX_DATATYPE, nupds_pe+i);
+ MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+
+
+ /*-------------------------------------------------------------
+ / Place the recieved to-be updated vertices into update[]
+ /-------------------------------------------------------------*/
+ for (i=0; i<nnbrs; i++) {
+ pe_updates = rupdate+sendptr[i];
+ for (j=0; j<nupds_pe[i]; j++) {
+ k = pe_updates[j];
+ if (htable[k-firstvtx] == 0) {
+ htable[k-firstvtx] = 1;
+ update[nlupd++] = k-firstvtx;
+ }
+ }
+ }
+
+
+ /*-------------------------------------------------------------
+ / Update the rinfo of the vertices in the update[] array
+ /-------------------------------------------------------------*/
+ for (ii=0; ii<nlupd; ii++) {
+ i = update[ii];
+ ASSERT(ctrl, htable[i] == 1);
+
+ htable[i] = 0;
+
+ mydomain = where[i];
+ myrinfo = rinfo+i;
+ tmp_myrinfo = tmp_rinfo+i;
+ my_edegrees = myrinfo->degrees;
+ your_edegrees = tmp_myrinfo->degrees;
+
+ graph->lmincut -= myrinfo->ed;
+ myrinfo->ndegrees = 0;
+ myrinfo->id = 0;
+ myrinfo->ed = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ yourdomain = where[ladjncy[j]];
+ if (mydomain != yourdomain) {
+ myrinfo->ed += adjwgt[j];
+
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (my_edegrees[k].edge == yourdomain) {
+ my_edegrees[k].ewgt += adjwgt[j];
+ your_edegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ my_edegrees[k].edge = yourdomain;
+ my_edegrees[k].ewgt = adjwgt[j];
+ your_edegrees[k].edge = yourdomain;
+ your_edegrees[k].ewgt = adjwgt[j];
+ myrinfo->ndegrees++;
+ }
+ ASSERT(ctrl, myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
+ ASSERT(ctrl, tmp_myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
+
+ }
+ else {
+ myrinfo->id += adjwgt[j];
+ }
+ }
+ graph->lmincut += myrinfo->ed;
+
+ tmp_myrinfo->id = myrinfo->id;
+ tmp_myrinfo->ed = myrinfo->ed;
+ tmp_myrinfo->ndegrees = myrinfo->ndegrees;
+ }
+
+ /* finally, sum-up the partition weights */
+ MPI_Allreduce((void *)lnpwgts, (void *)gnpwgts, nparts*ncon,
+ MPI_FLOAT, MPI_SUM, ctrl->comm);
+ }
+ graph->mincut = GlobalSESum(ctrl, graph->lmincut)/2;
+
+ if (graph->mincut == oldcut)
+ break;
+ }
+
+/*
+ gnswaps = GlobalSESum(ctrl, nswaps);
+ if (mype == 0)
+ printf("niters: %d, nswaps: %d\n", pass+1, gnswaps);
+*/
+
+ GKfree((void **)&badmaxpwgt, (void **)&update, (void **)&nupds_pe, (void **)&htable, LTERM);
+ GKfree((void **)&changed, (void **)&pperm, (void **)&perm, (void **)&moved, LTERM);
+ GKfree((void **)&tmp_where, (void **)&tmp_rinfo, (void **)&tmp_edegrees, LTERM);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->KWayTmr));
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwayfm.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwayfm.c
new file mode 100644
index 0000000..4d0849b
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwayfm.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mkwayfm.c
+ *
+ * This file contains code that performs the k-way refinement
+ *
+ * Started 3/1/96
+ * George
+ *
+ * $Id: kwayfm.c,v 1.3 2003/07/22 20:29:05 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+#define ProperSide(c, from, other) \
+ (((c) == 0 && (from)-(other) < 0) || ((c) == 1 && (from)-(other) > 0))
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void Moc_KWayFM(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace, int npasses)
+{
+ int h, i, ii, iii, j, k, c;
+ int pass, nvtxs, nedges, ncon;
+ int nmoves, nmoved, nswaps, nzgswaps;
+/* int gnswaps, gnzgswaps; */
+ int me, firstvtx, lastvtx, yourlastvtx;
+ int from, to = -1, oldto, oldcut, mydomain, yourdomain, imbalanced, overweight;
+ int npes = ctrl->npes, mype = ctrl->mype, nparts = ctrl->nparts;
+ int nlupd, nsupd, nnbrs, nchanged;
+ idxtype *xadj, *ladjncy, *adjwgt, *vtxdist;
+ idxtype *where, *tmp_where, *moved;
+ float *lnpwgts, *gnpwgts, *ognpwgts, *pgnpwgts, *movewgts, *overfill;
+ idxtype *update, *supdate, *rupdate, *pe_updates;
+ idxtype *changed, *perm, *pperm, *htable;
+ idxtype *peind, *recvptr, *sendptr;
+ KeyValueType *swchanges, *rwchanges;
+ RInfoType *rinfo, *myrinfo, *tmp_myrinfo, *tmp_rinfo;
+ EdgeType *tmp_edegrees, *my_edegrees, *your_edegrees;
+ float lbvec[MAXNCON], *nvwgt, *badmaxpwgt, *ubvec, *tpwgts, lbavg, ubavg;
+ int *nupds_pe;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->KWayTmr));
+
+ /*************************/
+ /* set up common aliases */
+ /*************************/
+ nvtxs = graph->nvtxs;
+ nedges = graph->nedges;
+ ncon = graph->ncon;
+
+ vtxdist = graph->vtxdist;
+ xadj = graph->xadj;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+
+ firstvtx = vtxdist[mype];
+ lastvtx = vtxdist[mype+1];
+
+ where = graph->where;
+ rinfo = graph->rinfo;
+ lnpwgts = graph->lnpwgts;
+ gnpwgts = graph->gnpwgts;
+ ubvec = ctrl->ubvec;
+ tpwgts = ctrl->tpwgts;
+
+ nnbrs = graph->nnbrs;
+ peind = graph->peind;
+ recvptr = graph->recvptr;
+ sendptr = graph->sendptr;
+
+ changed = idxmalloc(nvtxs, "KWR: changed");
+ rwchanges = wspace->pairs;
+ swchanges = rwchanges + recvptr[nnbrs];
+
+ /************************************/
+ /* set up important data structures */
+ /************************************/
+ perm = idxmalloc(nvtxs, "KWR: perm");
+ pperm = idxmalloc(nparts, "KWR: pperm");
+
+ update = idxmalloc(nvtxs, "KWR: update");
+ supdate = wspace->indices;
+ rupdate = supdate + recvptr[nnbrs];
+ nupds_pe = imalloc(npes, "KWR: nupds_pe");
+ htable = idxsmalloc(nvtxs+graph->nrecv, 0, "KWR: lhtable");
+ badmaxpwgt = fmalloc(nparts*ncon, "badmaxpwgt");
+
+ for (i=0; i<nparts; i++) {
+ for (h=0; h<ncon; h++) {
+ badmaxpwgt[i*ncon+h] = ubvec[h]*tpwgts[i*ncon+h];
+ }
+ }
+
+ movewgts = fmalloc(nparts*ncon, "KWR: movewgts");
+ ognpwgts = fmalloc(nparts*ncon, "KWR: ognpwgts");
+ pgnpwgts = fmalloc(nparts*ncon, "KWR: pgnpwgts");
+ overfill = fmalloc(nparts*ncon, "KWR: overfill");
+ moved = idxmalloc(nvtxs, "KWR: moved");
+ tmp_where = idxmalloc(nvtxs+graph->nrecv, "KWR: tmp_where");
+ tmp_rinfo = (RInfoType *)GKmalloc(sizeof(RInfoType)*nvtxs, "KWR: tmp_rinfo");
+ tmp_edegrees = (EdgeType *)GKmalloc(sizeof(EdgeType)*nedges, "KWR: tmp_edegrees");
+
+ idxcopy(nvtxs+graph->nrecv, where, tmp_where);
+ for (i=0; i<nvtxs; i++) {
+ tmp_rinfo[i].id = rinfo[i].id;
+ tmp_rinfo[i].ed = rinfo[i].ed;
+ tmp_rinfo[i].ndegrees = rinfo[i].ndegrees;
+ tmp_rinfo[i].degrees = tmp_edegrees+xadj[i];
+
+ for (j=0; j<rinfo[i].ndegrees; j++) {
+ tmp_rinfo[i].degrees[j].edge = rinfo[i].degrees[j].edge;
+ tmp_rinfo[i].degrees[j].ewgt = rinfo[i].degrees[j].ewgt;
+ }
+ }
+
+ nswaps = nzgswaps = 0;
+ /*********************************************************/
+ /* perform a small number of passes through the vertices */
+ /*********************************************************/
+ for (pass=0; pass<npasses; pass++) {
+ if (mype == 0)
+ RandomPermute(nparts, pperm, 1);
+ MPI_Bcast((void *)pperm, nparts, IDX_DATATYPE, 0, ctrl->comm);
+ FastRandomPermute(nvtxs, perm, 1);
+ oldcut = graph->mincut;
+
+ /* check to see if the partitioning is imbalanced */
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ ubavg = savg(ncon, ubvec);
+ lbavg = savg(ncon, lbvec);
+ imbalanced = (lbavg > ubavg) ? 1 : 0;
+
+ for (c=0; c<2; c++) {
+ scopy(ncon*nparts, gnpwgts, ognpwgts);
+ sset(ncon*nparts, 0.0, movewgts);
+ nmoved = 0;
+
+ /**********************************************/
+ /* PASS ONE -- record stats for desired moves */
+ /**********************************************/
+ for (iii=0; iii<nvtxs; iii++) {
+ i = perm[iii];
+ from = tmp_where[i];
+ nvwgt = graph->nvwgt+i*ncon;
+
+ for (h=0; h<ncon; h++)
+ if (fabs(nvwgt[h]-gnpwgts[from*ncon+h]) < SMALLFLOAT)
+ break;
+
+ if (h < ncon) {
+ continue;
+ }
+
+ /* check for a potential improvement */
+ if (tmp_rinfo[i].ed >= tmp_rinfo[i].id) {
+ my_edegrees = tmp_rinfo[i].degrees;
+
+ for (k=0; k<tmp_rinfo[i].ndegrees; k++) {
+ to = my_edegrees[k].edge;
+ if (ProperSide(c, pperm[from], pperm[to])) {
+ for (h=0; h<ncon; h++)
+ if (gnpwgts[to*ncon+h]+nvwgt[h] > badmaxpwgt[to*ncon+h] && nvwgt[h] > 0.0)
+ break;
+
+ if (h == ncon)
+ break;
+ }
+ }
+ oldto = to;
+
+ /* check if a subdomain was found that fits */
+ if (k < tmp_rinfo[i].ndegrees) {
+ for (j=k+1; j<tmp_rinfo[i].ndegrees; j++) {
+ to = my_edegrees[j].edge;
+ if (ProperSide(c, pperm[from], pperm[to])) {
+ for (h=0; h<ncon; h++)
+ if (gnpwgts[to*ncon+h]+nvwgt[h] > badmaxpwgt[to*ncon+h] && nvwgt[h] > 0.0)
+ break;
+
+ if (h == ncon) {
+ if (my_edegrees[j].ewgt > my_edegrees[k].ewgt ||
+ (my_edegrees[j].ewgt == my_edegrees[k].ewgt &&
+ IsHBalanceBetterTT(ncon,gnpwgts+oldto*ncon,gnpwgts+to*ncon,nvwgt,ubvec))){
+ k = j;
+ oldto = my_edegrees[k].edge;
+ }
+ }
+ }
+ }
+ to = oldto;
+
+ if (my_edegrees[k].ewgt > tmp_rinfo[i].id ||
+ (my_edegrees[k].ewgt == tmp_rinfo[i].id &&
+ (imbalanced || graph->level > 3 || iii % 8 == 0) &&
+ IsHBalanceBetterFT(ncon,gnpwgts+from*ncon,gnpwgts+to*ncon,nvwgt,ubvec))){
+
+ /****************************************/
+ /* Update tmp arrays of the moved vertex */
+ /****************************************/
+ tmp_where[i] = to;
+ moved[nmoved++] = i;
+ for (h=0; h<ncon; h++) {
+ lnpwgts[to*ncon+h] += nvwgt[h];
+ lnpwgts[from*ncon+h] -= nvwgt[h];
+ gnpwgts[to*ncon+h] += nvwgt[h];
+ gnpwgts[from*ncon+h] -= nvwgt[h];
+ movewgts[to*ncon+h] += nvwgt[h];
+ movewgts[from*ncon+h] -= nvwgt[h];
+ }
+
+ tmp_rinfo[i].ed += tmp_rinfo[i].id-my_edegrees[k].ewgt;
+ SWAP(tmp_rinfo[i].id, my_edegrees[k].ewgt, j);
+ if (my_edegrees[k].ewgt == 0) {
+ tmp_rinfo[i].ndegrees--;
+ my_edegrees[k].edge = my_edegrees[tmp_rinfo[i].ndegrees].edge;
+ my_edegrees[k].ewgt = my_edegrees[tmp_rinfo[i].ndegrees].ewgt;
+ }
+ else {
+ my_edegrees[k].edge = from;
+ }
+
+ /* Update the degrees of adjacent vertices */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ /* no need to bother about vertices on different pe's */
+ if (ladjncy[j] >= nvtxs)
+ continue;
+
+ me = ladjncy[j];
+ mydomain = tmp_where[me];
+
+ myrinfo = tmp_rinfo+me;
+ your_edegrees = myrinfo->degrees;
+
+ if (mydomain == from) {
+ INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
+ }
+ else {
+ if (mydomain == to) {
+ INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
+ }
+ }
+
+ /* Remove contribution from the .ed of 'from' */
+ if (mydomain != from) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == from) {
+ if (your_edegrees[k].ewgt == adjwgt[j]) {
+ myrinfo->ndegrees--;
+ your_edegrees[k].edge = your_edegrees[myrinfo->ndegrees].edge;
+ your_edegrees[k].ewgt = your_edegrees[myrinfo->ndegrees].ewgt;
+ }
+ else {
+ your_edegrees[k].ewgt -= adjwgt[j];
+ }
+ break;
+ }
+ }
+ }
+
+ /* Add contribution to the .ed of 'to' */
+ if (mydomain != to) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == to) {
+ your_edegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ your_edegrees[myrinfo->ndegrees].edge = to;
+ your_edegrees[myrinfo->ndegrees++].ewgt = adjwgt[j];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /******************************************/
+ /* Let processors know the subdomain wgts */
+ /* if all proposed moves commit. */
+ /******************************************/
+ MPI_Allreduce((void *)lnpwgts, (void *)pgnpwgts, nparts*ncon,
+ MPI_FLOAT, MPI_SUM, ctrl->comm);
+
+ /**************************/
+ /* compute overfill array */
+ /**************************/
+ overweight = 0;
+ for (j=0; j<nparts; j++) {
+ for (h=0; h<ncon; h++) {
+ if (pgnpwgts[j*ncon+h] > ognpwgts[j*ncon+h]) {
+ overfill[j*ncon+h] =
+ (pgnpwgts[j*ncon+h]-badmaxpwgt[j*ncon+h]) /
+ (pgnpwgts[j*ncon+h]-ognpwgts[j*ncon+h]);
+ }
+ else {
+ overfill[j*ncon+h] = 0.0;
+ }
+
+ overfill[j*ncon+h] = amax(overfill[j*ncon+h], 0.0);
+ overfill[j*ncon+h] *= movewgts[j*ncon+h];
+
+ if (overfill[j*ncon+h] > 0.0)
+ overweight = 1;
+
+ ASSERTP(ctrl, ognpwgts[j*ncon+h] <= badmaxpwgt[j*ncon+h] ||
+ pgnpwgts[j*ncon+h] <= ognpwgts[j*ncon+h],
+ (ctrl, "%.4f %.4f %.4f\n", ognpwgts[j*ncon+h],
+ badmaxpwgt[j*ncon+h], pgnpwgts[j*ncon+h]));
+ }
+ }
+
+ /****************************************************/
+ /* select moves to undo according to overfill array */
+ /****************************************************/
+ if (overweight == 1) {
+ for (iii=0; iii<nmoved; iii++) {
+ i = moved[iii];
+ oldto = tmp_where[i];
+ nvwgt = graph->nvwgt+i*ncon;
+ my_edegrees = tmp_rinfo[i].degrees;
+
+ for (k=0; k<tmp_rinfo[i].ndegrees; k++)
+ if (my_edegrees[k].edge == where[i])
+ break;
+
+ for (h=0; h<ncon; h++)
+ if (nvwgt[h] > 0.0 && overfill[oldto*ncon+h] > nvwgt[h]/4.0)
+ break;
+
+ /**********************************/
+ /* nullify this move if necessary */
+ /**********************************/
+ if (k != tmp_rinfo[i].ndegrees && h != ncon) {
+ moved[iii] = -1;
+ from = oldto;
+ to = where[i];
+
+ for (h=0; h<ncon; h++) {
+ overfill[oldto*ncon+h] = amax(overfill[oldto*ncon+h]-nvwgt[h], 0.0);
+ }
+
+ tmp_where[i] = to;
+ tmp_rinfo[i].ed += tmp_rinfo[i].id-my_edegrees[k].ewgt;
+ SWAP(tmp_rinfo[i].id, my_edegrees[k].ewgt, j);
+ if (my_edegrees[k].ewgt == 0) {
+ tmp_rinfo[i].ndegrees--;
+ my_edegrees[k].edge = my_edegrees[tmp_rinfo[i].ndegrees].edge;
+ my_edegrees[k].ewgt = my_edegrees[tmp_rinfo[i].ndegrees].ewgt;
+ }
+ else {
+ my_edegrees[k].edge = from;
+ }
+
+ for (h=0; h<ncon; h++) {
+ lnpwgts[to*ncon+h] += nvwgt[h];
+ lnpwgts[from*ncon+h] -= nvwgt[h];
+ }
+
+ /* Update the degrees of adjacent vertices */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ /* no need to bother about vertices on different pe's */
+ if (ladjncy[j] >= nvtxs)
+ continue;
+
+ me = ladjncy[j];
+ mydomain = tmp_where[me];
+
+ myrinfo = tmp_rinfo+me;
+ your_edegrees = myrinfo->degrees;
+
+ if (mydomain == from) {
+ INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
+ }
+ else {
+ if (mydomain == to) {
+ INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
+ }
+ }
+
+ /* Remove contribution from the .ed of 'from' */
+ if (mydomain != from) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == from) {
+ if (your_edegrees[k].ewgt == adjwgt[j]) {
+ myrinfo->ndegrees--;
+ your_edegrees[k].edge = your_edegrees[myrinfo->ndegrees].edge;
+ your_edegrees[k].ewgt = your_edegrees[myrinfo->ndegrees].ewgt;
+ }
+ else {
+ your_edegrees[k].ewgt -= adjwgt[j];
+ }
+ break;
+ }
+ }
+ }
+
+ /* Add contribution to the .ed of 'to' */
+ if (mydomain != to) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (your_edegrees[k].edge == to) {
+ your_edegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ your_edegrees[myrinfo->ndegrees].edge = to;
+ your_edegrees[myrinfo->ndegrees++].ewgt = adjwgt[j];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*************************************************/
+ /* PASS TWO -- commit the remainder of the moves */
+ /*************************************************/
+ nlupd = nsupd = nmoves = nchanged = 0;
+ for (iii=0; iii<nmoved; iii++) {
+ i = moved[iii];
+ if (i == -1)
+ continue;
+
+ where[i] = tmp_where[i];
+
+ /* Make sure to update the vertex information */
+ if (htable[i] == 0) {
+ /* make sure you do the update */
+ htable[i] = 1;
+ update[nlupd++] = i;
+ }
+
+ /* Put the vertices adjacent to i into the update array */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = ladjncy[j];
+ if (htable[k] == 0) {
+ htable[k] = 1;
+ if (k<nvtxs)
+ update[nlupd++] = k;
+ else
+ supdate[nsupd++] = k;
+ }
+ }
+ nmoves++;
+ nswaps++;
+
+ /* check number of zero-gain moves */
+ for (k=0; k<rinfo[i].ndegrees; k++)
+ if (rinfo[i].degrees[k].edge == to)
+ break;
+ if (rinfo[i].id == rinfo[i].degrees[k].ewgt)
+ nzgswaps++;
+
+ if (graph->pexadj[i+1]-graph->pexadj[i] > 0)
+ changed[nchanged++] = i;
+ }
+
+ /* Tell interested pe's the new where[] info for the interface vertices */
+ CommChangedInterfaceData(ctrl, graph, nchanged, changed, where,
+ swchanges, rwchanges, wspace->pv4);
+
+
+ IFSET(ctrl->dbglvl, DBG_RMOVEINFO,
+ rprintf(ctrl, "\t[%d %d], [%.4f], [%d %d %d]\n",
+ pass, c, badmaxpwgt[0],
+ GlobalSESum(ctrl, nmoves),
+ GlobalSESum(ctrl, nsupd),
+ GlobalSESum(ctrl, nlupd)));
+
+ /*-------------------------------------------------------------
+ / Time to communicate with processors to send the vertices
+ / whose degrees need to be update.
+ /-------------------------------------------------------------*/
+ /* Issue the receives first */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Irecv((void *)(rupdate+sendptr[i]), sendptr[i+1]-sendptr[i], IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ /* Issue the sends next. This needs some preporcessing */
+ for (i=0; i<nsupd; i++) {
+ htable[supdate[i]] = 0;
+ supdate[i] = graph->imap[supdate[i]];
+ }
+ iidxsort(nsupd, supdate);
+
+ for (j=i=0; i<nnbrs; i++) {
+ yourlastvtx = vtxdist[peind[i]+1];
+ for (k=j; k<nsupd && supdate[k] < yourlastvtx; k++);
+ MPI_Isend((void *)(supdate+j), k-j, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ j = k;
+ }
+
+ /* OK, now get into the loop waiting for the send/recv operations to finish */
+ MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+ for (i=0; i<nnbrs; i++)
+ MPI_Get_count(ctrl->statuses+i, IDX_DATATYPE, nupds_pe+i);
+ MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+
+
+ /*-------------------------------------------------------------
+ / Place the recieved to-be updated vertices into update[]
+ /-------------------------------------------------------------*/
+ for (i=0; i<nnbrs; i++) {
+ pe_updates = rupdate+sendptr[i];
+ for (j=0; j<nupds_pe[i]; j++) {
+ k = pe_updates[j];
+ if (htable[k-firstvtx] == 0) {
+ htable[k-firstvtx] = 1;
+ update[nlupd++] = k-firstvtx;
+ }
+ }
+ }
+
+
+ /*-------------------------------------------------------------
+ / Update the rinfo of the vertices in the update[] array
+ /-------------------------------------------------------------*/
+ for (ii=0; ii<nlupd; ii++) {
+ i = update[ii];
+ ASSERT(ctrl, htable[i] == 1);
+
+ htable[i] = 0;
+
+ mydomain = where[i];
+ myrinfo = rinfo+i;
+ tmp_myrinfo = tmp_rinfo+i;
+ my_edegrees = myrinfo->degrees;
+ your_edegrees = tmp_myrinfo->degrees;
+
+ graph->lmincut -= myrinfo->ed;
+ myrinfo->ndegrees = 0;
+ myrinfo->id = 0;
+ myrinfo->ed = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ yourdomain = where[ladjncy[j]];
+ if (mydomain != yourdomain) {
+ myrinfo->ed += adjwgt[j];
+
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (my_edegrees[k].edge == yourdomain) {
+ my_edegrees[k].ewgt += adjwgt[j];
+ your_edegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ my_edegrees[k].edge = yourdomain;
+ my_edegrees[k].ewgt = adjwgt[j];
+ your_edegrees[k].edge = yourdomain;
+ your_edegrees[k].ewgt = adjwgt[j];
+ myrinfo->ndegrees++;
+ }
+ ASSERT(ctrl, myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
+ ASSERT(ctrl, tmp_myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
+
+ }
+ else {
+ myrinfo->id += adjwgt[j];
+ }
+ }
+ graph->lmincut += myrinfo->ed;
+
+ tmp_myrinfo->id = myrinfo->id;
+ tmp_myrinfo->ed = myrinfo->ed;
+ tmp_myrinfo->ndegrees = myrinfo->ndegrees;
+ }
+
+ /* finally, sum-up the partition weights */
+ MPI_Allreduce((void *)lnpwgts, (void *)gnpwgts, nparts*ncon,
+ MPI_FLOAT, MPI_SUM, ctrl->comm);
+ }
+ graph->mincut = GlobalSESum(ctrl, graph->lmincut)/2;
+
+ if (graph->mincut == oldcut)
+ break;
+ }
+
+/*
+ gnswaps = GlobalSESum(ctrl, nswaps);
+ gnzgswaps = GlobalSESum(ctrl, nzgswaps);
+ if (mype == 0)
+ printf("niters: %d, nswaps: %d, nzgswaps: %d\n", pass+1, gnswaps, gnzgswaps);
+*/
+
+ GKfree((void **)&badmaxpwgt, (void **)&update, (void **)&nupds_pe, (void **)&htable, LTERM);
+ GKfree((void **)&changed, (void **)&pperm, (void **)&perm, (void **)&moved, LTERM);
+ GKfree((void **)&pgnpwgts, (void **)&ognpwgts, (void **)&overfill, (void **)&movewgts, LTERM);
+ GKfree((void **)&tmp_where, (void **)&tmp_rinfo, (void **)&tmp_edegrees, LTERM);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->KWayTmr));
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwayrefine.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwayrefine.c
new file mode 100644
index 0000000..e4b776e
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/kwayrefine.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * medge_refine.c
+ *
+ * This file contains code that performs the k-way refinement
+ *
+ * Started 3/1/96
+ * George
+ *
+ * $Id: kwayrefine.c,v 1.2 2003/07/21 17:18:49 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+#define ProperSide(c, from, other) \
+ (((c) == 0 && (from)-(other) < 0) || ((c) == 1 && (from)-(other) > 0))
+
+/*************************************************************************
+* This function projects a partition.
+**************************************************************************/
+void Moc_ProjectPartition(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, nvtxs, nnbrs = -1, firstvtx, cfirstvtx;
+ idxtype *match, *cmap, *where, *cwhere;
+ idxtype *peind, *slens = NULL, *rlens = NULL;
+ KeyValueType *rcand, *scand = NULL;
+ GraphType *cgraph;
+
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
+
+ cgraph = graph->coarser;
+ cwhere = cgraph->where;
+ cfirstvtx = cgraph->vtxdist[ctrl->mype];
+
+ nvtxs = graph->nvtxs;
+ match = graph->match;
+ cmap = graph->cmap;
+ where = graph->where = idxmalloc(nvtxs+graph->nrecv, "ProjectPartition: graph->where");
+ firstvtx = graph->vtxdist[ctrl->mype];
+
+
+ if (graph->match_type == MATCH_GLOBAL) { /* Only if global matching is on */
+ /*------------------------------------------------------------
+ / Start the transmission of the remote where information
+ /------------------------------------------------------------*/
+ scand = wspace->pairs;
+ nnbrs = graph->nnbrs;
+ peind = graph->peind;
+ slens = graph->slens;
+ rlens = graph->rlens;
+ rcand = graph->rcand;
+
+ /* Issue the receives first */
+ for (i=0; i<nnbrs; i++) {
+ if (slens[i+1]-slens[i] > 0) /* Issue a receive only if you are getting something */
+ MPI_Irecv((void *)(scand+slens[i]), 2*(slens[i+1]-slens[i]), IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+#ifdef DEBUG_PROJECT
+ PrintPairs(ctrl, rlens[nnbrs], rcand, "rcand");
+#endif
+
+ /* Put the where[rcand[].key] into the val field */
+ for (i=0; i<rlens[nnbrs]; i++) {
+ ASSERT(ctrl, rcand[i].val >= 0 && rcand[i].val < cgraph->nvtxs);
+ rcand[i].val = cwhere[rcand[i].val];
+ }
+
+#ifdef DEBUG_PROJECT
+ PrintPairs(ctrl, rlens[nnbrs], rcand, "rcand");
+ PrintVector(ctrl, nvtxs, firstvtx, cmap, "cmap");
+#endif
+
+ /* Issue the sends next */
+ for (i=0; i<nnbrs; i++) {
+ if (rlens[i+1]-rlens[i] > 0) /* Issue a send only if you are sending something */
+ MPI_Isend((void *)(rcand+rlens[i]), 2*(rlens[i+1]-rlens[i]), IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ }
+ }
+
+ /*------------------------------------------------------------
+ / Project local vertices first
+ /------------------------------------------------------------*/
+ for (i=0; i<nvtxs; i++) {
+ if (match[i] >= KEEP_BIT) {
+ ASSERT(ctrl, cmap[i]-cfirstvtx>=0 && cmap[i]-cfirstvtx<cgraph->nvtxs);
+ where[i] = cwhere[cmap[i]-cfirstvtx];
+ }
+ }
+
+ if (graph->match_type == MATCH_GLOBAL) { /* Only if global matching is on */
+ /*------------------------------------------------------------
+ / Wait for the nonblocking operations to finish
+ /------------------------------------------------------------*/
+ for (i=0; i<nnbrs; i++) {
+ if (rlens[i+1]-rlens[i] > 0)
+ MPI_Wait(ctrl->sreq+i, &ctrl->status);
+ }
+ for (i=0; i<nnbrs; i++) {
+ if (slens[i+1]-slens[i] > 0)
+ MPI_Wait(ctrl->rreq+i, &ctrl->status);
+ }
+
+#ifdef DEBUG_PROJECT
+ PrintPairs(ctrl, slens[nnbrs], scand, "scand");
+#endif
+
+ /*------------------------------------------------------------
+ / Project received vertices now
+ /------------------------------------------------------------*/
+ for (i=0; i<slens[nnbrs]; i++) {
+ ASSERTP(ctrl, scand[i].key-firstvtx>=0 && scand[i].key-firstvtx<graph->nvtxs, (ctrl, "%d %d %d\n", scand[i].key, firstvtx, graph->nvtxs));
+ where[scand[i].key-firstvtx] = scand[i].val;
+ }
+ }
+
+
+ FreeGraph(graph->coarser);
+ graph->coarser = NULL;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
+}
+
+
+
+/*************************************************************************
+* This function computes the initial id/ed
+**************************************************************************/
+void Moc_ComputePartitionParams(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int h, i, j, k;
+ int nvtxs, ncon;
+ int firstvtx, lastvtx;
+ idxtype *xadj, *ladjncy, *adjwgt, *vtxdist;
+ float *lnpwgts, *gnpwgts;
+ idxtype *where, *swhere, *rwhere;
+ RInfoType *rinfo, *myrinfo;
+ EdgeType *edegrees;
+ int me, other;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->KWayInitTmr));
+
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+
+ vtxdist = graph->vtxdist;
+ xadj = graph->xadj;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+
+ where = graph->where;
+ rinfo = graph->rinfo = (RInfoType *)GKmalloc(sizeof(RInfoType)*nvtxs, "CPP: rinfo");
+ lnpwgts = graph->lnpwgts = fmalloc(ctrl->nparts*ncon, "CPP: lnpwgts");
+ gnpwgts = graph->gnpwgts = fmalloc(ctrl->nparts*ncon, "CPP: gnpwgts");
+
+ sset(ctrl->nparts*ncon, 0, lnpwgts);
+
+ firstvtx = vtxdist[ctrl->mype];
+ lastvtx = vtxdist[ctrl->mype+1];
+
+ /*------------------------------------------------------------
+ / Send/Receive the where information of interface vertices
+ /------------------------------------------------------------*/
+ swhere = wspace->indices;
+ rwhere = where + nvtxs;
+
+ CommInterfaceData(ctrl, graph, where, swhere, rwhere);
+
+#ifdef DEBUG_COMPUTEPPARAM
+ PrintVector(ctrl, nvtxs, firstvtx, where, "where");
+#endif
+
+ ASSERT(ctrl, wspace->nlarge >= xadj[nvtxs]);
+
+ /*------------------------------------------------------------
+ / Compute now the id/ed degrees
+ /------------------------------------------------------------*/
+ graph->lmincut = 0;
+ for (i=0; i<nvtxs; i++) {
+ me = where[i];
+ myrinfo = rinfo+i;
+
+ for (h=0; h<ncon; h++)
+ lnpwgts[me*ncon+h] += graph->nvwgt[i*ncon+h];
+
+ myrinfo->degrees = wspace->degrees + xadj[i];
+ myrinfo->ndegrees = myrinfo->id = myrinfo->ed = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ if (me == where[ladjncy[j]])
+ myrinfo->id += adjwgt[j];
+ else
+ myrinfo->ed += adjwgt[j];
+ }
+
+
+ if (myrinfo->ed > 0) { /* Time to do some serious work */
+ graph->lmincut += myrinfo->ed;
+ edegrees = myrinfo->degrees;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ other = where[ladjncy[j]];
+ if (me != other) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (edegrees[k].edge == other) {
+ edegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ edegrees[k].edge = other;
+ edegrees[k].ewgt = adjwgt[j];
+ myrinfo->ndegrees++;
+ }
+ ASSERT(ctrl, myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
+ }
+ }
+ }
+ }
+
+#ifdef DEBUG_COMPUTEPPARAM
+ PrintVector(ctrl, ctrl->nparts*ncon, 0, lnpwgts, "lnpwgts");
+#endif
+
+ /* Finally, sum-up the partition weights */
+ MPI_Allreduce((void *)lnpwgts, (void *)gnpwgts, ctrl->nparts*ncon, MPI_FLOAT, MPI_SUM, ctrl->comm);
+
+ graph->mincut = GlobalSESum(ctrl, graph->lmincut)/2;
+
+#ifdef DEBUG_COMPUTEPPARAM
+ PrintVector(ctrl, ctrl->nparts*ncon, 0, gnpwgts, "gnpwgts");
+#endif
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->KWayInitTmr));
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/lmatch.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/lmatch.c
new file mode 100644
index 0000000..d8601ef
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/lmatch.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * coarsen.c
+ *
+ * This file contains code that finds a matching and performs the coarsening
+ *
+ * Started 2/22/96
+ * George
+ *
+ * $Id: lmatch.c,v 1.2 2003/07/21 17:18:50 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function finds a HEM matching between local vertices only
+**************************************************************************/
+void Mc_LocalMatch_HEM(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int h, i, ii, j, k;
+ int nvtxs, ncon, cnvtxs, firstvtx, maxi, maxidx, edge;
+ idxtype *xadj, *ladjncy, *adjwgt, *vtxdist, *home, *myhome, *shome, *rhome;
+ idxtype *perm, *match;
+ float maxnvwgt, *nvwgt;
+
+ graph->match_type = MATCH_LOCAL;
+ maxnvwgt = 1.0/((float)(ctrl->nparts)*MAXVWGT_FACTOR);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ nvwgt = graph->nvwgt;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ home = graph->home;
+
+ vtxdist = graph->vtxdist;
+ firstvtx = vtxdist[ctrl->mype];
+
+ match = graph->match = idxmalloc(nvtxs+graph->nrecv, "HEM_Match: match");
+ myhome = idxsmalloc(nvtxs+graph->nrecv, UNMATCHED, "HEM_Match: myhome");
+
+ idxset(nvtxs, UNMATCHED, match);
+ idxset(graph->nrecv, 0, match+nvtxs); /* Easy way to handle remote vertices */
+
+ /*------------------------------------------------------------
+ / Send/Receive the home information of interface vertices
+ /------------------------------------------------------------*/
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+ idxcopy(nvtxs, home, myhome);
+ shome = wspace->indices;
+ rhome = myhome + nvtxs;
+ CommInterfaceData(ctrl, graph, myhome, shome, rhome);
+ }
+
+ /*************************************************************
+ * Go now and find a local matching
+ *************************************************************/
+ perm = wspace->indices;
+ FastRandomPermute(nvtxs, perm, 1);
+ cnvtxs = 0;
+ for (ii=0; ii<nvtxs; ii++) {
+ i = perm[ii];
+ if (match[i] == UNMATCHED) {
+ maxidx = maxi = -1;
+
+ /* Find a heavy-edge matching, if the weight of the vertex is OK */
+ for (h=0; h<ncon; h++)
+ if (nvwgt[i*ncon+h] > maxnvwgt)
+ break;
+
+ if (h == ncon) {
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ edge = ladjncy[j];
+
+ /* match only with local vertices */
+ if (myhome[edge] != myhome[i] || edge >= nvtxs)
+ continue;
+
+ for (h=0; h<ncon; h++)
+ if (nvwgt[edge*ncon+h] > maxnvwgt)
+ break;
+
+ if (h == ncon) {
+ if (match[edge] == UNMATCHED &&
+ (maxi == -1 ||
+ adjwgt[maxi] < adjwgt[j] ||
+ (adjwgt[maxi] == adjwgt[j] &&
+ BetterVBalance(ncon,nvwgt+i*ncon,nvwgt+maxidx*ncon,nvwgt+edge*ncon) >= 0))) {
+ maxi = j;
+ maxidx = edge;
+ }
+ }
+ }
+ }
+
+ if (maxi != -1) {
+ k = ladjncy[maxi];
+ if (i <= k) {
+ match[i] = firstvtx+k + KEEP_BIT;
+ match[k] = firstvtx+i;
+ }
+ else {
+ match[i] = firstvtx+k;
+ match[k] = firstvtx+i + KEEP_BIT;
+ }
+ }
+ else {
+ match[i] = (firstvtx+i) + KEEP_BIT;
+ }
+ cnvtxs++;
+ }
+ }
+
+ CommInterfaceData(ctrl, graph, match, wspace->indices, match+nvtxs);
+ GKfree((void **)(&myhome), LTERM);
+
+#ifdef DEBUG_MATCH
+ PrintVector2(ctrl, nvtxs, firstvtx, match, "Match1");
+#endif
+
+
+ if (ctrl->dbglvl&DBG_MATCHINFO) {
+ PrintVector2(ctrl, nvtxs, firstvtx, match, "Match");
+ myprintf(ctrl, "Cnvtxs: %d\n", cnvtxs);
+ rprintf(ctrl, "Done with matching...\n");
+ }
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr));
+ Mc_Local_CreateCoarseGraph(ctrl, graph, wspace, cnvtxs);
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr));
+
+}
+
+
+
+
+
+/*************************************************************************
+* This function creates the coarser graph
+**************************************************************************/
+void Mc_Local_CreateCoarseGraph(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace, int cnvtxs)
+{
+ int h, i, j, k, l;
+ int nvtxs, ncon, nedges, firstvtx, cfirstvtx;
+ int npes=ctrl->npes, mype=ctrl->mype;
+ int cnedges, v, u;
+ idxtype *xadj, *vwgt, *vsize, *ladjncy, *adjwgt, *vtxdist, *where, *home;
+ idxtype *match, *cmap;
+ idxtype *cxadj, *cvwgt, *cvsize = NULL, *cadjncy, *cadjwgt, *cvtxdist, *chome = NULL, *cwhere = NULL;
+ float *cnvwgt;
+ GraphType *cgraph;
+ int mask=(1<<13)-1, htable[8192], htableidx[8192];
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+
+ vtxdist = graph->vtxdist;
+ xadj = graph->xadj;
+ vwgt = graph->vwgt;
+ home = graph->home;
+ vsize = graph->vsize;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ match = graph->match;
+
+ firstvtx = vtxdist[mype];
+
+ cmap = graph->cmap = idxmalloc(nvtxs+graph->nrecv, "CreateCoarseGraph: cmap");
+
+ /* Initialize the coarser graph */
+ cgraph = CreateGraph();
+ cgraph->nvtxs = cnvtxs;
+ cgraph->level = graph->level+1;
+ cgraph->ncon = ncon;
+
+ cgraph->finer = graph;
+ graph->coarser = cgraph;
+
+
+ /*************************************************************
+ * Obtain the vtxdist of the coarser graph
+ **************************************************************/
+ cvtxdist = cgraph->vtxdist = idxmalloc(npes+1, "CreateCoarseGraph: cvtxdist");
+ cvtxdist[npes] = cnvtxs; /* Use last position in the cvtxdist as a temp buffer */
+
+ MPI_Allgather((void *)(cvtxdist+npes), 1, IDX_DATATYPE, (void *)cvtxdist, 1, IDX_DATATYPE, ctrl->comm);
+
+ MAKECSR(i, npes, cvtxdist);
+
+ cgraph->gnvtxs = cvtxdist[npes];
+
+#ifdef DEBUG_CONTRACT
+ PrintVector(ctrl, npes+1, 0, cvtxdist, "cvtxdist");
+#endif
+
+
+ /*************************************************************
+ * Construct the cmap vector
+ **************************************************************/
+ cfirstvtx = cvtxdist[mype];
+
+ /* Create the cmap of what you know so far locally */
+ cnvtxs = 0;
+ for (i=0; i<nvtxs; i++) {
+ if (match[i] >= KEEP_BIT) {
+ k = match[i] - KEEP_BIT;
+ if (k<firstvtx+i)
+ continue; /* i has been matched via the (k,i) side */
+
+ cmap[i] = cfirstvtx + cnvtxs++;
+ if (k != firstvtx+i) {
+ cmap[k-firstvtx] = cmap[i];
+ match[k-firstvtx] += KEEP_BIT; /* Add the KEEP_BIT to simplify coding */
+ }
+ }
+ }
+
+ CommInterfaceData(ctrl, graph, cmap, wspace->indices, cmap+nvtxs);
+
+
+#ifdef DEBUG_CONTRACT
+ PrintVector(ctrl, nvtxs, firstvtx, cmap, "Cmap");
+#endif
+
+
+
+ /*************************************************************
+ * Finally, create the coarser graph
+ **************************************************************/
+ /* Allocate memory for the coarser graph, and fire up coarsening */
+ cxadj = cgraph->xadj = idxmalloc(cnvtxs+1, "CreateCoarserGraph: cxadj");
+ cvwgt = cgraph->vwgt = idxmalloc(cnvtxs*ncon, "CreateCoarserGraph: cvwgt");
+ cnvwgt = cgraph->nvwgt = fmalloc(cnvtxs*ncon, "CreateCoarserGraph: cnvwgt");
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION)
+ chome = cgraph->home = idxmalloc(cnvtxs, "CreateCoarserGraph: chome");
+ if (vsize != NULL)
+ cvsize = cgraph->vsize = idxmalloc(cnvtxs, "CreateCoarserGraph: cvsize");
+ if (where != NULL)
+ cwhere = cgraph->where = idxmalloc(cnvtxs, "CreateCoarserGraph: cwhere");
+ cadjncy = idxmalloc(2*graph->nedges, "CreateCoarserGraph: cadjncy");
+ cadjwgt = cadjncy+graph->nedges;
+
+ iset(8192, -1, htable);
+
+ cxadj[0] = cnvtxs = cnedges = 0;
+ for (i=0; i<nvtxs; i++) {
+ v = firstvtx+i;
+ u = match[i]-KEEP_BIT;
+
+ if (v > u)
+ continue; /* I have already collapsed it as (u,v) */
+
+ /* Collapse the v vertex first, which you know that is local */
+ for (h=0; h<ncon; h++)
+ cvwgt[cnvtxs*ncon+h] = vwgt[i*ncon+h];
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION)
+ chome[cnvtxs] = home[i];
+ if (vsize != NULL)
+ cvsize[cnvtxs] = vsize[i];
+ if (where != NULL)
+ cwhere[cnvtxs] = where[i];
+ nedges = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = cmap[ladjncy[j]];
+ if (k != cfirstvtx+cnvtxs) { /* If this is not an internal edge */
+ l = k&mask;
+ if (htable[l] == -1) { /* Seeing this for first time */
+ htable[l] = k;
+ htableidx[l] = cnedges+nedges;
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = adjwgt[j];
+ }
+ else if (htable[l] == k) {
+ cadjwgt[htableidx[l]] += adjwgt[j];
+ }
+ else { /* Now you have to go and do a search. Expensive case */
+ for (l=0; l<nedges; l++) {
+ if (cadjncy[cnedges+l] == k)
+ break;
+ }
+ if (l < nedges) {
+ cadjwgt[cnedges+l] += adjwgt[j];
+ }
+ else {
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = adjwgt[j];
+ }
+ }
+ }
+ }
+
+ /* Collapse the u vertex next */
+ if (v != u) {
+ u -= firstvtx;
+ for (h=0; h<ncon; h++)
+ cvwgt[cnvtxs*ncon+h] += vwgt[u*ncon+h];
+ if (vsize != NULL)
+ cvsize[cnvtxs] += vsize[u];
+ if (where != NULL && cwhere[cnvtxs] != where[u])
+ myprintf(ctrl, "Something went wrong with the where local matching! %d %d\n", cwhere[cnvtxs], where[u]);
+
+ for (j=xadj[u]; j<xadj[u+1]; j++) {
+ k = cmap[ladjncy[j]];
+ if (k != cfirstvtx+cnvtxs) { /* If this is not an internal edge */
+ l = k&mask;
+ if (htable[l] == -1) { /* Seeing this for first time */
+ htable[l] = k;
+ htableidx[l] = cnedges+nedges;
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = adjwgt[j];
+ }
+ else if (htable[l] == k) {
+ cadjwgt[htableidx[l]] += adjwgt[j];
+ }
+ else { /* Now you have to go and do a search. Expensive case */
+ for (l=0; l<nedges; l++) {
+ if (cadjncy[cnedges+l] == k)
+ break;
+ }
+ if (l < nedges) {
+ cadjwgt[cnedges+l] += adjwgt[j];
+ }
+ else {
+ cadjncy[cnedges+nedges] = k;
+ cadjwgt[cnedges+nedges++] = adjwgt[j];
+ }
+ }
+ }
+ }
+ }
+
+ cnedges += nedges;
+ for (j=cxadj[cnvtxs]; j<cnedges; j++)
+ htable[cadjncy[j]&mask] = -1; /* reset the htable */
+ cxadj[++cnvtxs] = cnedges;
+ }
+
+ cgraph->nedges = cnedges;
+
+ for (j=0; j<cnvtxs; j++)
+ for (h=0; h<ncon; h++)
+ cgraph->nvwgt[j*ncon+h] = (float)(cvwgt[j*ncon+h])/(float)(ctrl->tvwgts[h]);
+
+ cgraph->adjncy = idxmalloc(cnedges, "CreateCoarserGraph: cadjncy");
+ cgraph->adjwgt = idxmalloc(cnedges, "CreateCoarserGraph: cadjwgt");
+ idxcopy(cnedges, cadjncy, cgraph->adjncy);
+ idxcopy(cnedges, cadjwgt, cgraph->adjwgt);
+ GKfree((void **)&cadjncy, (void **)&graph->where, LTERM); /* Note that graph->where works fine even if it is NULL */
+
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/macros.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/macros.h
new file mode 100644
index 0000000..31861f7
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/macros.h
@@ -0,0 +1,163 @@
+/*
+ * 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.8 2003/07/21 19:11:46 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 icopy(n, a, b) memcpy((b), (a), sizeof(int)*(n))
+#define scopy(n, a, b) memcpy((b), (a), sizeof(float)*(n))
+#define idxcopy(n, a, b) memcpy((b), (a), sizeof(idxtype)*(n))
+
+#define HASHFCT(key, size) ((key)%(size))
+
+
+/*************************************************************************
+* Timer macros
+**************************************************************************/
+#define cleartimer(tmr) (tmr = 0.0)
+#define starttimer(tmr) (tmr -= MPI_Wtime())
+#define stoptimer(tmr) (tmr += MPI_Wtime())
+#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)
+
+
+#define SHIFTCSR(i, n, a) \
+ do { \
+ for (i=n; i>0; i--) a[i] = a[i-1]; \
+ a[0] = 0; \
+ } while(0)
+
+
+
+#ifdef DEBUG
+# define ASSERT(ctrl, expr) \
+ if (!(expr)) { \
+ myprintf(ctrl, "***ASSERTION failed on line %d of file %s: " #expr "\n", \
+ __LINE__, __FILE__); \
+ abort(); \
+ }
+#else
+# define ASSERT(ctrl, expr) ;
+#endif
+
+#ifdef DEBUG
+# define ASSERTP(ctrl, expr, msg) \
+ if (!(expr)) { \
+ myprintf(ctrl, "***ASSERTION failed on line %d of file %s:" #expr "\n", \
+ __LINE__, __FILE__); \
+ myprintf msg ; \
+ abort(); \
+ }
+#else
+# define ASSERTP(ctrl, expr,msg) ;
+#endif
+
+#ifdef DEBUGS
+# define ASSERTS(expr) \
+ if (!(expr)) { \
+ printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \
+ __LINE__, __FILE__); \
+ abort(); \
+ }
+#else
+# define ASSERTS(expr) ;
+#endif
+
+#ifdef DEBUGS
+# define ASSERTSP(expr, msg) \
+ if (!(expr)) { \
+ printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \
+ __LINE__, __FILE__); \
+ printf msg ; \
+ abort(); \
+ }
+#else
+# define ASSERTSP(expr, msg) ;
+#endif
+
+/*************************************************************************
+ * * These macros insert and remove nodes from the boundary list
+ * **************************************************************************/
+#define BNDInsert(nbnd, bndind, bndptr, vtx) \
+ do { \
+ bndind[nbnd] = vtx; \
+ bndptr[vtx] = nbnd++;\
+ } while(0)
+
+#define BNDDelete(nbnd, bndind, bndptr, vtx) \
+ do { \
+ bndind[bndptr[vtx]] = bndind[--nbnd]; \
+ bndptr[bndind[nbnd]] = bndptr[vtx]; \
+ bndptr[vtx] = -1; \
+ } while(0)
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/match.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/match.c
new file mode 100644
index 0000000..89bfa62
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/match.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mmatch.c
+ *
+ * This file contains code that finds a matching
+ *
+ * Started 2/22/96
+ * George
+ *
+ * $Id: match.c,v 1.2 2003/07/21 17:18:50 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function finds a matching
+**************************************************************************/
+void Moc_GlobalMatch_Balance(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int h, i, ii, j, k;
+ int nnbrs, nvtxs, ncon, cnvtxs, firstvtx, lastvtx, maxi, maxidx, nkept;
+ int otherlastvtx, nrequests, nchanged, pass, nmatched, wside;
+ idxtype *xadj, *ladjncy, *adjwgt, *vtxdist, *home, *myhome, *shome, *rhome;
+ idxtype *match, *rmatch, *smatch;
+ idxtype *peind, *sendptr, *recvptr;
+ idxtype *perm, *iperm, *nperm, *changed;
+ float *nvwgt, maxnvwgt;
+ int *nreqs_pe;
+ KeyValueType *match_requests, *match_granted, *pe_requests;
+
+ maxnvwgt = 1.0/((float)(ctrl->nparts)*MAXNVWGT_FACTOR);
+
+ graph->match_type = MATCH_GLOBAL;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ home = graph->home;
+ nvwgt = graph->nvwgt;
+
+ vtxdist = graph->vtxdist;
+ firstvtx = vtxdist[ctrl->mype];
+ lastvtx = vtxdist[ctrl->mype+1];
+
+ match = graph->match = idxsmalloc(nvtxs+graph->nrecv, UNMATCHED, "HEM_Match: match");
+ myhome = idxsmalloc(nvtxs+graph->nrecv, UNMATCHED, "HEM_Match: myhome");
+
+ /*------------------------------------------------------------
+ / Send/Receive the home information of interface vertices
+ /------------------------------------------------------------*/
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+ idxcopy(nvtxs, home, myhome);
+ shome = wspace->indices;
+ rhome = myhome + nvtxs;
+ CommInterfaceData(ctrl, graph, myhome, shome, rhome);
+ }
+
+ nnbrs = graph->nnbrs;
+ peind = graph->peind;
+ sendptr = graph->sendptr;
+ recvptr = graph->recvptr;
+
+ /* Use wspace->indices as the tmp space for matching info of the boundary
+ * vertices that are sent and received */
+ rmatch = match + nvtxs;
+ smatch = wspace->indices;
+ changed = smatch+graph->nsend;
+
+ /* Use wspace->indices as the tmp space for match requests of the boundary
+ * vertices that are sent and received */
+ match_requests = wspace->pairs;
+ match_granted = match_requests + graph->nsend;
+
+ nreqs_pe = ismalloc(nnbrs, 0, "Match_HEM: nreqs_pe");
+
+ nkept = graph->gnvtxs/ctrl->npes - nvtxs;
+
+ perm = (idxtype *)wspace->degrees;
+ iperm = perm + nvtxs;
+ FastRandomPermute(nvtxs, perm, 1);
+ for (i=0; i<nvtxs; i++)
+ iperm[perm[i]] = i;
+
+ nperm = iperm + nvtxs;
+ for (i=0; i<nnbrs; i++)
+ nperm[i] = i;
+
+ /*************************************************************
+ * Go now and find a matching by doing multiple iterations
+ *************************************************************/
+ /* First nullify the heavy vertices */
+ for (nchanged=i=0; i<nvtxs; i++) {
+ for (h=0; h<ncon; h++)
+ if (nvwgt[i*ncon+h] > maxnvwgt) {
+ break;
+ }
+
+ if (h != ncon) {
+ match[i] = TOO_HEAVY;
+ nchanged++;
+ }
+ }
+ if (GlobalSESum(ctrl, nchanged) > 0) {
+ IFSET(ctrl->dbglvl, DBG_PROGRESS,
+ rprintf(ctrl, "We found %d heavy vertices!\n", GlobalSESum(ctrl, nchanged)));
+ CommInterfaceData(ctrl, graph, match, smatch, rmatch);
+ }
+
+
+ for (nmatched=pass=0; pass<NMATCH_PASSES; pass++) {
+ wside = (graph->level+pass)%2;
+ nchanged = nrequests = 0;
+ for (ii=nmatched; ii<nvtxs; ii++) {
+ i = perm[ii];
+ if (match[i] == UNMATCHED) { /* Unmatched */
+ maxidx = i;
+ maxi = -1;
+
+ /* Find a heavy-edge matching */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = ladjncy[j];
+ if (match[k] == UNMATCHED &&
+ myhome[k] == myhome[i] &&
+ (maxi == -1 ||
+ adjwgt[maxi] < adjwgt[j] ||
+ (maxidx < nvtxs &&
+ k < nvtxs &&
+ adjwgt[maxi] == adjwgt[j] &&
+ BetterVBalance(ncon,nvwgt+i*ncon,nvwgt+maxidx*ncon,nvwgt+k*ncon) >= 0))) {
+ maxi = j;
+ maxidx = k;
+ }
+ }
+
+ if (maxi != -1) {
+ k = ladjncy[maxi];
+ if (k < nvtxs) { /* Take care the local vertices first */
+ /* Here we give preference the local matching by granting it right away */
+ if (i <= k) {
+ match[i] = firstvtx+k + KEEP_BIT;
+ match[k] = firstvtx+i;
+ }
+ else {
+ match[i] = firstvtx+k;
+ match[k] = firstvtx+i + KEEP_BIT;
+ }
+ changed[nchanged++] = i;
+ changed[nchanged++] = k;
+ }
+ else { /* Take care any remote boundary vertices */
+ match[k] = MAYBE_MATCHED;
+ /* Alternate among which vertices will issue the requests */
+ if ((wside ==0 && firstvtx+i < graph->imap[k]) || (wside == 1 && firstvtx+i > graph->imap[k])) {
+ match[i] = MAYBE_MATCHED;
+ match_requests[nrequests].key = graph->imap[k];
+ match_requests[nrequests].val = firstvtx+i;
+ nrequests++;
+ }
+ }
+ }
+ }
+ }
+
+
+#ifdef DEBUG_MATCH
+ PrintVector2(ctrl, nvtxs, firstvtx, match, "Match1");
+ myprintf(ctrl, "[c: %2d] Nlocal: %d, Nrequests: %d\n", c, nlocal, nrequests);
+#endif
+
+
+ /***********************************************************
+ * Exchange the match_requests, requests for me are stored in
+ * match_granted
+ ************************************************************/
+ /* Issue the receives first. Note that from each PE can receive a maximum
+ of the interface node that it needs to send it in the case of a mat-vec */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Irecv((void *)(match_granted+recvptr[i]), 2*(recvptr[i+1]-recvptr[i]), IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ /* Issue the sends next. This needs some work */
+ ikeysort(nrequests, match_requests);
+ for (j=i=0; i<nnbrs; i++) {
+ otherlastvtx = vtxdist[peind[i]+1];
+ for (k=j; k<nrequests && match_requests[k].key < otherlastvtx; k++);
+ MPI_Isend((void *)(match_requests+j), 2*(k-j), IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ j = k;
+ }
+
+ /* OK, now get into the loop waiting for the operations to finish */
+ MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+ for (i=0; i<nnbrs; i++) {
+ MPI_Get_count(ctrl->statuses+i, IDX_DATATYPE, nreqs_pe+i);
+ nreqs_pe[i] = nreqs_pe[i]/2; /* Adjust for pairs of IDX_DATATYPE */
+ }
+ MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+
+
+ /***********************************************************
+ * Now, go and service the requests that you received in
+ * match_granted
+ ************************************************************/
+ RandomPermute(nnbrs, nperm, 0);
+ for (ii=0; ii<nnbrs; ii++) {
+ i = nperm[ii];
+ pe_requests = match_granted+recvptr[i];
+ for (j=0; j<nreqs_pe[i]; j++) {
+ k = pe_requests[j].key;
+ ASSERTP(ctrl, k >= firstvtx && k < lastvtx, (ctrl, "%d %d %d %d %d\n", firstvtx, lastvtx, k, j, peind[i]));
+ /* myprintf(ctrl, "Requesting a match %d %d\n", pe_requests[j].key, pe_requests[j].val); */
+ if (match[k-firstvtx] == UNMATCHED) { /* Bingo, lets grant this request */
+ changed[nchanged++] = k-firstvtx;
+ if (nkept >= 0) { /* Flip a coin for who gets it */
+ match[k-firstvtx] = pe_requests[j].val + KEEP_BIT;
+ nkept--;
+ }
+ else {
+ match[k-firstvtx] = pe_requests[j].val;
+ pe_requests[j].key += KEEP_BIT;
+ nkept++;
+ }
+ /* myprintf(ctrl, "Request from pe:%d (%d %d) granted!\n", peind[i], pe_requests[j].val, pe_requests[j].key); */
+ }
+ else { /* We are not granting the request */
+ /* myprintf(ctrl, "Request from pe:%d (%d %d) not granted!\n", peind[i], pe_requests[j].val, pe_requests[j].key); */
+ pe_requests[j].key = UNMATCHED;
+ }
+ }
+ }
+
+
+ /***********************************************************
+ * Exchange the match_granted information. It is stored in
+ * match_requests
+ ************************************************************/
+ /* Issue the receives first. Note that from each PE can receive a maximum
+ of the interface node that it needs to send during the case of a mat-vec */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Irecv((void *)(match_requests+sendptr[i]), 2*(sendptr[i+1]-sendptr[i]), IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ /* Issue the sends next. */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Isend((void *)(match_granted+recvptr[i]), 2*nreqs_pe[i], IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ }
+
+ /* OK, now get into the loop waiting for the operations to finish */
+ MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+ for (i=0; i<nnbrs; i++) {
+ MPI_Get_count(ctrl->statuses+i, IDX_DATATYPE, nreqs_pe+i);
+ nreqs_pe[i] = nreqs_pe[i]/2; /* Adjust for pairs of IDX_DATATYPE */
+ }
+ MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+
+
+ /***********************************************************
+ * Now, go and through the match_requests and update local
+ * match information for the matchings that were granted.
+ ************************************************************/
+ for (i=0; i<nnbrs; i++) {
+ pe_requests = match_requests+sendptr[i];
+ for (j=0; j<nreqs_pe[i]; j++) {
+ match[pe_requests[j].val-firstvtx] = pe_requests[j].key;
+ if (pe_requests[j].key != UNMATCHED)
+ changed[nchanged++] = pe_requests[j].val-firstvtx;
+ }
+ }
+
+ for (i=0; i<nchanged; i++) {
+ ii = iperm[changed[i]];
+ perm[ii] = perm[nmatched];
+ iperm[perm[nmatched]] = ii;
+ nmatched++;
+ }
+
+ CommChangedInterfaceData(ctrl, graph, nchanged, changed, match, match_requests, match_granted, wspace->pv4);
+ }
+
+ /* Traverse the vertices and those that were unmatched, match them with themselves */
+ cnvtxs = 0;
+ for (i=0; i<nvtxs; i++) {
+ if (match[i] == UNMATCHED || match[i] == TOO_HEAVY) {
+ match[i] = (firstvtx+i) + KEEP_BIT;
+ cnvtxs++;
+ }
+ else if (match[i] >= KEEP_BIT) { /* A matched vertex which I get to keep */
+ cnvtxs++;
+ }
+ }
+
+ if (ctrl->dbglvl&DBG_MATCHINFO) {
+ PrintVector2(ctrl, nvtxs, firstvtx, match, "Match");
+ myprintf(ctrl, "Cnvtxs: %d\n", cnvtxs);
+ rprintf(ctrl, "Done with matching...\n");
+ }
+
+ GKfree((void **)(&myhome), (void **)(&nreqs_pe), LTERM);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr));
+
+ Moc_Global_CreateCoarseGraph(ctrl, graph, wspace, cnvtxs);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr));
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mdiffusion.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mdiffusion.c
new file mode 100644
index 0000000..6c02138
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mdiffusion.c
@@ -0,0 +1,455 @@
+/* * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mdiffusion.c
+ *
+ * This file contains code that performs mc-diffusion
+ *
+ * Started 9/16/99
+ * George
+ *
+ * $Id: mdiffusion.c,v 1.2 2003/07/21 17:18:50 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+#define PE -1
+
+/*************************************************************************
+* This function is the entry point of the initial partitioning algorithm.
+* This algorithm assembles the graph to all the processors and preceed
+* serially.
+**************************************************************************/
+int Moc_Diffusion(CtrlType *ctrl, GraphType *graph, idxtype *vtxdist,
+ idxtype *where, idxtype *home, WorkSpaceType *wspace, int npasses)
+{
+ int h, i, j;
+ int nvtxs, nedges, ncon, pass, iter, domain, processor;
+ int nparts, mype, npes, nlinks, me, you, wsize;
+ int nvisited, nswaps = -1, tnswaps, done, alldone = -1;
+ idxtype *rowptr, *colind, *diff_where, *sr_where, *ehome, *map, *rmap;
+ idxtype *pack, *unpack, *match, *proc2sub, *sub2proc;
+ idxtype *visited, *gvisited;
+ float *transfer, *npwgts, maxdiff, minflow, maxflow;
+ float lbavg, oldlbavg, ubavg, lbvec[MAXNCON];
+ float diff_flows[MAXNCON], sr_flows[MAXNCON];
+ float diff_lbavg, sr_lbavg, diff_cost, sr_cost;
+ idxtype *rbuffer, *sbuffer;
+ int *rcount, *rdispl;
+ float *solution, *load, *workspace;
+ EdgeType *degrees;
+ MatrixType matrix;
+ GraphType *egraph;
+ RInfoType *rinfo;
+
+ if (graph->ncon > 3)
+ return 0;
+
+ nvtxs = graph->nvtxs;
+ nedges = graph->nedges;
+ ncon = graph->ncon;
+
+ nparts = ctrl->nparts;
+ mype = ctrl->mype;
+ npes = ctrl->npes;
+ ubavg = savg(ncon, ctrl->ubvec);
+
+ /********************************************/
+ /* initialize variables and allocate memory */
+ /********************************************/
+ load = fmalloc(nparts*(2+ncon)+nedges*(1+ncon), "load");
+ solution = load + nparts;
+ npwgts = graph->gnpwgts = load + 2*nparts;
+ matrix.values = load + (2+ncon)*nparts;
+ transfer = matrix.transfer = load + (2+ncon)*nparts + nedges;
+
+ proc2sub = idxmalloc(amax(nparts, npes*2), "Mc_Diffusion: proc2sub");
+ sub2proc = idxmalloc(nparts*3+nedges+1, "Mc_Diffusion: match");
+ match = sub2proc + nparts;
+ rowptr = matrix.rowptr = sub2proc + 2*nparts;
+ colind = matrix.colind = sub2proc + 3*nparts + 1;
+
+ rcount = imalloc(2*npes+1, "Mc_Diffusion: rcount");
+ rdispl = rcount + npes;
+
+ pack = idxmalloc(nvtxs*8, "Mc_Diffusion: pack");
+ unpack = pack + nvtxs;
+ rbuffer = pack + 2*nvtxs;
+ sbuffer = pack + 3*nvtxs;
+ map = pack + 4*nvtxs;
+ rmap = pack + 5*nvtxs;
+ diff_where = pack + 6*nvtxs;
+ ehome = pack + 7*nvtxs;
+
+ wsize = amax(sizeof(float)*nparts*6, sizeof(idxtype)*(nvtxs+nparts*2+1));
+ workspace = (float *)GKmalloc(wsize, "Moc_Diffusion: workspace");
+ degrees = GKmalloc(nedges*sizeof(EdgeType), "Mc_Diffusion: degrees");
+ rinfo = graph->rinfo = GKmalloc(nvtxs*sizeof(RInfoType), "Mc_Diffusion: rinfo");
+
+ /******************************************/
+ /* construct subdomain connectivity graph */
+ /******************************************/
+ matrix.nrows = nparts;
+ SetUpConnectGraph(graph, &matrix, (idxtype *)workspace);
+ nlinks = (matrix.nnzs-nparts) / 2;
+
+ visited = idxmalloc(matrix.nnzs*2, "visited");
+ gvisited = visited + matrix.nnzs;
+
+ for (pass=0; pass<npasses; pass++) {
+ sset(matrix.nnzs*ncon, 0.0, transfer);
+ idxset(matrix.nnzs, 0, gvisited);
+ idxset(matrix.nnzs, 0, visited);
+ iter = nvisited = 0;
+
+ /*******************************/
+ /* compute ncon flow solutions */
+ /*******************************/
+ for (h=0; h<ncon; h++) {
+ sset(nparts, 0.0, solution);
+ ComputeLoad(graph, nparts, load, ctrl->tpwgts, h);
+
+ lbvec[h] = (load[samax(nparts, load)]+1.0/(float)nparts) * (float)nparts;
+
+ ConjGrad2(&matrix, load, solution, 0.001, workspace);
+ ComputeTransferVector(ncon, &matrix, solution, transfer, h);
+ }
+
+ oldlbavg = savg(ncon, lbvec);
+ tnswaps = 0;
+ maxdiff = 0.0;
+ for (i=0; i<nparts; i++) {
+ for (j=rowptr[i]; j<rowptr[i+1]; j++) {
+ minflow = transfer[j*ncon+samin(ncon, transfer+j*ncon)];
+ maxflow = transfer[j*ncon+samax(ncon, transfer+j*ncon)];
+ maxdiff = (maxflow - minflow > maxdiff) ? maxflow - minflow : maxdiff;
+ }
+ }
+
+ while (nvisited < nlinks) {
+
+ /******************************************/
+ /* compute independent sets of subdomains */
+ /******************************************/
+ idxset(amax(nparts, npes*2), UNMATCHED, proc2sub);
+ CSR_Match_SHEM(&matrix, match, proc2sub, gvisited, ncon);
+
+ /*****************************/
+ /* Set up the packing arrays */
+ /*****************************/
+ idxset(nparts, UNMATCHED, sub2proc);
+ for (i=0; i<npes*2; i++) {
+ if (proc2sub[i] == UNMATCHED)
+ break;
+
+ sub2proc[proc2sub[i]] = i/2;
+ }
+
+ iset(npes, 0, rcount);
+ for (i=0; i<nvtxs; i++) {
+ domain = where[i];
+ processor = sub2proc[domain];
+ if (processor != UNMATCHED) {
+ rcount[processor]++;
+ }
+ }
+
+ rdispl[0] = 0;
+ for (i=1; i<npes+1; i++)
+ rdispl[i] = rdispl[i-1] + rcount[i-1];
+
+ idxset(nvtxs, UNMATCHED, unpack);
+ for (i=0; i<nvtxs; i++) {
+ domain = where[i];
+ processor = sub2proc[domain];
+ if (processor != UNMATCHED) {
+ unpack[rdispl[processor]++] = i;
+ }
+ }
+
+ for (i=npes; i>0; i--)
+ rdispl[i] = rdispl[i-1];
+ rdispl[0] = 0;
+
+ idxset(nvtxs, UNMATCHED, pack);
+ for (i=0; i<rdispl[npes]; i++) {
+ ASSERTS(unpack[i] != UNMATCHED);
+ domain = where[unpack[i]];
+ processor = sub2proc[domain];
+ if (processor != UNMATCHED) {
+ pack[unpack[i]] = i;
+ }
+ }
+
+ /*********************/
+ /* Compute the flows */
+ /*********************/
+ if (proc2sub[mype*2] != UNMATCHED) {
+ me = proc2sub[mype*2];
+ you = proc2sub[mype*2+1];
+ ASSERTS(me != you);
+
+ for (j=rowptr[me]; j<rowptr[me+1]; j++) {
+ if (colind[j] == you) {
+ visited[j] = 1;
+ scopy(ncon, transfer+j*ncon, diff_flows);
+ break;
+ }
+ }
+
+ for (j=rowptr[you]; j<rowptr[you+1]; j++) {
+ if (colind[j] == me) {
+ visited[j] = 1;
+ for (h=0; h<ncon; h++)
+ if (transfer[j*ncon+h] > 0.0)
+ diff_flows[h] = -1.0 * transfer[j*ncon+h];
+ break;
+ }
+ }
+
+ nswaps = 1;
+ scopy(ncon, diff_flows, sr_flows);
+
+ idxset(nvtxs, 0, sbuffer);
+ for (i=0; i<nvtxs; i++)
+ if (where[i] == me || where[i] == you)
+ sbuffer[i] = 1;
+
+ egraph = ExtractGraph(ctrl, graph, sbuffer, map, rmap);
+
+ if (egraph != NULL) {
+ idxcopy(egraph->nvtxs, egraph->where, diff_where);
+ for (j=0; j<egraph->nvtxs; j++)
+ ehome[j] = home[map[j]];
+
+ RedoMyLink(ctrl, egraph, ehome, me, you, sr_flows, &sr_cost, &sr_lbavg);
+
+ if (ncon <= 4) {
+ sr_where = egraph->where;
+ egraph->where = diff_where;
+
+ nswaps = BalanceMyLink(ctrl, egraph, ehome, me, you, diff_flows, maxdiff, &diff_cost, &diff_lbavg, 1.0/(float)nvtxs);
+
+ if ((sr_lbavg < diff_lbavg &&
+ (diff_lbavg >= ubavg-1.0 || sr_cost == diff_cost)) ||
+ (sr_lbavg < ubavg-1.0 && sr_cost < diff_cost)) {
+ for (i=0; i<egraph->nvtxs; i++)
+ where[map[i]] = sr_where[i];
+ }
+ else {
+ for (i=0; i<egraph->nvtxs; i++)
+ where[map[i]] = diff_where[i];
+ }
+ }
+ else {
+ for (i=0; i<egraph->nvtxs; i++)
+ where[map[i]] = egraph->where[i];
+ }
+
+ GKfree((void **)&egraph->xadj, (void **)&egraph->nvwgt, (void **)&egraph->adjncy, LTERM);
+ GKfree((void **)&egraph, LTERM);
+ }
+
+ /**********************/
+ /* Pack the flow data */
+ /**********************/
+ idxset(nvtxs, UNMATCHED, sbuffer);
+ for (i=0; i<nvtxs; i++) {
+ domain = where[i];
+ if (domain == you || domain == me) {
+ sbuffer[pack[i]] = where[i];
+ }
+ }
+ }
+
+ /***************************/
+ /* Broadcast the flow data */
+ /***************************/
+ MPI_Allgatherv((void *)&sbuffer[rdispl[mype]], rcount[mype], IDX_DATATYPE, (void *)rbuffer, rcount, rdispl, IDX_DATATYPE, ctrl->comm);
+
+
+ /************************/
+ /* Unpack the flow data */
+ /************************/
+ for (i=0; i<rdispl[npes]; i++) {
+ if (rbuffer[i] != UNMATCHED) {
+ where[unpack[i]] = rbuffer[i];
+ }
+ }
+
+
+ /******************/
+ /* Do other stuff */
+ /******************/
+ MPI_Allreduce((void *)visited, (void *)gvisited, matrix.nnzs,
+ IDX_DATATYPE, MPI_MAX, ctrl->comm);
+ nvisited = idxsum(matrix.nnzs, gvisited)/2;
+ tnswaps += GlobalSESum(ctrl, nswaps);
+
+ if (iter++ == NGD_PASSES)
+ break;
+ }
+
+ /*****************************/
+ /* perform serial refinement */
+ /*****************************/
+ Moc_ComputeSerialPartitionParams(graph, nparts, degrees);
+ Moc_SerialKWayAdaptRefine(graph, nparts, home, ctrl->ubvec, 10);
+
+
+ /****************************/
+ /* check for early breakout */
+ /****************************/
+ for (h=0; h<ncon; h++) {
+ lbvec[h] = (float)(nparts) *
+ npwgts[samax_strd(nparts,npwgts+h,ncon)*ncon+h];
+ }
+ lbavg = savg(ncon, lbvec);
+
+ done = 0;
+ if (
+ tnswaps == 0 ||
+ lbavg >= oldlbavg ||
+ lbavg <= ubavg + 0.035
+ )
+ done = 1;
+
+ alldone = GlobalSEMax(ctrl, done);
+ if (alldone == 1)
+ break;
+ }
+
+ /*******************************************************/
+ /* ensure that all subdomains have at least one vertex */
+ /*******************************************************/
+/*
+ idxset(nparts, 0, match);
+ for (i=0; i<nvtxs; i++)
+ match[where[i]]++;
+
+ done = 0;
+ while (done == 0) {
+ done = 1;
+
+ me = idxamin(nparts, match);
+ if (match[me] == 0) {
+if (ctrl->mype == PE) printf("WARNING: empty subdomain %d in Moc_Diffusion\n", me);
+ you = idxamax(nparts, match);
+ for (i=0; i<nvtxs; i++) {
+ if (where[i] == you) {
+ where[i] = me;
+ match[you]--;
+ match[me]++;
+ done = 0;
+ break;
+ }
+ }
+ }
+ }
+*/
+
+ /******************************/
+ /* now free memory and return */
+ /******************************/
+ GKfree((void **)&load, (void **)&proc2sub, (void **)&sub2proc, (void **)&rcount, LTERM);
+ GKfree((void **)&pack, (void **)&workspace, (void **)&degrees, (void **)&rinfo, LTERM);
+ GKfree((void **)&visited, LTERM);
+ graph->gnpwgts = NULL;
+ graph->rinfo = NULL;
+
+ return 0;
+}
+
+
+/*************************************************************************
+* This function extracts a subgraph from a graph given an indicator array.
+**************************************************************************/
+GraphType *ExtractGraph(CtrlType *ctrl, GraphType *graph, idxtype *indicator,
+ idxtype *map, idxtype *rmap)
+{
+ int h, i, j;
+ int nvtxs, envtxs, enedges, ncon;
+ int vtx, count;
+ idxtype *xadj, *vsize, *adjncy, *adjwgt, *where;
+ idxtype *exadj, *evsize, *eadjncy, *eadjwgt, *ewhere;
+ float *nvwgt, *envwgt;
+ GraphType *egraph;
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ nvwgt = graph->nvwgt;
+ vsize = graph->vsize;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+
+ count = 0;
+ for (i=0; i<nvtxs; i++) {
+ if (indicator[i] == 1) {
+ map[count] = i;
+ rmap[i] = count;
+ count++;
+ }
+ }
+
+ if (count == 0) {
+ return NULL;
+ }
+
+ /*******************/
+ /* allocate memory */
+ /*******************/
+ egraph = CreateGraph();
+ envtxs = egraph->nvtxs = count;
+ egraph->ncon = graph->ncon;
+
+ exadj = egraph->xadj = idxmalloc(envtxs*3+1, "exadj");
+ ewhere = egraph->where = exadj + envtxs + 1;
+ evsize = egraph->vsize = exadj + 2*envtxs + 1;
+
+ envwgt = egraph->nvwgt = fmalloc(envtxs*ncon, "envwgt");
+
+ /************************************************/
+ /* compute xadj, where, nvwgt, and vsize arrays */
+ /************************************************/
+ idxset(envtxs+1, 0, exadj);
+ for (i=0; i<envtxs; i++) {
+ vtx = map[i];
+
+ ewhere[i] = where[vtx];
+ for (h=0; h<ncon; h++)
+ envwgt[i*ncon+h] = nvwgt[vtx*ncon+h];
+
+ if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION)
+ evsize[i] = vsize[vtx];
+
+ for (j=xadj[vtx]; j<xadj[vtx+1]; j++)
+ if (indicator[adjncy[j]] == 1)
+ exadj[i]++;
+
+ }
+ MAKECSR(i, envtxs, exadj);
+
+ /************************************/
+ /* compute adjncy and adjwgt arrays */
+ /************************************/
+ enedges = egraph->nedges = exadj[envtxs];
+ eadjncy = egraph->adjncy = idxmalloc(enedges*2, "eadjncy");
+ eadjwgt = egraph->adjwgt = eadjncy + enedges;
+
+ for (i=0; i<envtxs; i++) {
+ vtx = map[i];
+ for (j=xadj[vtx]; j<xadj[vtx+1]; j++) {
+ if (indicator[adjncy[j]] == 1) {
+ eadjncy[exadj[i]] = rmap[adjncy[j]];
+ eadjwgt[exadj[i]++] = adjwgt[j];
+ }
+ }
+ }
+
+ for (i=envtxs; i>0; i--)
+ exadj[i] = exadj[i-1];
+ exadj[0] = 0;
+
+ return egraph;
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mdrivers.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mdrivers.c
new file mode 100644
index 0000000..467df79
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mdrivers.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mdrivers.c
+ *
+ * This file contains the driving routines for the various parallel
+ * multilevel partitioning and repartitioning algorithms
+ *
+ * Started 11/19/96
+ * George
+ *
+ * $Id: mdrivers.c,v 1.3 2003/07/22 20:29:06 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+/*************************************************************************
+* This function is the driver to the multi-constraint partitioning algorithm.
+**************************************************************************/
+void Moc_Global_Partition(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, ncon, nparts;
+ float ftmp, ubavg, lbavg, lbvec[MAXNCON];
+
+ ncon = graph->ncon;
+ nparts = ctrl->nparts;
+ ubavg = savg(graph->ncon, ctrl->ubvec);
+
+ SetUp(ctrl, graph, wspace);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ rprintf(ctrl, "[%6d %8d %5d %5d] [%d] [", graph->gnvtxs, GlobalSESum(ctrl, graph->nedges),
+ GlobalSEMin(ctrl, graph->nvtxs), GlobalSEMax(ctrl, graph->nvtxs), ctrl->CoarsenTo);
+ for (i=0; i<ncon; i++)
+ rprintf(ctrl, " %.3f", GlobalSEMinFloat(ctrl,graph->nvwgt[samin_strd(graph->nvtxs, graph->nvwgt+i, ncon)*ncon+i]));
+ rprintf(ctrl, "] [");
+ for (i=0; i<ncon; i++)
+ rprintf(ctrl, " %.3f", GlobalSEMaxFloat(ctrl, graph->nvwgt[samax_strd(graph->nvtxs, graph->nvwgt+i, ncon)*ncon+i]));
+ rprintf(ctrl, "]\n");
+ }
+
+ if (graph->gnvtxs < 1.3*ctrl->CoarsenTo ||
+ (graph->finer != NULL &&
+ graph->gnvtxs > graph->finer->gnvtxs*COARSEN_FRACTION)) {
+
+ /* Done with coarsening. Find a partition */
+ graph->where = idxmalloc(graph->nvtxs+graph->nrecv, "graph->where");
+ Moc_InitPartition_RB(ctrl, graph, wspace);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, balance: ", graph->gnvtxs);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+
+ /* In case no coarsening took place */
+ if (graph->finer == NULL) {
+ Moc_ComputePartitionParams(ctrl, graph, wspace);
+ Moc_KWayFM(ctrl, graph, wspace, NGR_PASSES);
+ }
+ }
+ else {
+ Moc_GlobalMatch_Balance(ctrl, graph, wspace);
+
+ Moc_Global_Partition(ctrl, graph->coarser, wspace);
+
+ Moc_ProjectPartition(ctrl, graph, wspace);
+ Moc_ComputePartitionParams(ctrl, graph, wspace);
+
+ if (graph->ncon > 1 && graph->level < 3) {
+ for (i=0; i<ncon; i++) {
+ ftmp = ssum_strd(nparts, graph->gnpwgts+i, ncon);
+ if (ftmp != 0.0)
+ lbvec[i] = (float)(nparts) *
+ graph->gnpwgts[samax_strd(nparts, graph->gnpwgts+i, ncon)*ncon+i]/ftmp;
+ else
+ lbvec[i] = 1.0;
+ }
+ lbavg = savg(graph->ncon, lbvec);
+
+ if (lbavg > ubavg + 0.035) {
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, cut: %8d, balance: ", graph->gnvtxs, graph->mincut);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+
+ Moc_KWayBalance(ctrl, graph, wspace, graph->ncon);
+ }
+ }
+
+ Moc_KWayFM(ctrl, graph, wspace, NGR_PASSES);
+
+ if (ctrl->dbglvl&DBG_PROGRESS) {
+ Moc_ComputeParallelBalance(ctrl, graph, graph->where, lbvec);
+ rprintf(ctrl, "nvtxs: %10d, cut: %8d, balance: ", graph->gnvtxs, graph->mincut);
+ for (i=0; i<graph->ncon; i++)
+ rprintf(ctrl, "%.3f ", lbvec[i]);
+ rprintf(ctrl, "\n");
+ }
+
+ if (graph->level != 0)
+ GKfree((void **)&graph->lnpwgts, (void **)&graph->gnpwgts, LTERM);
+ }
+
+ return;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/memory.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/memory.c
new file mode 100644
index 0000000..a8eeaff
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/memory.c
@@ -0,0 +1,216 @@
+/*
+ * 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.3 2003/07/30 18:37:59 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function allocate various pools of memory
+**************************************************************************/
+void PreAllocateMemory(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ wspace->nlarge = 2*graph->nedges;
+
+ wspace->maxcore = 8*graph->nedges+1;
+ wspace->core = idxmalloc(wspace->maxcore, "PreAllocateMemory: wspace->core");
+
+ wspace->pairs = (KeyValueType *)wspace->core;
+ wspace->indices = (idxtype *)(wspace->pairs + wspace->nlarge);
+ wspace->degrees = (EdgeType *)(wspace->indices + wspace->nlarge);
+
+
+ wspace->pv1 = idxmalloc(ctrl->nparts+ctrl->npes+1, "PreAllocateMemory: wspace->pv?");
+ wspace->pv2 = idxmalloc(ctrl->nparts+ctrl->npes+1, "PreAllocateMemory: wspace->pv?");
+ wspace->pv3 = idxmalloc(ctrl->nparts+ctrl->npes+1, "PreAllocateMemory: wspace->pv?");
+ wspace->pv4 = idxmalloc(ctrl->nparts+ctrl->npes+1, "PreAllocateMemory: wspace->pv?");
+
+ wspace->pepairs1 = (KeyValueType *)GKmalloc(sizeof(KeyValueType)*(ctrl->nparts+ctrl->npes+1), "PreAllocateMemory: wspace->pepairs?");
+ wspace->pepairs2 = (KeyValueType *)GKmalloc(sizeof(KeyValueType)*(ctrl->nparts+ctrl->npes+1), "PreAllocateMemory: wspace->pepairs?");
+
+}
+
+
+/*************************************************************************
+* This function de-allocate various pools of memory
+**************************************************************************/
+void FreeWSpace(WorkSpaceType *wspace)
+{
+
+ GKfree((void **)&wspace->core,
+ (void **)&wspace->pv1,
+ (void **)&wspace->pv2,
+ (void **)&wspace->pv3,
+ (void **)&wspace->pv4,
+ (void **)&wspace->pepairs1,
+ (void **)&wspace->pepairs2,
+ LTERM);
+}
+
+
+/*************************************************************************
+* This function de-allocates memory allocated for the control structures
+**************************************************************************/
+void FreeCtrl(CtrlType *ctrl)
+{
+ MPI_Comm_free(&(ctrl->gcomm));
+}
+
+
+/*************************************************************************
+* 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->gnvtxs = graph->nvtxs = graph->nedges = graph->nsep = -1;
+ graph->nnbrs = graph->nrecv = graph->nsend = graph->nlocal = -1;
+ graph->xadj = graph->vwgt = graph->vsize = graph->adjncy = graph->adjwgt = NULL;
+ graph->nvwgt = NULL;
+ graph->vtxdist = NULL;
+ graph->match = graph->cmap = NULL;
+ graph->label = NULL;
+
+ graph->peind = NULL;
+ graph->sendptr = graph->sendind = graph->recvptr = graph->recvind = NULL;
+ graph->imap = NULL;
+ graph->pexadj = graph->peadjncy = graph->peadjloc = NULL;
+ graph->lperm = NULL;
+
+ graph->slens = graph->rlens = NULL;
+ graph->rcand = NULL;
+
+ graph->where = graph->home = graph->lpwgts = graph->gpwgts = NULL;
+ graph->lnpwgts = graph->gnpwgts = NULL;
+ graph->rinfo = NULL;
+
+ graph->nrinfo = NULL;
+ graph->sepind = NULL;
+
+ graph->coarser = graph->finer = NULL;
+
+}
+
+/*************************************************************************
+* This function deallocates any memory stored in a graph
+**************************************************************************/
+void FreeGraph(GraphType *graph)
+{
+
+ GKfree((void **)&graph->xadj,
+ (void **)&graph->vwgt,
+ (void **)&graph->nvwgt,
+ (void **)&graph->vsize,
+ (void **)&graph->adjncy,
+ (void **)&graph->adjwgt,
+ (void **)&graph->vtxdist,
+ (void **)&graph->match,
+ (void **)&graph->cmap,
+ (void **)&graph->lperm,
+ (void **)&graph->label,
+ (void **)&graph->where,
+ (void **)&graph->home,
+ (void **)&graph->rinfo,
+ (void **)&graph->nrinfo,
+ (void **)&graph->sepind,
+ (void **)&graph->lpwgts,
+ (void **)&graph->gpwgts,
+ (void **)&graph->lnpwgts,
+ (void **)&graph->gnpwgts,
+ (void **)&graph->peind,
+ (void **)&graph->sendptr,
+ (void **)&graph->sendind,
+ (void **)&graph->recvptr,
+ (void **)&graph->recvind,
+ (void **)&graph->imap,
+ (void **)&graph->rlens,
+ (void **)&graph->slens,
+ (void **)&graph->rcand,
+ (void **)&graph->pexadj,
+ (void **)&graph->peadjncy,
+ (void **)&graph->peadjloc,
+ LTERM);
+
+ free(graph);
+}
+
+
+
+/*************************************************************************
+* This function deallocates any memory stored in a graph
+**************************************************************************/
+void FreeInitialGraphAndRemap(GraphType *graph, int wgtflag)
+{
+ int i, nedges;
+ idxtype *adjncy, *imap;
+
+ nedges = graph->nedges;
+ adjncy = graph->adjncy;
+ imap = graph->imap;
+
+ if (imap != NULL) {
+ for (i=0; i<nedges; i++)
+ adjncy[i] = imap[adjncy[i]]; /* Apply local to global transformation */
+ }
+
+ /* Free Metis's things */
+ GKfree((void **)&graph->match,
+ (void **)&graph->cmap,
+ (void **)&graph->lperm,
+ (void **)&graph->where,
+ (void **)&graph->label,
+ (void **)&graph->rinfo,
+ (void **)&graph->nrinfo,
+ (void **)&graph->nvwgt,
+ (void **)&graph->lpwgts,
+ (void **)&graph->gpwgts,
+ (void **)&graph->lnpwgts,
+ (void **)&graph->gnpwgts,
+ (void **)&graph->sepind,
+ (void **)&graph->peind,
+ (void **)&graph->sendptr,
+ (void **)&graph->sendind,
+ (void **)&graph->recvptr,
+ (void **)&graph->recvind,
+ (void **)&graph->imap,
+ (void **)&graph->rlens,
+ (void **)&graph->slens,
+ (void **)&graph->rcand,
+ (void **)&graph->pexadj,
+ (void **)&graph->peadjncy,
+ (void **)&graph->peadjloc,
+ LTERM);
+
+ if ((wgtflag&2) == 0)
+ GKfree((void **)&graph->vwgt, (void **)&graph->vsize, LTERM);
+ if ((wgtflag&1) == 0)
+ GKfree((void **)&graph->adjwgt, LTERM);
+
+ free(graph);
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mesh.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mesh.c
new file mode 100644
index 0000000..57a80c0
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mesh.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mesh.c
+ *
+ * This file contains routines for constructing the dual graph of a mesh.
+ * Assumes that each processor has at least one mesh element.
+ *
+ * Started 10/19/94
+ * George
+ *
+ * $Id: mesh.c,v 1.11 2003/07/25 04:01:04 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function converts a mesh into a dual graph
+**************************************************************************/
+void ParMETIS_V3_Mesh2Dual(idxtype *elmdist, idxtype *eptr, idxtype *eind,
+ int *numflag, int *ncommonnodes, idxtype **xadj,
+ idxtype **adjncy, MPI_Comm *comm)
+{
+ int i, j, jj, k, kk, m;
+ int npes, mype, pe, count, mask, pass;
+ int nelms, lnns, my_nns, node;
+ int firstelm, firstnode, lnode, nrecv, nsend;
+ int *scounts, *rcounts, *sdispl, *rdispl;
+ idxtype *nodedist, *nmap, *auxarray;
+ idxtype *gnptr, *gnind, *nptr, *nind, *myxadj, *myadjncy = NULL;
+ idxtype *sbuffer, *rbuffer, *htable;
+ KeyValueType *nodelist, *recvbuffer;
+ idxtype ind[200], wgt[200];
+ int gmaxnode, gminnode;
+ CtrlType ctrl;
+
+
+ SetUpCtrl(&ctrl, -1, 0, *comm);
+
+ npes = ctrl.npes;
+ mype = ctrl.mype;
+
+ nelms = elmdist[mype+1]-elmdist[mype];
+
+ if (*numflag == 1)
+ ChangeNumberingMesh2(elmdist, eptr, eind, NULL, NULL, NULL, npes, mype, 1);
+
+ mask = (1<<11)-1;
+
+ /*****************************/
+ /* Determine number of nodes */
+ /*****************************/
+ gminnode = GlobalSEMin(&ctrl, eind[idxamin(eptr[nelms], eind)]);
+ for (i=0; i<eptr[nelms]; i++)
+ eind[i] -= gminnode;
+
+ gmaxnode = GlobalSEMax(&ctrl, eind[idxamax(eptr[nelms], eind)]);
+
+
+ /**************************/
+ /* Check for input errors */
+ /**************************/
+ ASSERTS(nelms > 0);
+
+ /* construct node distribution array */
+ nodedist = idxsmalloc(npes+1, 0, "nodedist");
+ for (nodedist[0]=0, i=0,j=gmaxnode+1; i<npes; i++) {
+ k = j/(npes-i);
+ nodedist[i+1] = nodedist[i]+k;
+ j -= k;
+ }
+ my_nns = nodedist[mype+1]-nodedist[mype];
+ firstnode = nodedist[mype];
+
+ nodelist = (KeyValueType *)GKmalloc(eptr[nelms]*sizeof(KeyValueType), "nodelist");
+ auxarray = idxmalloc(eptr[nelms], "auxarray");
+ htable = idxsmalloc(amax(my_nns, mask+1), -1, "htable");
+ scounts = imalloc(4*npes+2, "scounts");
+ rcounts = scounts+npes;
+ sdispl = scounts+2*npes;
+ rdispl = scounts+3*npes+1;
+
+
+ /*********************************************/
+ /* first find a local numbering of the nodes */
+ /*********************************************/
+ for (i=0; i<nelms; i++) {
+ for (j=eptr[i]; j<eptr[i+1]; j++) {
+ nodelist[j].key = eind[j];
+ nodelist[j].val = j;
+ auxarray[j] = i; /* remember the local element ID that uses this node */
+ }
+ }
+ ikeysort(eptr[nelms], nodelist);
+
+ for (count=1, i=1; i<eptr[nelms]; i++) {
+ if (nodelist[i].key > nodelist[i-1].key)
+ count++;
+ }
+
+ lnns = count;
+ nmap = idxmalloc(lnns, "nmap");
+
+ /* renumber the nodes of the elements array */
+ count = 1;
+ nmap[0] = nodelist[0].key;
+ eind[nodelist[0].val] = 0;
+ nodelist[0].val = auxarray[nodelist[0].val]; /* Store the local element ID */
+ for (i=1; i<eptr[nelms]; i++) {
+ if (nodelist[i].key > nodelist[i-1].key) {
+ nmap[count] = nodelist[i].key;
+ count++;
+ }
+ eind[nodelist[i].val] = count-1;
+ nodelist[i].val = auxarray[nodelist[i].val]; /* Store the local element ID */
+ }
+ MPI_Barrier(*comm);
+
+ /**********************************************************/
+ /* perform comms necessary to construct node-element list */
+ /**********************************************************/
+ iset(npes, 0, scounts);
+ for (pe=i=0; i<eptr[nelms]; i++) {
+ while (nodelist[i].key >= nodedist[pe+1])
+ pe++;
+ scounts[pe] += 2;
+ }
+ ASSERTS(pe < npes);
+
+ MPI_Alltoall((void *)scounts, 1, MPI_INT, (void *)rcounts, 1, MPI_INT, *comm);
+
+ icopy(npes, scounts, sdispl);
+ MAKECSR(i, npes, sdispl);
+
+ icopy(npes, rcounts, rdispl);
+ MAKECSR(i, npes, rdispl);
+
+ ASSERTS(sdispl[npes] == eptr[nelms]*2);
+
+ nrecv = rdispl[npes]/2;
+ recvbuffer = (KeyValueType *)GKmalloc(amax(1, nrecv)*sizeof(KeyValueType), "recvbuffer");
+
+ MPI_Alltoallv((void *)nodelist, scounts, sdispl, IDX_DATATYPE, (void *)recvbuffer,
+ rcounts, rdispl, IDX_DATATYPE, *comm);
+
+ /**************************************/
+ /* construct global node-element list */
+ /**************************************/
+ gnptr = idxsmalloc(my_nns+1, 0, "gnptr");
+
+ for (i=0; i<npes; i++) {
+ for (j=rdispl[i]/2; j<rdispl[i+1]/2; j++) {
+ lnode = recvbuffer[j].key-firstnode;
+ ASSERTS(lnode >= 0 && lnode < my_nns)
+
+ gnptr[lnode]++;
+ }
+ }
+ MAKECSR(i, my_nns, gnptr);
+
+ gnind = idxmalloc(amax(1, gnptr[my_nns]), "gnind");
+ for (pe=0; pe<npes; pe++) {
+ firstelm = elmdist[pe];
+ for (j=rdispl[pe]/2; j<rdispl[pe+1]/2; j++) {
+ lnode = recvbuffer[j].key-firstnode;
+ gnind[gnptr[lnode]++] = recvbuffer[j].val+firstelm;
+ }
+ }
+ SHIFTCSR(i, my_nns, gnptr);
+
+
+ /*********************************************************/
+ /* send the node-element info to the relevant processors */
+ /*********************************************************/
+ iset(npes, 0, scounts);
+
+ /* use a hash table to ensure that each node is sent to a proc only once */
+ for (pe=0; pe<npes; pe++) {
+ for (j=rdispl[pe]/2; j<rdispl[pe+1]/2; j++) {
+ lnode = recvbuffer[j].key-firstnode;
+ if (htable[lnode] == -1) {
+ scounts[pe] += gnptr[lnode+1]-gnptr[lnode];
+ htable[lnode] = 1;
+ }
+ }
+
+ /* now reset the hash table */
+ for (j=rdispl[pe]/2; j<rdispl[pe+1]/2; j++) {
+ lnode = recvbuffer[j].key-firstnode;
+ htable[lnode] = -1;
+ }
+ }
+
+
+ MPI_Alltoall((void *)scounts, 1, MPI_INT, (void *)rcounts, 1, MPI_INT, *comm);
+
+ icopy(npes, scounts, sdispl);
+ MAKECSR(i, npes, sdispl);
+
+ /* create the send buffer */
+ nsend = sdispl[npes];
+ sbuffer = (idxtype *)realloc(nodelist, sizeof(idxtype)*amax(1, nsend));
+
+ count = 0;
+ for (pe=0; pe<npes; pe++) {
+ for (j=rdispl[pe]/2; j<rdispl[pe+1]/2; j++) {
+ lnode = recvbuffer[j].key-firstnode;
+ if (htable[lnode] == -1) {
+ for (k=gnptr[lnode]; k<gnptr[lnode+1]; k++) {
+ if (k == gnptr[lnode])
+ sbuffer[count++] = -1*(gnind[k]+1);
+ else
+ sbuffer[count++] = gnind[k];
+ }
+ htable[lnode] = 1;
+ }
+ }
+ ASSERTS(count == sdispl[pe+1]);
+
+ /* now reset the hash table */
+ for (j=rdispl[pe]/2; j<rdispl[pe+1]/2; j++) {
+ lnode = recvbuffer[j].key-firstnode;
+ htable[lnode] = -1;
+ }
+ }
+
+ icopy(npes, rcounts, rdispl);
+ MAKECSR(i, npes, rdispl);
+
+ nrecv = rdispl[npes];
+ rbuffer = (idxtype *)realloc(recvbuffer, sizeof(idxtype)*amax(1, nrecv));
+
+ MPI_Alltoallv((void *)sbuffer, scounts, sdispl, IDX_DATATYPE, (void *)rbuffer,
+ rcounts, rdispl, IDX_DATATYPE, *comm);
+
+ k = -1;
+ nptr = idxsmalloc(lnns+1, 0, "nptr");
+ nind = rbuffer;
+ for (pe=0; pe<npes; pe++) {
+ for (j=rdispl[pe]; j<rdispl[pe+1]; j++) {
+ if (nind[j] < 0) {
+ k++;
+ nind[j] = (-1*nind[j])-1;
+ }
+ nptr[k]++;
+ }
+ }
+ MAKECSR(i, lnns, nptr);
+
+ ASSERTS(k+1 == lnns);
+ ASSERTS(nptr[lnns] == nrecv)
+
+ myxadj = *xadj = idxsmalloc(nelms+1, 0, "xadj");
+ idxset(mask+1, -1, htable);
+
+ firstelm = elmdist[mype];
+
+ /* Two passes -- in first pass, simply find out the memory requirements */
+ for (pass=0; pass<2; pass++) {
+ for (i=0; i<nelms; i++) {
+ for (count=0, j=eptr[i]; j<eptr[i+1]; j++) {
+ node = eind[j];
+
+ for (k=nptr[node]; k<nptr[node+1]; k++) {
+ if ((kk=nind[k]) == firstelm+i)
+ continue;
+
+ m = htable[(kk&mask)];
+
+ if (m == -1) {
+ ind[count] = kk;
+ wgt[count] = 1;
+ htable[(kk&mask)] = count++;
+ }
+ else {
+ if (ind[m] == kk) {
+ wgt[m]++;
+ }
+ else {
+ for (jj=0; jj<count; jj++) {
+ if (ind[jj] == kk) {
+ wgt[jj]++;
+ break;
+ }
+ }
+ if (jj == count) {
+ ind[count] = kk;
+ wgt[count++] = 1;
+ }
+ }
+ }
+ }
+ }
+
+ for (j=0; j<count; j++) {
+ htable[(ind[j]&mask)] = -1;
+ if (wgt[j] >= *ncommonnodes) {
+ if (pass == 0)
+ myxadj[i]++;
+ else
+ myadjncy[myxadj[i]++] = ind[j];
+ }
+ }
+ }
+
+ if (pass == 0) {
+ MAKECSR(i, nelms, myxadj);
+ myadjncy = *adjncy = idxmalloc(myxadj[nelms], "adjncy");
+ }
+ else {
+ SHIFTCSR(i, nelms, myxadj);
+ }
+ }
+
+ /*****************************************/
+ /* correctly renumber the elements array */
+ /*****************************************/
+ for (i=0; i<eptr[nelms]; i++)
+ eind[i] = nmap[eind[i]] + gminnode;
+
+ if (*numflag == 1)
+ ChangeNumberingMesh2(elmdist, eptr, eind, myxadj, myadjncy, NULL, npes, mype, 0);
+
+ /* do not free nodelist, recvbuffer, rbuffer */
+ GKfree((void **)&scounts, (void **)&nodedist, (void **)&nmap, (void **)&sbuffer,
+ (void **)&htable, (void **)&nptr, (void **)&nind, (void **)&gnptr,
+ (void **)&gnind, (void **)&auxarray, LTERM);
+
+ FreeCtrl(&ctrl);
+
+ return;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mmetis.c
new file mode 100644
index 0000000..b262ed1
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/mmetis.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mmetis.c
+ *
+ * This is the entry point of ParMETIS_V3_PartMeshKway
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: mmetis.c,v 1.8 2003/07/25 04:01:04 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel k-way multilevel mesh partitionioner.
+* This function assumes nothing about the mesh distribution.
+* It is the general case.
+************************************************************************************/
+void ParMETIS_V3_PartMeshKway(idxtype *elmdist, idxtype *eptr, idxtype *eind, idxtype *elmwgt,
+ int *wgtflag, int *numflag, int *ncon, int *ncommonnodes, int *nparts,
+ float *tpwgts, float *ubvec, int *options, int *edgecut, idxtype *part,
+ MPI_Comm *comm)
+{
+ int i, nvtxs, nedges, gnedges, npes, mype;
+ idxtype *xadj, *adjncy;
+ timer TotalTmr, Mesh2DualTmr, ParMETISTmr;
+ CtrlType ctrl;
+
+ /********************************/
+ /* Try and take care bad inputs */
+ /********************************/
+ if (elmdist == NULL || eptr == NULL || eind == NULL || wgtflag == NULL ||
+ numflag == NULL || ncon == NULL || ncommonnodes == NULL || nparts == NULL ||
+ tpwgts == NULL || ubvec == NULL || options == NULL || edgecut == NULL ||
+ part == NULL || comm == NULL) {
+ printf("ERROR: One or more required parameters is NULL. Aborting.\n");
+ abort();
+ }
+ if (((*wgtflag)&2) && elmwgt == NULL) {
+ printf("ERROR: elmwgt == NULL when vertex weights were specified. Aborting.\n");
+ abort();
+ }
+
+
+ SetUpCtrl(&ctrl, *nparts, (options[0] == 1 ? options[PMV3_OPTION_DBGLVL] : 0), *comm);
+ npes = ctrl.npes;
+ mype = ctrl.mype;
+
+ cleartimer(TotalTmr);
+ cleartimer(Mesh2DualTmr);
+ cleartimer(ParMETISTmr);
+
+ MPI_Barrier(ctrl.comm);
+ starttimer(TotalTmr);
+ starttimer(Mesh2DualTmr);
+
+ ParMETIS_V3_Mesh2Dual(elmdist, eptr, eind, numflag, ncommonnodes, &xadj, &adjncy, &(ctrl.comm));
+
+ if (ctrl.dbglvl&DBG_INFO) {
+ nvtxs = elmdist[mype+1]-elmdist[mype];
+ nedges = xadj[nvtxs] + (*numflag == 0 ? 0 : -1);
+ rprintf(&ctrl, "Completed Dual Graph -- Nvtxs: %d, Nedges: %d \n",
+ elmdist[npes], GlobalSESum(&ctrl, nedges));
+ }
+
+ MPI_Barrier(ctrl.comm);
+ stoptimer(Mesh2DualTmr);
+
+
+ /***********************/
+ /* Partition the graph */
+ /***********************/
+ starttimer(ParMETISTmr);
+
+ ParMETIS_V3_PartKway(elmdist, xadj, adjncy, elmwgt, NULL, wgtflag, numflag, ncon,
+ nparts, tpwgts, ubvec, options, edgecut, part, &(ctrl.comm));
+
+ MPI_Barrier(ctrl.comm);
+ stoptimer(ParMETISTmr);
+ stoptimer(TotalTmr);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimer(&ctrl, Mesh2DualTmr, " Mesh2Dual"));
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimer(&ctrl, ParMETISTmr, " ParMETIS"));
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimer(&ctrl, TotalTmr, " Total"));
+
+ GKfree((void **)&xadj, (void **)&adjncy, LTERM);
+
+ FreeCtrl(&ctrl);
+
+ return;
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/move.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/move.c
new file mode 100644
index 0000000..06a8e5c
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/move.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * mmove.c
+ *
+ * This file contains functions that move the graph given a partition
+ *
+ * Started 11/22/96
+ * George
+ *
+ * $Id: move.c,v 1.3 2003/07/31 16:23:30 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+/*************************************************************************
+* This function moves the graph, and returns a new graph.
+* This routine can be called with or without performing refinement.
+* In the latter case it allocates and computes lpwgts itself.
+**************************************************************************/
+GraphType *Moc_MoveGraph(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int h, i, ii, j, jj, nvtxs, ncon, nparts;
+ idxtype *xadj, *vwgt, *adjncy, *adjwgt, *mvtxdist;
+ idxtype *where, *newlabel, *lpwgts, *gpwgts;
+ idxtype *sgraph, *rgraph;
+ KeyValueType *sinfo, *rinfo;
+ GraphType *mgraph;
+
+ nparts = ctrl->nparts;
+ ASSERT(ctrl, nparts == ctrl->npes);
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ vwgt = graph->vwgt;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+
+ mvtxdist = idxmalloc(nparts+1, "MoveGraph: mvtxdist");
+
+ /* Let's do a prefix scan to determine the labeling of the nodes given */
+ lpwgts = wspace->pv1;
+ gpwgts = wspace->pv2;
+ sinfo = wspace->pepairs1;
+ rinfo = wspace->pepairs2;
+ for (i=0; i<nparts; i++)
+ sinfo[i].key = sinfo[i].val = 0;
+
+ for (i=0; i<nvtxs; i++) {
+ sinfo[where[i]].key++;
+ sinfo[where[i]].val += xadj[i+1]-xadj[i];
+ }
+ for (i=0; i<nparts; i++)
+ lpwgts[i] = sinfo[i].key;
+
+ MPI_Scan((void *)lpwgts, (void *)gpwgts, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+ MPI_Allreduce((void *)lpwgts, (void *)mvtxdist, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+
+ MAKECSR(i, nparts, mvtxdist);
+
+ /* gpwgts[i] will store the label of the first vertex for each domain in each processor */
+ for (i=0; i<nparts; i++)
+ /* We were interested in an exclusive Scan */
+ gpwgts[i] = mvtxdist[i] + gpwgts[i] - lpwgts[i];
+
+ newlabel = idxmalloc(nvtxs+graph->nrecv, "MoveGraph: newlabel");
+
+ for (i=0; i<nvtxs; i++)
+ newlabel[i] = gpwgts[where[i]]++;
+
+ /* OK, now send the newlabel info to processors storing adjacent interface nodes */
+ CommInterfaceData(ctrl, graph, newlabel, wspace->indices, newlabel+nvtxs);
+
+ /* Now lets tell everybody what and from where he will get it. Assume nparts == npes */
+ MPI_Alltoall((void *)sinfo, 2, IDX_DATATYPE, (void *)rinfo, 2, IDX_DATATYPE, ctrl->comm);
+
+ /* Use lpwgts and gpwgts as pointers to where data will be received and send */
+ lpwgts[0] = 0; /* Send part */
+ gpwgts[0] = 0; /* Received part */
+ for (i=0; i<nparts; i++) {
+ lpwgts[i+1] = lpwgts[i] + (1+ncon)*sinfo[i].key + 2*sinfo[i].val;
+ gpwgts[i+1] = gpwgts[i] + (1+ncon)*rinfo[i].key + 2*rinfo[i].val;
+ }
+
+
+ if (lpwgts[nparts]+gpwgts[nparts] > wspace->maxcore) {
+ /* Adjust core memory, incase the graph was originally very memory unbalanced */
+ free(wspace->core);
+ wspace->maxcore = lpwgts[nparts]+4*gpwgts[nparts]; /* In spirit of the 8*nedges */
+ wspace->core = idxmalloc(wspace->maxcore, "Moc_MoveGraph: wspace->core");
+ }
+
+ sgraph = wspace->core;
+ rgraph = wspace->core + lpwgts[nparts];
+
+ /* Issue the receives first */
+ for (i=0; i<nparts; i++) {
+ if (rinfo[i].key > 0)
+ MPI_Irecv((void *)(rgraph+gpwgts[i]), gpwgts[i+1]-gpwgts[i], IDX_DATATYPE, i, 1, ctrl->comm, ctrl->rreq+i);
+ else
+ ASSERT(ctrl, gpwgts[i+1]-gpwgts[i] == 0);
+ }
+
+ /* Assemble the graph to be sent and send it */
+ for (i=0; i<nvtxs; i++) {
+ ii = lpwgts[where[i]];
+ sgraph[ii++] = xadj[i+1]-xadj[i];
+ for (h=0; h<ncon; h++)
+ sgraph[ii++] = vwgt[i*ncon+h];
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ sgraph[ii++] = newlabel[adjncy[j]];
+ sgraph[ii++] = adjwgt[j];
+ }
+ lpwgts[where[i]] = ii;
+ }
+
+ for (i=nparts; i>0; i--)
+ lpwgts[i] = lpwgts[i-1];
+ lpwgts[0] = 0;
+
+ for (i=0; i<nparts; i++) {
+ if (sinfo[i].key > 0)
+ MPI_Isend((void *)(sgraph+lpwgts[i]), lpwgts[i+1]-lpwgts[i], IDX_DATATYPE, i, 1, ctrl->comm, ctrl->sreq+i);
+ else
+ ASSERT(ctrl, lpwgts[i+1]-lpwgts[i] == 0);
+ }
+
+/*
+#ifdef DMALLOC
+ ASSERT(ctrl, dmalloc_verify(NULL) == DMALLOC_VERIFY_NOERROR);
+#endif
+*/
+
+ /* Wait for the send/recv to finish */
+ for (i=0; i<nparts; i++) {
+ if (sinfo[i].key > 0)
+ MPI_Wait(ctrl->sreq+i, &ctrl->status);
+ }
+ for (i=0; i<nparts; i++) {
+ if (rinfo[i].key > 0)
+ MPI_Wait(ctrl->rreq+i, &ctrl->status);
+ }
+
+ /* OK, now go and put the graph into GraphType Format */
+ mgraph = CreateGraph();
+ mgraph->gnvtxs = graph->gnvtxs;
+ mgraph->ncon = ncon;
+ mgraph->level = 0;
+ mgraph->nvtxs = mgraph->nedges = 0;
+ for (i=0; i<nparts; i++) {
+ mgraph->nvtxs += rinfo[i].key;
+ mgraph->nedges += rinfo[i].val;
+ }
+ nvtxs = mgraph->nvtxs;
+ xadj = mgraph->xadj = idxmalloc(nvtxs+1, "MMG: mgraph->xadj");
+ vwgt = mgraph->vwgt = idxmalloc(nvtxs*ncon, "MMG: mgraph->vwgt");
+ adjncy = mgraph->adjncy = idxmalloc(mgraph->nedges, "MMG: mgraph->adjncy");
+ adjwgt = mgraph->adjwgt = idxmalloc(mgraph->nedges, "MMG: mgraph->adjwgt");
+ mgraph->vtxdist = mvtxdist;
+
+ for (jj=ii=i=0; i<nvtxs; i++) {
+ xadj[i] = rgraph[ii++];
+ for (h=0; h<ncon; h++)
+ vwgt[i*ncon+h] = rgraph[ii++];
+ for (j=0; j<xadj[i]; j++) {
+ adjncy[jj] = rgraph[ii++];
+ adjwgt[jj++] = rgraph[ii++];
+ }
+ }
+ MAKECSR(i, nvtxs, xadj);
+
+ ASSERTP(ctrl, jj == mgraph->nedges, (ctrl, "%d %d\n", jj, mgraph->nedges));
+ ASSERTP(ctrl, ii == gpwgts[nparts], (ctrl, "%d %d %d %d %d\n", ii, gpwgts[nparts], jj, mgraph->nedges, nvtxs));
+
+ free(newlabel);
+
+#ifdef DEBUG
+ IFSET(ctrl->dbglvl, DBG_INFO, rprintf(ctrl, "Checking moved graph...\n"));
+ CheckMGraph(ctrl, mgraph);
+ IFSET(ctrl->dbglvl, DBG_INFO, rprintf(ctrl, "Moved graph is consistent.\n"));
+#endif
+
+ return mgraph;
+}
+
+
+/*************************************************************************
+* This function is used to transfer information from the moved graph
+* back to the original graph. The information is transfered from array
+* minfo to array info. The routine assumes that graph->where is left intact
+* and it is used to get the inverse mapping information.
+* The routine assumes that graph->where corresponds to a npes-way partition.
+**************************************************************************/
+void ProjectInfoBack(CtrlType *ctrl, GraphType *graph, idxtype *info, idxtype *minfo,
+ WorkSpaceType *wspace)
+{
+ int i, nvtxs, nparts;
+ idxtype *where, *auxinfo, *sinfo, *rinfo;
+
+ nparts = ctrl->npes;
+
+ nvtxs = graph->nvtxs;
+ where = graph->where;
+
+ sinfo = wspace->pv1;
+ rinfo = wspace->pv2;
+
+ /* Find out in rinfo how many entries are received per partition */
+ idxset(nparts, 0, rinfo);
+ for (i=0; i<nvtxs; i++)
+ rinfo[where[i]]++;
+
+ /* The rinfo are transposed and become the sinfo for the back-projection */
+ MPI_Alltoall((void *)rinfo, 1, IDX_DATATYPE, (void *)sinfo, 1, IDX_DATATYPE, ctrl->comm);
+
+ MAKECSR(i, nparts, sinfo);
+ MAKECSR(i, nparts, rinfo);
+
+ /* allocate memory for auxinfo */
+ auxinfo = idxmalloc(rinfo[nparts], "ProjectInfoBack: auxinfo");
+
+ /*-----------------------------------------------------------------
+ * Now, go and send back the minfo
+ -----------------------------------------------------------------*/
+ for (i=0; i<nparts; i++) {
+ if (rinfo[i+1]-rinfo[i] > 0)
+ MPI_Irecv((void *)(auxinfo+rinfo[i]), rinfo[i+1]-rinfo[i], IDX_DATATYPE, i, 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ for (i=0; i<nparts; i++) {
+ if (sinfo[i+1]-sinfo[i] > 0)
+ MPI_Isend((void *)(minfo+sinfo[i]), sinfo[i+1]-sinfo[i], IDX_DATATYPE, i, 1, ctrl->comm, ctrl->sreq+i);
+ }
+
+ /* Wait for the send/recv to finish */
+ for (i=0; i<nparts; i++) {
+ if (rinfo[i+1]-rinfo[i] > 0)
+ MPI_Wait(ctrl->rreq+i, &ctrl->status);
+ }
+ for (i=0; i<nparts; i++) {
+ if (sinfo[i+1]-sinfo[i] > 0)
+ MPI_Wait(ctrl->sreq+i, &ctrl->status);
+ }
+
+ /* Scatter the info received in auxinfo back to info. */
+ for (i=0; i<nvtxs; i++)
+ info[i] = auxinfo[rinfo[where[i]]++];
+
+ free(auxinfo);
+}
+
+
+
+/*************************************************************************
+* This function is used to convert a partition vector to a permutation
+* vector.
+**************************************************************************/
+void FindVtxPerm(CtrlType *ctrl, GraphType *graph, idxtype *perm, WorkSpaceType *wspace)
+{
+ int i, nvtxs, nparts;
+ idxtype *xadj, *adjncy, *adjwgt, *mvtxdist;
+ idxtype *where, *lpwgts, *gpwgts;
+
+ nparts = ctrl->nparts;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+
+ mvtxdist = idxmalloc(nparts+1, "MoveGraph: mvtxdist");
+
+ /* Let's do a prefix scan to determine the labeling of the nodes given */
+ lpwgts = wspace->pv1;
+ gpwgts = wspace->pv2;
+
+ /* Here we care about the count and not total weight (diff since graph may be weighted */
+ idxset(nparts, 0, lpwgts);
+ for (i=0; i<nvtxs; i++)
+ lpwgts[where[i]]++;
+
+ MPI_Scan((void *)lpwgts, (void *)gpwgts, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+ MPI_Allreduce((void *)lpwgts, (void *)mvtxdist, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+
+ MAKECSR(i, nparts, mvtxdist);
+
+ for (i=0; i<nparts; i++)
+ gpwgts[i] = mvtxdist[i] + gpwgts[i] - lpwgts[i]; /* We were interested in an exclusive Scan */
+
+ for (i=0; i<nvtxs; i++)
+ perm[i] = gpwgts[where[i]]++;
+
+ free(mvtxdist);
+
+}
+
+
+
+
+/*************************************************************************
+* This function quickly performs a check on the consistency of moved graph.
+**************************************************************************/
+void CheckMGraph(CtrlType *ctrl, GraphType *graph)
+{
+ int i, j, jj, k, nvtxs, firstvtx, lastvtx;
+ idxtype *xadj, *adjncy, *vtxdist;
+
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ vtxdist = graph->vtxdist;
+
+ firstvtx = vtxdist[ctrl->mype];
+ lastvtx = vtxdist[ctrl->mype+1];
+
+ for (i=0; i<nvtxs; i++) {
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ ASSERT(ctrl, firstvtx+i != adjncy[j]);
+ if (adjncy[j] >= firstvtx && adjncy[j] < lastvtx) {
+ k = adjncy[j]-firstvtx;
+ for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
+ if (adjncy[jj] == firstvtx+i)
+ break;
+ }
+ if (jj == xadj[k+1])
+ myprintf(ctrl, "(%d %d) but not (%d %d)\n", firstvtx+i, k, k, firstvtx+i);
+ }
+ }
+ }
+}
+
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/msetup.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/msetup.c
new file mode 100644
index 0000000..decfc65
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/msetup.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * msetup.c
+ *
+ * This file contain various routines for setting up a mesh
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: msetup.c,v 1.3 2003/07/31 06:14:01 karypis Exp $
+ *
+ */
+
+#include <parmetis.h>
+
+
+
+/*************************************************************************
+* This function setsup the CtrlType structure
+**************************************************************************/
+MeshType *SetUpMesh(int *etype, int *ncon, idxtype *elmdist, idxtype *elements,
+ idxtype *elmwgt, int *wgtflag, MPI_Comm *comm)
+{
+ MeshType *mesh;
+ int i, npes, mype;
+ int esizes[5] = {-1, 3, 4, 8, 4};
+ int maxnode, gmaxnode, minnode, gminnode;
+
+ MPI_Comm_size(*comm, &npes);
+ MPI_Comm_rank(*comm, &mype);
+
+ mesh = CreateMesh();
+ mesh->elmdist = elmdist;
+ mesh->gnelms = elmdist[npes];
+ mesh->nelms = elmdist[mype+1]-elmdist[mype];
+ mesh->elements = elements;
+ mesh->elmwgt = elmwgt;
+ mesh->etype = *etype;
+ mesh->ncon = *ncon;
+ mesh->esize = esizes[*etype];
+
+ if (((*wgtflag)&1) == 0) {
+ mesh->elmwgt = idxsmalloc(mesh->nelms*mesh->ncon, 1, "SetUpMesh: elmwgt");
+ }
+
+ minnode = elements[idxamin(mesh->nelms*mesh->esize, elements)];
+ MPI_Allreduce((void *)&minnode, (void *)&gminnode, 1, MPI_INT, MPI_MIN, *comm);
+ for (i=0; i<mesh->nelms*mesh->esize; i++)
+ elements[i] -= gminnode;
+ mesh->gminnode = gminnode;
+
+ maxnode = elements[idxamax(mesh->nelms*mesh->esize, elements)];
+ MPI_Allreduce((void *)&maxnode, (void *)&gmaxnode, 1, MPI_INT, MPI_MAX, *comm);
+ mesh->gnns = gmaxnode+1;
+
+ return mesh;
+}
+
+/*************************************************************************
+* This function creates a MeshType data structure and initializes
+* the various fields
+**************************************************************************/
+MeshType *CreateMesh(void)
+{
+ MeshType *mesh;
+
+ mesh = (MeshType *)GKmalloc(sizeof(MeshType), "CreateMesh: mesh");
+
+ InitMesh(mesh);
+
+ return mesh;
+}
+
+/*************************************************************************
+* This function initializes the various fields of a MeshType.
+**************************************************************************/
+void InitMesh(MeshType *mesh)
+{
+
+ mesh->etype = -1;
+ mesh->gnelms = -1;
+ mesh->gnns = -1;
+ mesh->nelms = -1;
+ mesh->nns = -1;
+ mesh->ncon = -1;
+ mesh->esize = -1;
+ mesh->gminnode = 0;
+ mesh->elmdist = NULL;
+ mesh->elements = NULL;
+ mesh->elmwgt = NULL;
+
+ return;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/node_refine.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/node_refine.c
new file mode 100644
index 0000000..3f57aa7
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/node_refine.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * node_refine.c
+ *
+ * This file contains code that performs the k-way refinement
+ *
+ * Started 3/1/96
+ * George
+ *
+ * $Id: node_refine.c,v 1.2 2003/07/21 17:18:50 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+#define PackWeightWhereInfo(a, b) (((a)<<10) + (b))
+#define SelectWhere(a) ((a)%1024)
+#define SelectWeight(a) (((a)>>10))
+
+
+
+/*************************************************************************
+* This function computes the initial id/ed
+**************************************************************************/
+void ComputeNodePartitionParams(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, j, nparts, nvtxs, nsep, firstvtx, lastvtx;
+ idxtype *xadj, *ladjncy, *adjwgt, *vtxdist, *vwgt, *lpwgts, *gpwgts, *sepind;
+ idxtype *where, *swhere, *rwhere;
+ NRInfoType *rinfo, *myrinfo;
+ int me, other, otherwgt;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->KWayInitTmr));
+
+ nvtxs = graph->nvtxs;
+ nparts = ctrl->nparts;
+
+ vtxdist = graph->vtxdist;
+ xadj = graph->xadj;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ vwgt = graph->vwgt;
+
+ where = graph->where;
+ rinfo = graph->nrinfo = (NRInfoType *)GKmalloc(sizeof(NRInfoType)*nvtxs, "ComputeNodePartitionParams: rinfo");
+ lpwgts = graph->lpwgts = idxsmalloc(2*nparts, 0, "ComputePartitionParams: lpwgts");
+ gpwgts = graph->gpwgts = idxmalloc(2*nparts, "ComputePartitionParams: gpwgts");
+ sepind = graph->sepind = idxmalloc(nvtxs, "ComputePartitionParams: sepind");
+
+ firstvtx = vtxdist[ctrl->mype];
+ lastvtx = vtxdist[ctrl->mype+1];
+
+ /*------------------------------------------------------------
+ / Send/Receive the where information of interface vertices.
+ / Also use this to also encode the vwgt information of this
+ / vertex. This is a hack, but it should work for now!
+ /------------------------------------------------------------*/
+ swhere = wspace->indices;
+ rwhere = where + nvtxs;
+
+ for (i=0; i<nvtxs; i++) {
+ ASSERTP(ctrl, where[i] >= 0 && where[i] < 2*nparts, (ctrl, "%d\n", where[i]) );
+ where[i] = PackWeightWhereInfo(vwgt[i], where[i]);
+ }
+
+ CommInterfaceData(ctrl, graph, where, swhere, rwhere);
+
+ /*------------------------------------------------------------
+ / Compute now the degrees
+ /------------------------------------------------------------*/
+ for (nsep=i=0; i<nvtxs; i++) {
+ me = SelectWhere(where[i]);
+ ASSERT(ctrl, me >= 0 && me < 2*nparts);
+ lpwgts[me] += vwgt[i];
+
+ if (me >= nparts) { /* If it is a separator vertex */
+ sepind[nsep++] = i;
+ lpwgts[2*nparts-1] += vwgt[i];
+
+ myrinfo = rinfo+i;
+ myrinfo->edegrees[0] = myrinfo->edegrees[1] = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ other = SelectWhere(where[ladjncy[j]]);
+ otherwgt = SelectWeight(where[ladjncy[j]]);
+ if (me != other)
+ myrinfo->edegrees[other%2] += otherwgt;
+ }
+ }
+ }
+ graph->nsep = nsep;
+
+ /* Finally, sum-up the partition weights */
+ MPI_Allreduce((void *)lpwgts, (void *)gpwgts, 2*nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+ graph->mincut = gpwgts[2*nparts-1];
+
+#ifdef XX
+ /* Print Weight information */
+ if (ctrl->mype == 0) {
+ for (i=0; i<nparts; i+=2)
+ printf("[%5d %5d %5d] ", gpwgts[i], gpwgts[i+1], gpwgts[nparts+i]);
+ printf("\n");
+ }
+#endif
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->KWayInitTmr));
+}
+
+
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void KWayNodeRefine(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace, int npasses, float ubfraction)
+{
+ int i, ii, j, k, pass, nvtxs, firstvtx, lastvtx, otherlastvtx, c, nmoves,
+ nlupd, nsupd, nnbrs, nchanged, nsep;
+ int npes = ctrl->npes, mype = ctrl->mype, nparts = ctrl->nparts;
+ idxtype *xadj, *ladjncy, *adjwgt, *vtxdist, *vwgt;
+ idxtype *where, *lpwgts, *gpwgts, *sepind;
+ idxtype *peind, *recvptr, *sendptr;
+ idxtype *update, *supdate, *rupdate, *pe_updates, *htable, *changed;
+ idxtype *badminpwgt, *badmaxpwgt;
+ KeyValueType *swchanges, *rwchanges;
+ int *nupds_pe;
+ NRInfoType *rinfo, *myrinfo;
+ int from, me, other, otherwgt, oldcut;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->KWayTmr));
+
+ nvtxs = graph->nvtxs;
+
+ vtxdist = graph->vtxdist;
+ xadj = graph->xadj;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ vwgt = graph->vwgt;
+
+ firstvtx = vtxdist[mype];
+ lastvtx = vtxdist[mype+1];
+
+ where = graph->where;
+ rinfo = graph->nrinfo;
+ lpwgts = graph->lpwgts;
+ gpwgts = graph->gpwgts;
+
+ nsep = graph->nsep;
+ sepind = graph->sepind;
+
+ nnbrs = graph->nnbrs;
+ peind = graph->peind;
+ recvptr = graph->recvptr;
+ sendptr = graph->sendptr;
+
+ changed = idxmalloc(nvtxs, "KWayRefine: changed");
+ rwchanges = wspace->pairs;
+ swchanges = rwchanges + recvptr[nnbrs];
+
+ update = idxmalloc(nvtxs, "KWayRefine: update");
+ supdate = wspace->indices;
+ rupdate = supdate + recvptr[nnbrs];
+ nupds_pe = imalloc(npes, "KWayRefine: nupds_pe");
+
+ htable = idxsmalloc(nvtxs+graph->nrecv, 0, "KWayRefine: lhtable");
+
+ badminpwgt = wspace->pv1;
+ badmaxpwgt = wspace->pv2;
+
+ for (i=0; i<nparts; i+=2) {
+ badminpwgt[i] = badminpwgt[i+1] = (1.0/ubfraction)*(gpwgts[i]+gpwgts[i+1])/2;
+ badmaxpwgt[i] = badmaxpwgt[i+1] = ubfraction*(gpwgts[i]+gpwgts[i+1])/2;
+ }
+
+ IFSET(ctrl->dbglvl, DBG_REFINEINFO, PrintNodeBalanceInfo(ctrl, nparts, gpwgts, badminpwgt, badmaxpwgt, 1));
+
+ for (pass=0; pass<npasses; pass++) {
+ oldcut = graph->mincut;
+
+ for (c=0; c<2; c++) {
+ for (i=0; i<nparts; i+=2) {
+ badminpwgt[i] = badminpwgt[i+1] = (1.0/ubfraction)*(gpwgts[i]+gpwgts[i+1])/2;
+ badmaxpwgt[i] = badmaxpwgt[i+1] = ubfraction*(gpwgts[i]+gpwgts[i+1])/2;
+ }
+
+ nlupd = nsupd = nmoves = nchanged = 0;
+ for (ii=0; ii<nsep; ii++) {
+ i = sepind[ii];
+ from = SelectWhere(where[i]);
+
+ ASSERT(ctrl, from >= nparts);
+
+ /* Go through the loop if gain is possible for the separator vertex */
+ if (rinfo[i].edegrees[(c+1)%2] <= vwgt[i]) {
+ other = from%nparts+c; /* It is one-sided move so we know where it goes */
+
+ if (gpwgts[other]+vwgt[i] > badmaxpwgt[other]) {
+ /* printf("Skip because of weight! %d\n", vwgt[i]-rinfo[i].edegrees[(c+1)%2]); */
+ continue; /* We cannot move it there because it gets too heavy */
+ }
+
+ /* Update where, weight, and ID/ED information of the vertex you moved */
+ where[i] = PackWeightWhereInfo(vwgt[i], other);
+
+ /* Remove this vertex from the sepind. Note the trick for looking at the sepind[ii] again */
+ sepind[ii--] = sepind[--nsep];
+
+ /* myprintf(ctrl, "Vertex %d [%d %d] is moving to %d from %d [%d]\n", i+firstvtx, vwgt[i], rinfo[i].edegrees[(c+1)%2], other, from, SelectWhere(where[i])); */
+
+ lpwgts[from] -= vwgt[i];
+ lpwgts[2*nparts-1] -= vwgt[i];
+ lpwgts[other] += vwgt[i];
+ gpwgts[other] += vwgt[i];
+
+ /*
+ * Put the vertices adjacent to i that belong to either the separator or
+ * the (c+1)%2 partition into the update array
+ */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = ladjncy[j];
+ if (htable[k] == 0 && SelectWhere(where[k]) != other) {
+ htable[k] = 1;
+ if (k<nvtxs)
+ update[nlupd++] = k;
+ else
+ supdate[nsupd++] = k;
+ }
+ }
+ nmoves++;
+ if (graph->pexadj[i+1]-graph->pexadj[i] > 0)
+ changed[nchanged++] = i;
+ }
+ }
+
+ /* myprintf(ctrl, "nmoves: %d, nlupd: %d, nsupd: %d\n", nmoves, nlupd, nsupd); */
+
+ /* Tell everybody interested what the new where[] info is for the interface vertices */
+ CommChangedInterfaceData(ctrl, graph, nchanged, changed, where, swchanges, rwchanges, wspace->pv4);
+
+
+ IFSET(ctrl->dbglvl, DBG_RMOVEINFO, rprintf(ctrl, "\t[%d %d], [%d %d %d]\n",
+ pass, c, GlobalSESum(ctrl, nmoves), GlobalSESum(ctrl, nsupd), GlobalSESum(ctrl, nlupd)));
+
+
+ /*-------------------------------------------------------------
+ / Time to communicate with processors to send the vertices
+ / whose degrees need to be update.
+ /-------------------------------------------------------------*/
+ /* Issue the receives first */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Irecv((void *)(rupdate+sendptr[i]), sendptr[i+1]-sendptr[i], IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ /* Issue the sends next. This needs some preporcessing */
+ for (i=0; i<nsupd; i++) {
+ htable[supdate[i]] = 0;
+ supdate[i] = graph->imap[supdate[i]];
+ }
+ iidxsort(nsupd, supdate);
+
+ for (j=i=0; i<nnbrs; i++) {
+ otherlastvtx = vtxdist[peind[i]+1];
+ for (k=j; k<nsupd && supdate[k] < otherlastvtx; k++);
+ MPI_Isend((void *)(supdate+j), k-j, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ j = k;
+ }
+
+ /* OK, now get into the loop waiting for the send/recv operations to finish */
+ MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+ for (i=0; i<nnbrs; i++)
+ MPI_Get_count(ctrl->statuses+i, IDX_DATATYPE, nupds_pe+i);
+ MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+
+
+ /*-------------------------------------------------------------
+ / Place the received to-be updated vertices into update[]
+ /-------------------------------------------------------------*/
+ for (i=0; i<nnbrs; i++) {
+ pe_updates = rupdate+sendptr[i];
+ for (j=0; j<nupds_pe[i]; j++) {
+ k = pe_updates[j];
+ if (htable[k-firstvtx] == 0) {
+ htable[k-firstvtx] = 1;
+ update[nlupd++] = k-firstvtx;
+ }
+ }
+ }
+
+
+ /*-------------------------------------------------------------
+ / Update the where information of the vertices that are pulled
+ / into the separator.
+ /-------------------------------------------------------------*/
+ nchanged = 0;
+ for (ii=0; ii<nlupd; ii++) {
+ i = update[ii];
+ me = SelectWhere(where[i]);
+ if (me < nparts && me%2 == (c+1)%2) { /* This vertex is pulled into the separator */
+ lpwgts[me] -= vwgt[i];
+ where[i] = PackWeightWhereInfo(vwgt[i], nparts+me-(me%2));
+ sepind[nsep++] = i; /* Put the vertex into the sepind array */
+ if (graph->pexadj[i+1]-graph->pexadj[i] > 0)
+ changed[nchanged++] = i;
+
+ lpwgts[SelectWhere(where[i])] += vwgt[i];
+ lpwgts[2*nparts-1] += vwgt[i];
+ /* myprintf(ctrl, "Vertex %d moves into the separator from %d to %d\n", i+firstvtx, me, SelectWhere(where[i])); */
+ }
+ }
+
+ /* Tell everybody interested what the new where[] info is for the interface vertices */
+ CommChangedInterfaceData(ctrl, graph, nchanged, changed, where, swchanges, rwchanges, wspace->pv4);
+
+
+ /*-------------------------------------------------------------
+ / Update the rinfo of the vertices in the update[] array
+ /-------------------------------------------------------------*/
+ for (ii=0; ii<nlupd; ii++) {
+ i = update[ii];
+ ASSERT(ctrl, htable[i] == 1);
+
+ htable[i] = 0;
+
+ me = SelectWhere(where[i]);
+ if (me >= nparts) { /* If it is a separator vertex */
+ /* myprintf(ctrl, "Updating %d %d\n", i+firstvtx, me); */
+
+ myrinfo = rinfo+i;
+ myrinfo->edegrees[0] = myrinfo->edegrees[1] = 0;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ other = SelectWhere(where[ladjncy[j]]);
+ otherwgt = SelectWeight(where[ladjncy[j]]);
+ if (me != other)
+ myrinfo->edegrees[other%2] += otherwgt;
+ }
+ }
+ }
+
+ /* Finally, sum-up the partition weights */
+ MPI_Allreduce((void *)lpwgts, (void *)gpwgts, 2*nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+ graph->mincut = gpwgts[2*nparts-1];
+
+ IFSET(ctrl->dbglvl, DBG_REFINEINFO, PrintNodeBalanceInfo(ctrl, nparts, gpwgts, badminpwgt, badmaxpwgt, 0));
+ }
+
+ if (graph->mincut == oldcut)
+ break;
+ }
+
+ /* Go and clear-up the where array */
+ for (i=0; i<nvtxs+graph->nrecv; i++)
+ where[i] = SelectWhere(where[i]);
+
+ GKfree((void **)&update, (void **)&nupds_pe, (void **)&htable, (void **)&changed, LTERM);
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->KWayTmr));
+}
+
+
+
+
+/*************************************************************************
+* This function prints balance information for the parallel k-section
+* refinement algorithm
+**************************************************************************/
+void PrintNodeBalanceInfo(CtrlType *ctrl, int nparts, idxtype *gpwgts, idxtype *badminpwgt, idxtype *badmaxpwgt, int title)
+{
+ int i;
+
+ if (ctrl->mype == 0) {
+ if (title)
+ printf("K-way sep-refinement: TotalSep: %d, ", gpwgts[2*nparts-1]);
+ else
+ printf("\tTotalSep: %d, ", gpwgts[2*nparts-1]);
+
+ for (i=0; i<nparts; i+=2)
+ printf(" [%5d %5d %5d %5d %5d]", gpwgts[i], gpwgts[i+1], gpwgts[nparts+i], badminpwgt[i], badmaxpwgt[i]);
+ printf("\n");
+ }
+ MPI_Barrier(ctrl->comm);
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ometis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ometis.c
new file mode 100644
index 0000000..1a461f1
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/ometis.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * ometis.c
+ *
+ * This is the entry point of parallel ordering
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: ometis.c,v 1.4 2003/07/25 04:01:04 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel ordering algorithm.
+* This function assumes that the graph is already nice partitioned among the
+* processors and then proceeds to perform recursive bisection.
+************************************************************************************/
+void ParMETIS_V3_NodeND(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, int *numflag,
+ int *options, idxtype *order, idxtype *sizes, MPI_Comm *comm)
+{
+ int i, j;
+ int ltvwgts[MAXNCON];
+ int nparts, npes, mype, wgtflag = 0, seed = GLOBAL_SEED;
+ CtrlType ctrl;
+ WorkSpaceType wspace;
+ GraphType *graph, *mgraph;
+ idxtype *morder;
+ int minnvtxs;
+
+ MPI_Comm_size(*comm, &npes);
+ MPI_Comm_rank(*comm, &mype);
+ nparts = npes;
+
+ if (!ispow2(npes)) {
+ if (mype == 0)
+ printf("Error: The number of processors must be a power of 2!\n");
+ return;
+ }
+
+ if (vtxdist[npes] < (int)((float)(npes*npes)*1.2)) {
+ if (mype == 0)
+ printf("Error: Too many processors for this many vertices.\n");
+ return;
+ }
+
+ minnvtxs = vtxdist[1]-vtxdist[0];
+ for (i=0; i<npes; i++)
+ minnvtxs = (minnvtxs < vtxdist[i+1]-vtxdist[i]) ? minnvtxs : vtxdist[i+1]-vtxdist[i];
+
+ if (minnvtxs < (int)((float)npes*1.1)) {
+ if (mype == 0)
+ printf("Error: vertices are not distributed equally.\n");
+ return;
+ }
+
+
+ if (*numflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, order, npes, mype, 1);
+
+ SetUpCtrl(&ctrl, nparts, options[PMV3_OPTION_DBGLVL], *comm);
+ ctrl.CoarsenTo = amin(vtxdist[npes]+1, 25*npes);
+
+ ctrl.CoarsenTo = amin(vtxdist[npes]+1, 25*amax(npes, nparts));
+ ctrl.seed = mype;
+ ctrl.sync = seed;
+ ctrl.partType = STATIC_PARTITION;
+ ctrl.ps_relation = -1;
+ ctrl.tpwgts = fsmalloc(nparts, 1.0/(float)(nparts), "tpwgts");
+ ctrl.ubvec[0] = 1.03;
+
+ graph = Moc_SetUpGraph(&ctrl, 1, vtxdist, xadj, NULL, adjncy, NULL, &wgtflag);
+
+ PreAllocateMemory(&ctrl, graph, &wspace);
+
+ /*=======================================================
+ * Compute the initial k-way partitioning
+ =======================================================*/
+ IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
+
+ Moc_Global_Partition(&ctrl, graph, &wspace);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl));
+
+ /*=======================================================
+ * Move the graph according to the partitioning
+ =======================================================*/
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.MoveTmr));
+
+ MALLOC_CHECK(NULL);
+ graph->ncon = 1;
+ mgraph = Moc_MoveGraph(&ctrl, graph, &wspace);
+ MALLOC_CHECK(NULL);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.MoveTmr));
+
+ /*=======================================================
+ * Now compute an ordering of the moved graph
+ =======================================================*/
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
+
+ FreeWSpace(&wspace);
+ PreAllocateMemory(&ctrl, mgraph, &wspace);
+
+ ctrl.ipart = ISEP_NODE;
+ ctrl.CoarsenTo = amin(vtxdist[npes]+1, amax(20*npes, 1000));
+
+ /* compute tvwgts */
+ for (j=0; j<mgraph->ncon; j++)
+ ltvwgts[j] = 0;
+
+ for (i=0; i<mgraph->nvtxs; i++)
+ for (j=0; j<mgraph->ncon; j++)
+ ltvwgts[j] += mgraph->vwgt[i*mgraph->ncon+j];
+
+ for (j=0; j<mgraph->ncon; j++)
+ ctrl.tvwgts[j] = GlobalSESum(&ctrl, ltvwgts[j]);
+
+ mgraph->nvwgt = fmalloc(mgraph->nvtxs*mgraph->ncon, "mgraph->nvwgt");
+ for (i=0; i<mgraph->nvtxs; i++)
+ for (j=0; j<mgraph->ncon; j++)
+ mgraph->nvwgt[i*mgraph->ncon+j] = (float)(mgraph->vwgt[i*mgraph->ncon+j]) / (float)(ctrl.tvwgts[j]);
+
+
+ morder = idxmalloc(mgraph->nvtxs, "PAROMETIS: morder");
+ MultilevelOrder(&ctrl, mgraph, morder, sizes, &wspace);
+
+ MALLOC_CHECK(NULL);
+
+ /* Invert the ordering back to the original graph */
+ ProjectInfoBack(&ctrl, graph, order, morder, &wspace);
+
+ MALLOC_CHECK(NULL);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+
+ free(ctrl.tpwgts);
+ free(morder);
+ FreeGraph(mgraph);
+ FreeInitialGraphAndRemap(graph, 0);
+ FreeWSpace(&wspace);
+ FreeCtrl(&ctrl);
+
+ if (*numflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, order, npes, mype, 0);
+
+ MALLOC_CHECK(NULL);
+}
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel ordering algorithm.
+* This function assumes that the graph is already nice partitioned among the
+* processors and then proceeds to perform recursive bisection.
+************************************************************************************/
+void PAROMETIS(idxtype *vtxdist, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt,
+ idxtype *order, idxtype *sizes, int *options, MPI_Comm comm)
+{
+ int numflag, newoptions[5];
+
+ newoptions[0] = 1;
+ newoptions[PMV3_OPTION_DBGLVL] = options[4];
+ newoptions[PMV3_OPTION_SEED] = GLOBAL_SEED;
+
+ numflag = options[3];
+
+ ParMETIS_V3_NodeND(vtxdist, xadj, adjncy, &numflag, newoptions, order, sizes, &comm);
+
+ options[0] = -1;
+
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/order.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/order.c
new file mode 100644
index 0000000..a73c87b
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/order.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * order.c
+ *
+ * This file contains the driving routines for the multilevel ordering algorithm
+ *
+ * Started 5/3/97
+ * George
+ *
+ * $Id: order.c,v 1.2 2003/07/21 17:18:50 karypis Exp $
+ *
+ */
+
+#define DEBUG_ORDER_
+
+#include <parmetislib.h>
+
+/*************************************************************************
+* This is the top level ordering routine
+**************************************************************************/
+void MultilevelOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, idxtype *sizes, WorkSpaceType *wspace)
+{
+ int i, nparts, nvtxs, npes;
+ idxtype *perm, *lastnode, *morder, *porder;
+ GraphType *mgraph;
+
+ npes = ctrl->npes;
+ nvtxs = graph->nvtxs;
+
+ perm = idxmalloc(nvtxs, "MultilevelOrder: perm");
+ lastnode = idxsmalloc(4*npes, -1, "MultilevelOrder: lastnode");
+
+ for (i=0; i<nvtxs; i++)
+ perm[i] = i;
+ lastnode[2] = graph->gnvtxs;
+
+ idxset(nvtxs, -1, order);
+
+ sizes[0] = 2*npes-1;
+
+ graph->where = idxsmalloc(nvtxs, 0, "MultilevelOrder: graph->where");
+
+ for (nparts=2; nparts<=ctrl->npes; nparts*=2) {
+ ctrl->nparts = nparts;
+
+ Order_Partition(ctrl, graph, wspace);
+
+ LabelSeparators(ctrl, graph, lastnode, perm, order, sizes, wspace);
+
+ CompactGraph(ctrl, graph, perm, wspace);
+
+ if (ctrl->CoarsenTo < 100*nparts) {
+ ctrl->CoarsenTo = 1.5*ctrl->CoarsenTo;
+ }
+ ctrl->CoarsenTo = amin(ctrl->CoarsenTo, graph->gnvtxs-1);
+ }
+
+
+ /*-----------------------------------------------------------------
+ / Move the graph so that each processor gets its partition
+ -----------------------------------------------------------------*/
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MoveTmr));
+
+ SetUp(ctrl, graph, wspace);
+ graph->ncon = 1; /*needed for Moc_MoveGraph */
+ mgraph = Moc_MoveGraph(ctrl, graph, wspace);
+
+ /* Fill in the sizes[] array for the local part. Just the vtxdist of the mgraph */
+ for (i=0; i<npes; i++)
+ sizes[i] = mgraph->vtxdist[i+1]-mgraph->vtxdist[i];
+
+ porder = idxmalloc(graph->nvtxs, "MultilevelOrder: porder");
+ morder = idxmalloc(mgraph->nvtxs, "MultilevelOrder: morder");
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MoveTmr));
+
+ /* Find the local ordering */
+ LocalNDOrder(ctrl, mgraph, morder, lastnode[2*(ctrl->npes+ctrl->mype)]-mgraph->nvtxs, wspace);
+
+ /* Project the ordering back to the before-move graph */
+ ProjectInfoBack(ctrl, graph, porder, morder, wspace);
+
+ /* Copy the ordering from porder to order using perm */
+ for (i=0; i<graph->nvtxs; i++) {
+ ASSERT(ctrl, order[perm[i]] == -1);
+ order[perm[i]] = porder[i];
+ }
+
+ FreeGraph(mgraph);
+ GKfree((void **)&perm, (void **)&lastnode, (void **)&porder, (void **)&morder, LTERM);
+
+ /* PrintVector(ctrl, 2*npes-1, 0, sizes, "SIZES"); */
+}
+
+
+/*************************************************************************
+* This function is used to assign labels to the nodes in the separators
+* It uses the appropriate entry in the lastnode array to select label
+* boundaries and adjusts it for the next level
+**************************************************************************/
+void LabelSeparators(CtrlType *ctrl, GraphType *graph, idxtype *lastnode, idxtype *perm, idxtype *order, idxtype *sizes, WorkSpaceType *wspace)
+{
+ int i, nvtxs, nparts, sid;
+ idxtype *where, *lpwgts, *gpwgts, *sizescan;
+
+ nparts = ctrl->nparts;
+
+ nvtxs = graph->nvtxs;
+ where = graph->where;
+ lpwgts = graph->lpwgts;
+ gpwgts = graph->gpwgts;
+
+ /* Compute the local size of the separator. This is required in case the
+ * graph has vertex weights */
+ idxset(2*nparts, 0, lpwgts);
+ for (i=0; i<nvtxs; i++)
+ lpwgts[where[i]]++;
+
+ sizescan = idxmalloc(2*nparts, "LabelSeparators: sizescan");
+
+ /* Perform a Prefix scan of the separator sizes to determine the boundaries */
+ MPI_Scan((void *)lpwgts, (void *)sizescan, 2*nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+ MPI_Allreduce((void *)lpwgts, (void *)gpwgts, 2*nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+
+#ifdef DEBUG_ORDER
+ PrintVector(ctrl, 2*nparts, 0, lpwgts, "Lpwgts");
+ PrintVector(ctrl, 2*nparts, 0, sizescan, "SizeScan");
+ PrintVector(ctrl, 2*nparts, 0, lastnode, "LastNode");
+#endif
+
+ /* Fillin the sizes[] array */
+ for (i=nparts-2; i>=0; i-=2)
+ sizes[--sizes[0]] = gpwgts[nparts+i];
+
+ if (ctrl->dbglvl&DBG_INFO) {
+ if (ctrl->mype == 0) {
+ printf("SepSizes: ");
+ for (i=0; i<nparts; i+=2)
+ printf(" %d [%d %d]", gpwgts[nparts+i], gpwgts[i], gpwgts[i+1]);
+ printf("\n");
+ }
+ MPI_Barrier(ctrl->comm);
+ }
+
+ for (i=0; i<2*nparts; i++)
+ sizescan[i] -= lpwgts[i];
+
+ for (i=0; i<nvtxs; i++) {
+ if (where[i] >= nparts) {
+ sid = where[i];
+ sizescan[sid]++;
+ ASSERT(ctrl, order[perm[i]] == -1);
+ order[perm[i]] = lastnode[sid] - sizescan[sid];
+ /* myprintf(ctrl, "order[%d] = %d, %d\n", perm[i], order[perm[i]], sid); */
+ }
+ }
+
+ /* Update lastnode array */
+ idxcopy(2*nparts, lastnode, sizescan);
+ for (i=0; i<nparts; i+=2) {
+ lastnode[2*nparts+2*i] = sizescan[nparts+i]-gpwgts[nparts+i]-gpwgts[i+1];
+ lastnode[2*nparts+2*(i+1)] = sizescan[nparts+i]-gpwgts[nparts+i];
+ }
+
+ free(sizescan);
+
+}
+
+
+
+
+/*************************************************************************
+* This function compacts a graph by removing the vertex separator
+**************************************************************************/
+void CompactGraph(CtrlType *ctrl, GraphType *graph, idxtype *perm, WorkSpaceType *wspace)
+{
+ int i, j, l, nvtxs, cnvtxs, cfirstvtx, nparts, npes;
+ idxtype *xadj, *ladjncy, *adjwgt, *vtxdist, *where;
+ idxtype *cmap, *cvtxdist, *newwhere;
+
+ nparts = ctrl->nparts;
+ npes = ctrl->npes;
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ ladjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+
+ if (graph->cmap == NULL)
+ graph->cmap = idxmalloc(nvtxs+graph->nrecv, "CompactGraph: cmap");
+ cmap = graph->cmap;
+
+ vtxdist = graph->vtxdist;
+
+ /*************************************************************
+ * Construct the cvtxdist of the contracted graph. Uses the fact
+ * that lpwgts stores the local non separator vertices.
+ **************************************************************/
+ cvtxdist = wspace->pv1;
+ cnvtxs = cvtxdist[npes] = idxsum(nparts, graph->lpwgts);
+
+ MPI_Allgather((void *)(cvtxdist+npes), 1, IDX_DATATYPE, (void *)cvtxdist, 1, IDX_DATATYPE, ctrl->comm);
+ MAKECSR(i, npes, cvtxdist);
+
+#ifdef DEBUG_ORDER
+ PrintVector(ctrl, npes+1, 0, cvtxdist, "cvtxdist");
+#endif
+
+
+ /*************************************************************
+ * Construct the cmap vector
+ **************************************************************/
+ cfirstvtx = cvtxdist[ctrl->mype];
+
+ /* Create the cmap of what you know so far locally */
+ for (cnvtxs=0, i=0; i<nvtxs; i++) {
+ if (where[i] < nparts) {
+ perm[cnvtxs] = perm[i];
+ cmap[i] = cfirstvtx + cnvtxs++;
+ }
+ }
+
+ CommInterfaceData(ctrl, graph, cmap, wspace->indices, cmap+nvtxs);
+
+
+ /*************************************************************
+ * Finally, compact the graph
+ **************************************************************/
+ newwhere = idxmalloc(cnvtxs, "CompactGraph: newwhere");
+ cnvtxs = l = 0;
+ for (i=0; i<nvtxs; i++) {
+ if (where[i] < nparts) {
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ if (where[i] == where[ladjncy[j]]) {
+ ladjncy[l] = cmap[ladjncy[j]];
+ adjwgt[l++] = adjwgt[j];
+ }
+#ifdef DEBUG_ORDER
+ else if (where[ladjncy[j]] < nparts)
+ printf("It seems that the separation has failed: %d %d\n", where[i], where[ladjncy[j]]);
+#endif
+ }
+
+ xadj[cnvtxs] = l;
+ graph->vwgt[cnvtxs] = graph->vwgt[i];
+ newwhere[cnvtxs] = where[i];
+ cnvtxs++;
+ }
+ }
+ for (i=cnvtxs; i>0; i--)
+ xadj[i] = xadj[i-1];
+ xadj[0] = 0;
+
+ GKfree((void **)&graph->match, (void **)&graph->cmap, (void **)&graph->lperm, (void **)&graph->where, (void **)&graph->label, (void **)&graph->rinfo,
+ (void **)&graph->nrinfo, (void **)&graph->lpwgts, (void **)&graph->gpwgts, (void **)&graph->sepind, (void **)&graph->peind,
+ (void **)&graph->sendptr, (void **)&graph->sendind, (void **)&graph->recvptr, (void **)&graph->recvind,
+ (void **)&graph->imap, (void **)&graph->rlens, (void **)&graph->slens, (void **)&graph->rcand, (void **)&graph->pexadj,
+ (void **)&graph->peadjncy, (void **)&graph->peadjloc, LTERM);
+
+ graph->nvtxs = cnvtxs;
+ graph->nedges = l;
+ graph->gnvtxs = cvtxdist[npes];
+ idxcopy(npes+1, cvtxdist, graph->vtxdist);
+ graph->where = newwhere;
+
+}
+
+
+/*************************************************************************
+* This function orders the locally stored graph using MMD.
+* The vertices will be ordered from firstnode onwards.
+**************************************************************************/
+void LocalNDOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, int firstnode, WorkSpaceType *wspace)
+{
+ int i, j, nvtxs, firstvtx, lastvtx;
+ idxtype *xadj, *adjncy;
+ idxtype *perm, *iperm;
+ int numflag=0, options[10];
+
+ nvtxs = graph->nvtxs;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+
+ firstvtx = graph->vtxdist[ctrl->mype];
+ lastvtx = graph->vtxdist[ctrl->mype+1];
+
+ /* Relabel the vertices so that they are in local index space */
+ for (i=0; i<nvtxs; i++) {
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ ASSERT(ctrl, adjncy[j]>=firstvtx && adjncy[j]<lastvtx);
+ adjncy[j] -= firstvtx;
+ }
+ }
+
+ ASSERT(ctrl, 2*(nvtxs+5) < wspace->maxcore);
+
+ perm = wspace->core;
+ iperm = perm + nvtxs + 5;
+
+ options[0] = 0;
+ METIS_NodeND(&nvtxs, xadj, adjncy, &numflag, options, perm, iperm);
+
+ for (i=0; i<nvtxs; i++) {
+ ASSERT(ctrl, iperm[i]>=0 && iperm[i]<nvtxs);
+ order[i] = firstnode+iperm[i];
+ }
+
+}
+
+/*************************************************************************
+* This function is the driver for the partition refinement mode of ParMETIS
+**************************************************************************/
+void Order_Partition(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+
+ SetUp(ctrl, graph, wspace);
+ graph->ncon = 1;
+
+ IFSET(ctrl->dbglvl, DBG_PROGRESS, rprintf(ctrl, "[%6d %8d %5d %5d][%d][%d]\n",
+ graph->gnvtxs, GlobalSESum(ctrl, graph->nedges), GlobalSEMin(ctrl, graph->nvtxs),
+ GlobalSEMax(ctrl, graph->nvtxs), ctrl->CoarsenTo,
+ GlobalSEMax(ctrl, graph->vwgt[idxamax(graph->nvtxs, graph->vwgt)])));
+
+ if (graph->gnvtxs < 1.3*ctrl->CoarsenTo || (graph->finer != NULL && graph->gnvtxs > graph->finer->gnvtxs*COARSEN_FRACTION)) {
+ /* Compute the initial npart-way multisection */
+ InitMultisection(ctrl, graph, wspace);
+
+ if (graph->finer == NULL) { /* Do that only of no-coarsening took place */
+ ComputeNodePartitionParams(ctrl, graph, wspace);
+ KWayNodeRefine(ctrl, graph, wspace, 2*NGR_PASSES, ORDER_UNBALANCE_FRACTION);
+ }
+ }
+ else { /* Coarsen it and the partition it */
+ Mc_LocalMatch_HEM(ctrl, graph, wspace);
+
+ Order_Partition(ctrl, graph->coarser, wspace);
+
+ Moc_ProjectPartition(ctrl, graph, wspace);
+ ComputeNodePartitionParams(ctrl, graph, wspace);
+ KWayNodeRefine(ctrl, graph, wspace, 2*NGR_PASSES, ORDER_UNBALANCE_FRACTION);
+ }
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/parmetislib.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/parmetislib.h
new file mode 100644
index 0000000..36c1041
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/parmetislib.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * par_metis.h
+ *
+ * This file includes all necessary header files
+ *
+ * Started 8/27/94
+ * George
+ *
+ * $Id: parmetislib.h,v 1.2 2003/07/21 17:50:22 karypis Exp $
+ */
+
+/*
+#define DEBUG 1
+#define DMALLOC 1
+*/
+
+#include <stdheaders.h>
+#include "../parmetis.h"
+
+#ifdef DMALLOC
+#include <dmalloc.h>
+#endif
+
+#include <rename.h>
+#include <defs.h>
+#include <struct.h>
+#include <macros.h>
+#include <proto.h>
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/proto.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/proto.h
new file mode 100644
index 0000000..bbab2e5
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/proto.h
@@ -0,0 +1,352 @@
+/*
+ * 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.11 2003/07/25 13:52:03 karypis Exp $
+ *
+ */
+
+/* kmetis.c */
+void Moc_Global_Partition(CtrlType *, GraphType *, WorkSpaceType *);
+
+/* mmetis.c */
+
+/* gkmetis.c */
+
+/* match.c */
+void Moc_GlobalMatch_Balance(CtrlType *, GraphType *, WorkSpaceType *);
+
+/* coarsen.c */
+void Moc_Global_CreateCoarseGraph(CtrlType *, GraphType *, WorkSpaceType *, int);
+
+/* initpart.c */
+void Moc_InitPartition_RB(CtrlType *, GraphType *, WorkSpaceType *);
+void Moc_KeepPart(GraphType *, WorkSpaceType *, idxtype *, int);
+
+/* kwayrefine.c */
+void Moc_ProjectPartition(CtrlType *, GraphType *, WorkSpaceType *);
+void Moc_ComputePartitionParams(CtrlType *, GraphType *, WorkSpaceType *);
+
+/* kwayfm.c */
+void Moc_KWayFM(CtrlType *, GraphType *, WorkSpaceType *, int);
+
+/* kwaybalance.c */
+void Moc_KWayBalance(CtrlType *, GraphType *, WorkSpaceType *, int);
+
+/* remap.c */
+void ParallelReMapGraph(CtrlType *, GraphType *, WorkSpaceType *);
+void ParallelTotalVReMap(CtrlType *, idxtype *, idxtype *, WorkSpaceType *, int, int);
+int SimilarTpwgts(float *, int, int, int);
+
+/* move.c */
+GraphType *Moc_MoveGraph(CtrlType *, GraphType *, WorkSpaceType *);
+/* move.c */
+void CheckMGraph(CtrlType *, GraphType *);
+void ProjectInfoBack(CtrlType *, GraphType *, idxtype *, idxtype *, WorkSpaceType *);
+void FindVtxPerm(CtrlType *, GraphType *, idxtype *, WorkSpaceType *);
+
+/* memory.c */
+void PreAllocateMemory(CtrlType *, GraphType *, WorkSpaceType *);
+void FreeWSpace(WorkSpaceType *);
+void FreeCtrl(CtrlType *);
+GraphType *CreateGraph(void);
+void InitGraph(GraphType *);
+void FreeGraph(GraphType *);
+void FreeInitialGraphAndRemap(GraphType *, int);
+
+
+/* ametis.c */
+void Adaptive_Partition(CtrlType *, GraphType *, WorkSpaceType *);
+
+/* rmetis.c */
+
+
+/* lmatch.c */
+void Mc_LocalMatch_HEM(CtrlType *, GraphType *, WorkSpaceType *);
+void Mc_Local_CreateCoarseGraph(CtrlType *, GraphType *, WorkSpaceType *, int);
+
+/* wave.c */
+float WavefrontDiffusion(CtrlType *, GraphType *, idxtype *);
+
+/* balancemylink.c */
+int BalanceMyLink(CtrlType *, GraphType *, idxtype *, int, int, float *, float, float *, float *, float);
+
+/* redomylink.c */
+void RedoMyLink(CtrlType *, GraphType *, idxtype *, int, int, float *, float *, float *);
+
+/* initbalance.c */
+void Balance_Partition(CtrlType *, GraphType *, WorkSpaceType *);
+GraphType *Moc_AssembleAdaptiveGraph(CtrlType *, GraphType *, WorkSpaceType *);
+
+/* mdiffusion.c */
+int Moc_Diffusion(CtrlType *, GraphType *, idxtype *, idxtype *, idxtype *, WorkSpaceType *, int);
+GraphType *ExtractGraph(CtrlType *, GraphType *, idxtype *, idxtype *, idxtype *);
+
+/* diffutil.c */
+void SetUpConnectGraph(GraphType *, MatrixType *, idxtype *);
+void Mc_ComputeMoveStatistics(CtrlType *, GraphType *, int *, int *, int *);
+ int Mc_ComputeSerialTotalV(GraphType *, idxtype *);
+void ComputeLoad(GraphType *, int, float *, float *, int);
+void ConjGrad2(MatrixType *, float *, float *, float, float *);
+void mvMult2(MatrixType *, float *, float *);
+void ComputeTransferVector(int, MatrixType *, float *, float *, int);
+int ComputeSerialEdgeCut(GraphType *);
+int ComputeSerialTotalV(GraphType *, idxtype *);
+
+/* akwayfm.c */
+void Moc_KWayAdaptiveRefine(CtrlType *, GraphType *, WorkSpaceType *, int);
+
+/* selectq.c */
+void Moc_DynamicSelectQueue(int, int, int, int, idxtype *, float *, int *, int *, int, float, float);
+int Moc_HashVwgts(int, float *);
+int Moc_HashVRank(int, int *);
+
+
+/* csrmatch.c */
+void CSR_Match_SHEM(MatrixType *, idxtype *, idxtype *, idxtype *, int);
+
+/* serial.c */
+void Moc_SerialKWayAdaptRefine(GraphType *, int, idxtype *, float *, int);
+void Moc_ComputeSerialPartitionParams(GraphType *, int, EdgeType *);
+int AreAllHVwgtsBelow(int, float, float *, float, float *, float *);
+void ComputeHKWayLoadImbalance(int, int, float *, float *);
+void SerialRemap(GraphType *, int, idxtype *, idxtype *, idxtype *, float *);
+int SSMIncKeyCmp(const void *, const void *);
+void Moc_Serial_FM_2WayRefine(GraphType *, float *, int);
+void Serial_SelectQueue(int, float *, float *, int *, int *, FPQueueType [MAXNCON][2]);
+int Serial_BetterBalance(int, float *, float *, float *);
+float Serial_Compute2WayHLoadImbalance(int, float *, float *);
+void Moc_Serial_Balance2Way(GraphType *, float *, float);
+void Moc_Serial_Init2WayBalance(GraphType *, float *);
+int Serial_SelectQueueOneWay(int, float *, float *, int, FPQueueType [MAXNCON][2]);
+void Moc_Serial_Compute2WayPartitionParams(GraphType *);
+int Serial_AreAnyVwgtsBelow(int, float, float *, float, float *, float *);
+
+/* weird.c */
+void PartitionSmallGraph(CtrlType *, GraphType *, WorkSpaceType *);
+void CheckInputs(int partType, int npes, int dbglvl, int *wgtflag, int *iwgtflag,
+ int *numflag, int *inumflag, int *ncon, int *incon, int *nparts,
+ int *inparts, float *tpwgts, float **itpwgts, float *ubvec,
+ float *iubvec, float *ipc2redist, float *iipc2redist, int *options,
+ int *ioptions, idxtype *part, MPI_Comm *comm);
+
+/* mesh.c */
+
+/* ometis.c */
+
+/* pspases.c */
+GraphType *AssembleEntireGraph(CtrlType *, idxtype *, idxtype *, idxtype *);
+
+/* node_refine.c */
+void ComputeNodePartitionParams0(CtrlType *, GraphType *, WorkSpaceType *);
+void ComputeNodePartitionParams(CtrlType *, GraphType *, WorkSpaceType *);
+void KWayNodeRefine0(CtrlType *, GraphType *, WorkSpaceType *, int, float);
+void KWayNodeRefine(CtrlType *, GraphType *, WorkSpaceType *, int, float);
+void KWayNodeRefine2(CtrlType *, GraphType *, WorkSpaceType *, int, float);
+void PrintNodeBalanceInfo(CtrlType *, int, idxtype *, idxtype *, idxtype *, int);
+
+/* initmsection.c */
+void InitMultisection(CtrlType *, GraphType *, WorkSpaceType *);
+GraphType *AssembleMultisectedGraph(CtrlType *, GraphType *, WorkSpaceType *);
+
+/* order.c */
+void MultilevelOrder(CtrlType *, GraphType *, idxtype *, idxtype *, WorkSpaceType *);
+void LabelSeparators(CtrlType *, GraphType *, idxtype *, idxtype *, idxtype *, idxtype *, WorkSpaceType *);
+void CompactGraph(CtrlType *, GraphType *, idxtype *, WorkSpaceType *);
+void LocalOrder(CtrlType *, GraphType *, idxtype *, int, WorkSpaceType *);
+void LocalNDOrder(CtrlType *, GraphType *, idxtype *, int, WorkSpaceType *);
+void Order_Partition(CtrlType *, GraphType *, WorkSpaceType *);
+
+/* xyzpart.c */
+void Coordinate_Partition(CtrlType *, GraphType *, int, float *, int, WorkSpaceType *);
+void PartSort(CtrlType *, GraphType *, KeyValueType *, WorkSpaceType *);
+
+
+/* fpqueue.c */
+void FPQueueInit(FPQueueType *, int);
+void FPQueueReset(FPQueueType *);
+void FPQueueFree(FPQueueType *);
+int FPQueueGetSize(FPQueueType *);
+int FPQueueInsert(FPQueueType *, int, float);
+int FPQueueDelete(FPQueueType *, int);
+int FPQueueUpdate(FPQueueType *, int, float, float);
+void FPQueueUpdateUp(FPQueueType *, int, float, float);
+int FPQueueGetMax(FPQueueType *);
+int FPQueueSeeMaxVtx(FPQueueType *);
+float FPQueueSeeMaxGain(FPQueueType *);
+float FPQueueGetKey(FPQueueType *);
+int FPQueueGetQSize(FPQueueType *);
+int CheckHeapFloat(FPQueueType *);
+
+/* stat.c */
+void Moc_ComputeSerialBalance(CtrlType *, GraphType *, idxtype *, float *);
+void Moc_ComputeParallelBalance(CtrlType *, GraphType *, idxtype *, float *);
+void Moc_PrintThrottleMatrix(CtrlType *, GraphType *, float *);
+void Moc_ComputeRefineStats(CtrlType *, GraphType *, float *);
+
+/* debug.c */
+void PrintVector(CtrlType *, int, int, idxtype *, char *);
+void PrintVector2(CtrlType *, int, int, idxtype *, char *);
+void PrintPairs(CtrlType *, int, KeyValueType *, char *);
+void PrintGraph(CtrlType *, GraphType *);
+void PrintGraph2(CtrlType *, GraphType *);
+void PrintSetUpInfo(CtrlType *ctrl, GraphType *graph);
+void PrintTransferedGraphs(CtrlType *, int, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *);
+void WriteMetisGraph(int, idxtype *, idxtype *, idxtype *, idxtype *);
+
+/* comm.c */
+void CommInterfaceData(CtrlType *, GraphType *, idxtype *, idxtype *, idxtype *);
+void CommChangedInterfaceData(CtrlType *, GraphType *, int, idxtype *, idxtype *, KeyValueType *, KeyValueType *, idxtype *);
+int GlobalSEMax(CtrlType *, int);
+double GlobalSEMaxDouble(CtrlType *, double);
+int GlobalSEMin(CtrlType *, int);
+int GlobalSESum(CtrlType *, int);
+float GlobalSEMaxFloat(CtrlType *, float);
+float GlobalSEMinFloat(CtrlType *, float);
+float GlobalSESumFloat(CtrlType *, float);
+
+/* util.c */
+void errexit(char *,...);
+void myprintf(CtrlType *, char *f_str,...);
+void rprintf(CtrlType *, char *f_str,...);
+#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);
+int idxamax(int n, idxtype *x);
+int idxamin(int n, idxtype *x);
+int idxasum(int n, idxtype *x);
+float snorm2(int, float *);
+float sdot(int n, float *, float *);
+void saxpy(int, float, float *, float *);
+void ikeyvalsort_org(int, KeyValueType *);
+int IncKeyValueCmp(const void *, const void *);
+void dkeyvalsort(int, KeyValueType *);
+int DecKeyValueCmp(const void *, const void *);
+int BSearch(int, idxtype *, int);
+void RandomPermute(int, idxtype *, int);
+void FastRandomPermute(int, idxtype *, int);
+int ispow2(int);
+int log2Int(int);
+void BucketSortKeysDec(int, int, idxtype *, idxtype *);
+float *sset(int n, float val, float *x);
+int iamax(int, int *);
+int idxamax_strd(int, idxtype *, int);
+int idxamin_strd(int, idxtype *, int);
+int samax_strd(int, float *, int);
+int sfamax(int, float *);
+int samin_strd(int, float *, int);
+float idxavg(int, idxtype *);
+float savg(int, float *);
+int samax(int, float *);
+int sfavg(int n, float *x);
+int samax2(int, float *);
+int samin(int, float *);
+int idxsum(int, idxtype *);
+int idxsum_strd(int, idxtype *, int);
+void idxadd(int, idxtype *, idxtype *);
+float ssum(int, float *);
+float ssum_strd(int, float *, int);
+void sscale(int, float, float *);
+void saneg(int, float *);
+float BetterVBalance(int, float *, float *, float *);
+int IsHBalanceBetterTT(int, float *, float *, float *, float *);
+int IsHBalanceBetterFT(int, float *, float *, float *, float *);
+int myvalkeycompare(const void *, const void *);
+int imyvalkeycompare(const void *, const void *);
+float *fsmalloc(int, float, char *);
+void saxpy2(int, float, float *, int, float *, int);
+void GetThreeMax(int, float *, int *, int *, int *);
+
+/* qsort_special.c */
+void iidxsort(int, idxtype *);
+void iintsort(int, int *);
+void ikeysort(int, KeyValueType *);
+void ikeyvalsort(int, KeyValueType *);
+
+/* grsetup.c */
+GraphType *Moc_SetUpGraph(CtrlType *, int, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int *);
+void SetUpCtrl(CtrlType *ctrl, int, int, MPI_Comm);
+void ChangeNumbering(idxtype *, idxtype *, idxtype *, idxtype *, int, int, int);
+void ChangeNumberingMesh(idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int, int, int, int);
+void ChangeNumberingMesh2(idxtype *elmdist, idxtype *eptr, idxtype *eind,
+ idxtype *xadj, idxtype *adjncy, idxtype *part,
+ int npes, int mype, int from);
+void GraphRandomPermute(GraphType *);
+void ComputeMoveStatistics(CtrlType *, GraphType *, int *, int *, int *);
+
+/* timer.c */
+void InitTimers(CtrlType *);
+void PrintTimingInfo(CtrlType *);
+void PrintTimer(CtrlType *, timer, char *);
+
+/* setup.c */
+void SetUp(CtrlType *, GraphType *, WorkSpaceType *);
+int Home_PE(int, int, idxtype *, int);
+
+
+/*********************/
+/* METIS subroutines */
+/*********************/
+void METIS_WPartGraphKway2(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
+void METIS_mCPartGraphRecursive2(int *, int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, float *, int *, int *, idxtype *);
+int MCMlevelRecursiveBisection2(CtrlType *, GraphType *, int, float *, idxtype *, float, int);
+void METIS_PartGraphKway(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_EdgeComputeSeparator(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *);
+void METIS_NodeComputeSeparator(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, idxtype *);
+void METIS_NodeND(int *, idxtype *, idxtype *, int *, int *, idxtype *, idxtype *);
+void METIS_NodeNDP(int, idxtype *, idxtype *, int, int *, idxtype *, idxtype *, idxtype *);
+
+
+
+/***********************/
+/* TESTing subroutines */
+/***********************/
+
+/* pio.c */
+void ParallelReadGraph(GraphType *, char *, MPI_Comm);
+void Moc_ParallelWriteGraph(CtrlType *, GraphType *, char *, int, int);
+void ReadTestGraph(GraphType *, char *, MPI_Comm);
+float *ReadTestCoordinates(GraphType *, char *, int, MPI_Comm);
+void ReadMetisGraph(char *, int *, idxtype **, idxtype **);
+void Moc_SerialReadGraph(GraphType *, char *, int *, MPI_Comm);
+void Moc_SerialReadMetisGraph(char *, int *, int *, int *, int *, idxtype **, idxtype **, idxtype **, idxtype **, int *);
+
+/* adaptgraph */
+void AdaptGraph(GraphType *, int, MPI_Comm);
+void AdaptGraph2(GraphType *, int, MPI_Comm);
+void Mc_AdaptGraph(GraphType *, idxtype *, int, int, MPI_Comm);
+
+/* ptest.c */
+void TestParMetis(char *, MPI_Comm);
+
+/* NEW_ptest.c */
+void TestParMetis_V3(char *, MPI_Comm);
+int ComputeRealCut(idxtype *, idxtype *, char *, MPI_Comm);
+int ComputeRealCut2(idxtype *, idxtype *, idxtype *, idxtype *, char *, MPI_Comm);
+void TestMoveGraph(GraphType *, GraphType *, idxtype *, MPI_Comm);
+GraphType *SetUpGraph(CtrlType *, idxtype *, idxtype *, idxtype *, idxtype *, idxtype *, int);
+
+/* mienio.c */
+void mienIO(MeshType *, char *, int, int, MPI_Comm);
+
+/* meshio.c */
+void ParallelReadMesh(MeshType *, char *, MPI_Comm);
+
+/* parmetis.c */
+void ChangeToFortranNumbering(idxtype *, idxtype *, idxtype *, int, int);
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/pspases.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/pspases.c
new file mode 100644
index 0000000..8b7a182
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/pspases.c
@@ -0,0 +1,167 @@
+/*
+ * pspases.c
+ *
+ * This file contains ordering routines that are to be used with the
+ * parallel Cholesky factorization code PSPASES
+ *
+ * Started 10/14/97
+ * George
+ *
+ * $Id: pspases.c,v 1.3 2003/07/21 17:18:53 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/***********************************************************************************
+* This function is the entry point of the serial ordering algorithm.
+************************************************************************************/
+void ParMETIS_SerialNodeND(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy, int *numflag,
+ int *options, idxtype *order, idxtype *sizes, MPI_Comm *comm)
+{
+ int i, npes, mype, seroptions[10];
+ CtrlType ctrl;
+ GraphType *agraph;
+ idxtype *perm=NULL, *iperm=NULL;
+ int *sendcount, *displs;
+
+ MPI_Comm_size(*comm, &npes);
+ MPI_Comm_rank(*comm, &mype);
+
+ if (!ispow2(npes)) {
+ if (mype == 0)
+ printf("Error: The number of processors must be a power of 2!\n");
+ return;
+ }
+
+ if (*numflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, order, npes, mype, 1);
+
+ SetUpCtrl(&ctrl, npes, options[OPTION_DBGLVL], *comm);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.MoveTmr));
+
+ agraph = AssembleEntireGraph(&ctrl, vtxdist, xadj, adjncy);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.MoveTmr));
+
+
+ if (mype == 0) {
+ perm = idxmalloc(agraph->nvtxs, "PAROMETISS: perm");
+ iperm = idxmalloc(agraph->nvtxs, "PAROMETISS: iperm");
+
+ seroptions[0] = 0;
+ /*
+ seroptions[1] = 3;
+ seroptions[2] = 1;
+ seroptions[3] = 2;
+ seroptions[4] = 128;
+ seroptions[5] = 1;
+ seroptions[6] = 0;
+ seroptions[7] = 1;
+ */
+
+ METIS_NodeNDP(agraph->nvtxs, agraph->xadj, agraph->adjncy, npes, seroptions, perm, iperm, sizes);
+ }
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.MoveTmr));
+
+ /* Broadcast the sizes array */
+ MPI_Bcast((void *)sizes, 2*npes, IDX_DATATYPE, 0, ctrl.gcomm);
+
+ /* Scatter the iperm */
+ sendcount = imalloc(npes, "PAROMETISS: sendcount");
+ displs = imalloc(npes, "PAROMETISS: displs");
+ for (i=0; i<npes; i++) {
+ sendcount[i] = vtxdist[i+1]-vtxdist[i];
+ displs[i] = vtxdist[i];
+ }
+
+ MPI_Scatterv((void *)iperm, sendcount, displs, IDX_DATATYPE, (void *)order, vtxdist[mype+1]-vtxdist[mype], IDX_DATATYPE, 0, ctrl.gcomm);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.MoveTmr));
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+
+ GKfree((void **)&agraph->xadj, (void **)&agraph->adjncy, (void **)&perm, (void **)&iperm, (void **)&sendcount, (void **)&displs, LTERM);
+ free(agraph);
+ FreeCtrl(&ctrl);
+
+ if (*numflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, order, npes, mype, 0);
+
+}
+
+
+
+/*************************************************************************
+* This function assembles the graph into a single processor
+**************************************************************************/
+GraphType *AssembleEntireGraph(CtrlType *ctrl, idxtype *vtxdist, idxtype *xadj, idxtype *adjncy)
+{
+ int i, gnvtxs, nvtxs, gnedges, nedges;
+ int npes = ctrl->npes, mype = ctrl->mype;
+ idxtype *axadj, *aadjncy;
+ int *recvcounts, *displs;
+ GraphType *agraph;
+
+ gnvtxs = vtxdist[npes];
+ nvtxs = vtxdist[mype+1]-vtxdist[mype];
+ nedges = xadj[nvtxs];
+
+ recvcounts = imalloc(npes, "AssembleGraph: recvcounts");
+ displs = imalloc(npes+1, "AssembleGraph: displs");
+
+ /* Gather all the xadj arrays first */
+ for (i=0; i<nvtxs; i++)
+ xadj[i] = xadj[i+1]-xadj[i];
+
+ axadj = idxmalloc(gnvtxs+1, "AssembleEntireGraph: axadj");
+
+ for (i=0; i<npes; i++) {
+ recvcounts[i] = vtxdist[i+1]-vtxdist[i];
+ displs[i] = vtxdist[i];
+ }
+
+ /* Assemble the xadj and then the adjncy */
+ MPI_Gatherv((void *)xadj, nvtxs, IDX_DATATYPE, axadj, recvcounts, displs, IDX_DATATYPE, 0, ctrl->comm);
+
+ MAKECSR(i, nvtxs, xadj);
+ MAKECSR(i, gnvtxs, axadj);
+
+ /* Gather all the adjncy arrays next */
+ /* Determine the # of edges stored at each processor */
+ MPI_Allgather((void *)(&nedges), 1, MPI_INT, (void *)recvcounts, 1, MPI_INT, ctrl->comm);
+
+ displs[0] = 0;
+ for (i=1; i<npes+1; i++)
+ displs[i] = displs[i-1] + recvcounts[i-1];
+ gnedges = displs[npes];
+
+ aadjncy = idxmalloc(gnedges, "AssembleEntireGraph: aadjncy");
+
+ /* Assemble the xadj and then the adjncy */
+ MPI_Gatherv((void *)adjncy, nedges, IDX_DATATYPE, aadjncy, recvcounts, displs, IDX_DATATYPE, 0, ctrl->comm);
+
+ /* myprintf(ctrl, "Gnvtxs: %d, Gnedges: %d\n", gnvtxs, gnedges); */
+
+ agraph = CreateGraph();
+ agraph->nvtxs = gnvtxs;
+ agraph->nedges = gnedges;
+ agraph->xadj = axadj;
+ agraph->adjncy = aadjncy;
+
+ return agraph;
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/redomylink.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/redomylink.c
new file mode 100644
index 0000000..98b6810
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/redomylink.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * redomylink.c
+ *
+ * This file contains code that implements the edge-based FM refinement
+ *
+ * Started 7/23/97
+ * George
+ *
+ * $Id: redomylink.c,v 1.2 2003/07/21 17:18:53 karypis Exp $
+ */
+
+#include <parmetislib.h>
+#define PE 0
+
+/*************************************************************************
+* This function performs an edge-based FM refinement
+**************************************************************************/
+void RedoMyLink(CtrlType *ctrl, GraphType *graph, idxtype *home, int me,
+ int you, float *flows, float *sr_cost, float *sr_lbavg)
+{
+ int h, i, r;
+ int nvtxs, nedges, ncon;
+ int pass, lastseed, totalv;
+ idxtype *xadj, *adjncy, *adjwgt, *where, *vsize;
+ idxtype *costwhere, *lbwhere, *selectwhere;
+ idxtype *rdata, *ed, *id, *bndptr, *bndind, *perm;
+ float *nvwgt, mycost;
+ float lbavg, lbvec[MAXNCON];
+ float best_lbavg, other_lbavg = -1.0, bestcost, othercost = -1.0;
+ float npwgts[2*MAXNCON], pwgts[MAXNCON*2], tpwgts[MAXNCON*2];
+ float ipc_factor, redist_factor, ftmp;
+int mype;
+MPI_Comm_rank(MPI_COMM_WORLD, &mype);
+
+ nvtxs = graph->nvtxs;
+ nedges = graph->nedges;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ nvwgt = graph->nvwgt;
+ vsize = graph->vsize;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ ipc_factor = ctrl->ipc_factor;
+ redist_factor = ctrl->redist_factor;
+
+ /**************************/
+ /* set up data structures */
+ /**************************/
+ rdata = idxmalloc(7*nvtxs, "rdata");
+ id = graph->sendind = rdata;
+ ed = graph->recvind = rdata + nvtxs;
+ bndptr = graph->sendptr = rdata + 2*nvtxs;
+ bndind = graph->recvptr = rdata + 3*nvtxs;
+ costwhere = rdata + 4*nvtxs;
+ lbwhere = rdata + 5*nvtxs;
+ perm = rdata + 6*nvtxs;
+ graph->gnpwgts = npwgts;
+
+ RandomPermute(nvtxs, perm, 1);
+ idxcopy(nvtxs, where, costwhere);
+ idxcopy(nvtxs, where, lbwhere);
+
+ /*****************************/
+ /* compute target pwgts */
+ /*****************************/
+ sset(ncon*2, 0.0, pwgts);
+ for (h=0; h<ncon; h++) {
+ tpwgts[h] = -1.0 * flows[h];
+ tpwgts[ncon+h] = flows[h];
+ }
+
+ for (i=0; i<nvtxs; i++) {
+ if (where[i] == me) {
+ for (h=0; h<ncon; h++) {
+ tpwgts[h] += nvwgt[i*ncon+h];
+ pwgts[h] += nvwgt[i*ncon+h];
+ }
+ }
+ else {
+ ASSERTS(where[i] == you);
+ for (h=0; h<ncon; h++) {
+ tpwgts[ncon+h] += nvwgt[i*ncon+h];
+ pwgts[ncon+h] += nvwgt[i*ncon+h];
+ }
+ }
+ }
+
+ /* we don't want any weights to be less than zero */
+ for (h=0; h<ncon; h++) {
+ if (tpwgts[h] < 0.0) {
+ tpwgts[ncon+h] += tpwgts[h];
+ tpwgts[h] = 0.0;
+ }
+
+ if (tpwgts[ncon+h] < 0.0) {
+ tpwgts[h] += tpwgts[ncon+h];
+ tpwgts[ncon+h] = 0.0;
+ }
+ }
+
+ /*****************************/
+ /* now compute new bisection */
+ /*****************************/
+ bestcost = (float)idxsum(nedges, adjwgt)*ipc_factor + (float)idxsum(nvtxs, vsize)*redist_factor;
+ best_lbavg = 10.0;
+
+ lastseed = 0;
+ for (pass = N_MOC_REDO_PASSES; pass>0; pass--) {
+ idxset(nvtxs, 1, where);
+
+ /***************************/
+ /* find seed vertices */
+ /***************************/
+ r = perm[lastseed] % nvtxs;
+ lastseed = (lastseed+1) % nvtxs;
+ where[r] = 0;
+
+ Moc_Serial_Compute2WayPartitionParams(graph);
+ Moc_Serial_Init2WayBalance(graph, tpwgts);
+ Moc_Serial_FM_2WayRefine(graph, tpwgts, 4);
+ Moc_Serial_Balance2Way(graph, tpwgts, 1.02);
+ Moc_Serial_FM_2WayRefine(graph, tpwgts, 4);
+
+ for (i=0; i<nvtxs; i++)
+ where[i] = (where[i] == 0) ? me : you;
+
+ for (i=0; i<ncon; i++) {
+ ftmp = (pwgts[i]+pwgts[ncon+i])/2.0;
+ if (ftmp != 0.0)
+ lbvec[i] = fabs(npwgts[i]-tpwgts[i])/ftmp;
+ else
+ lbvec[i] = 0.0;
+ }
+ lbavg = savg(ncon, lbvec);
+
+ totalv = 0;
+ for (i=0; i<nvtxs; i++)
+ if (where[i] != home[i])
+ totalv += vsize[i];
+
+ mycost = (float)(graph->mincut)*ipc_factor + (float)totalv*redist_factor;
+
+ if (bestcost >= mycost) {
+ bestcost = mycost;
+ other_lbavg = lbavg;
+ idxcopy(nvtxs, where, costwhere);
+ }
+
+ if (best_lbavg >= lbavg) {
+ best_lbavg = lbavg;
+ othercost = mycost;
+ idxcopy(nvtxs, where, lbwhere);
+ }
+ }
+
+ if (other_lbavg <= .05) {
+ selectwhere = costwhere;
+ *sr_cost = bestcost;
+ *sr_lbavg = other_lbavg;
+ }
+ else {
+ selectwhere = lbwhere;
+ *sr_cost = othercost;
+ *sr_lbavg = best_lbavg;
+ }
+
+ idxcopy(nvtxs, selectwhere, where);
+
+ GKfree((void **)&rdata, LTERM);
+ return;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/remap.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/remap.c
new file mode 100644
index 0000000..31f186b
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/remap.c
@@ -0,0 +1,181 @@
+/*
+ * premap.c
+ *
+ * This file contains code that computes the assignment of processors to
+ * partition numbers so that it will minimize the redistribution cost
+ *
+ * Started 4/16/98
+ * George
+ *
+ * $Id: remap.c,v 1.2 2003/07/21 17:18:53 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+/*************************************************************************
+* This function remaps that graph so that it will minimize the
+* redistribution cost
+**************************************************************************/
+void ParallelReMapGraph(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, nvtxs, nparts;
+ idxtype *where, *vsize, *map, *lpwgts;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RemapTmr));
+
+ if (ctrl->npes != ctrl->nparts) {
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RemapTmr));
+ return;
+ }
+
+ nvtxs = graph->nvtxs;
+ where = graph->where;
+ vsize = graph->vsize;
+ nparts = ctrl->nparts;
+
+ map = wspace->pv1;
+ lpwgts = idxset(nparts, 0, wspace->pv2);
+
+ for (i=0; i<nvtxs; i++)
+ lpwgts[where[i]] += (vsize == NULL) ? 1 : vsize[i];
+
+ ParallelTotalVReMap(ctrl, lpwgts, map, wspace, NREMAP_PASSES, graph->ncon);
+
+ for (i=0; i<nvtxs; i++)
+ where[i] = map[where[i]];
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RemapTmr));
+}
+
+
+/*************************************************************************
+* This function computes the assignment using the the objective the
+* minimization of the total volume of data that needs to move
+**************************************************************************/
+void ParallelTotalVReMap(CtrlType *ctrl, idxtype *lpwgts, idxtype *map,
+ WorkSpaceType *wspace, int npasses, int ncon)
+{
+ int i, ii, j, k, nparts, mype;
+ int pass, maxipwgt, nmapped, oldwgt, newwgt, done;
+ idxtype *rowmap, *mylpwgts;
+ KeyValueType *recv, send;
+ int nsaved, gnsaved;
+
+ mype = ctrl->mype;
+ nparts = ctrl->nparts;
+ recv = (KeyValueType *)GKmalloc(sizeof(KeyValueType)*nparts, "remap: recv");
+ mylpwgts = idxmalloc(nparts, "mylpwgts");
+
+ done = nmapped = 0;
+ idxset(nparts, -1, map);
+ rowmap = idxset(nparts, -1, wspace->pv3);
+ idxcopy(nparts, lpwgts, mylpwgts);
+ for (pass=0; pass<npasses; pass++) {
+ maxipwgt = idxamax(nparts, mylpwgts);
+
+ if (mylpwgts[maxipwgt] > 0 && !done) {
+ send.key = -mylpwgts[maxipwgt];
+ send.val = mype*nparts+maxipwgt;
+ }
+ else {
+ send.key = 0;
+ send.val = -1;
+ }
+
+ /* each processor sends its selection */
+ MPI_Allgather((void *)&send, 2, IDX_DATATYPE, (void *)recv, 2, IDX_DATATYPE, ctrl->comm);
+
+ ikeysort(nparts, recv);
+ if (recv[0].key == 0)
+ break;
+
+ /* now make as many assignments as possible */
+ for (ii=0; ii<nparts; ii++) {
+ i = recv[ii].val;
+
+ if (i == -1)
+ continue;
+
+ j = i % nparts;
+ k = i / nparts;
+ if (map[j] == -1 && rowmap[k] == -1 && SimilarTpwgts(ctrl->tpwgts, ncon, j, k)) {
+ map[j] = k;
+ rowmap[k] = j;
+ nmapped++;
+ mylpwgts[j] = 0;
+ if (mype == k)
+ done = 1;
+ }
+
+ if (nmapped == nparts)
+ break;
+ }
+
+ if (nmapped == nparts)
+ break;
+ }
+
+ /* Map unmapped partitions */
+ if (nmapped < nparts) {
+ for (i=j=0; j<nparts && nmapped<nparts; j++) {
+ if (map[j] == -1) {
+ for (; i<nparts; i++) {
+ if (rowmap[i] == -1 && SimilarTpwgts(ctrl->tpwgts, ncon, i, j)) {
+ map[j] = i;
+ rowmap[i] = j;
+ nmapped++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* check to see if remapping fails (due to dis-similar tpwgts) */
+ /* if remapping fails, revert to original mapping */
+ if (nmapped < nparts) {
+ for (i=0; i<nparts; i++)
+ map[i] = i;
+ IFSET(ctrl->dbglvl, DBG_REMAP, rprintf(ctrl, "Savings from parallel remapping: %0\n"));
+ }
+ else {
+ /* check for a savings */
+ oldwgt = lpwgts[mype];
+ newwgt = lpwgts[rowmap[mype]];
+ nsaved = newwgt - oldwgt;
+ gnsaved = GlobalSESum(ctrl, nsaved);
+
+ /* undo everything if we don't see a savings */
+ if (gnsaved <= 0) {
+ for (i=0; i<nparts; i++)
+ map[i] = i;
+ }
+ IFSET(ctrl->dbglvl, DBG_REMAP, rprintf(ctrl, "Savings from parallel remapping: %d\n", amax(0,gnsaved)));
+ }
+
+ GKfree((void **)&recv, (void **)&mylpwgts, LTERM);
+
+}
+
+
+/*************************************************************************
+* This function computes the assignment using the the objective the
+* minimization of the total volume of data that needs to move
+**************************************************************************/
+int SimilarTpwgts(float *tpwgts, int ncon, int s1, int s2)
+{
+ int i;
+
+ for (i=0; i<ncon; i++)
+ if (fabs(tpwgts[s1*ncon+i]-tpwgts[s2*ncon+i]) > SMALLFLOAT)
+ break;
+
+ if (i == ncon)
+ return 1;
+
+ return 0;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/rename.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/rename.h
new file mode 100644
index 0000000..d993257
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/rename.h
@@ -0,0 +1,290 @@
+/* kmetis.c */
+#define Moc_Global_Partition Moc_Global_Partition__
+
+/* mmetis.c */
+
+/* gkmetis.c */
+
+/* match.c */
+#define Moc_GlobalMatch_Balance Moc_GlobalMatch_Balance__
+
+/* coarsen.c */
+#define Moc_Global_CreateCoarseGraph Moc_Global_CreateCoarseGraph__
+
+/* initpart.c */
+#define Moc_InitPartition_RB Moc_InitPartition_RB__
+#define Moc_KeepPart Moc_KeepPart__
+
+/* kwayrefine.c */
+#define Moc_ProjectPartition Moc_ProjectPartition__
+#define Moc_ComputePartitionParams Moc_ComputePartitionParams__
+
+/* kwayfm.c */
+#define Moc_KWayFM Moc_KWayFM__
+
+/* kwaybalance.c */
+#define Moc_KWayBalance Moc_KWayBalance__
+
+/* remap.c */
+#define ParallelReMapGraph ParallelReMapGraph__
+#define ParallelTotalVReMap ParallelTotalVReMap__
+#define SimilarTpwgts SimilarTpwgts__
+
+/* move.c */
+#define Moc_MoveGraph Moc_MoveGraph__
+#define CheckMGraph CheckMGraph__
+#define ProjectInfoBack ProjectInfoBack__
+#define FindVtxPerm FindVtxPerm__
+
+/* memory.c */
+#define PreAllocateMemory PreAllocateMemory__
+#define FreeWSpace FreeWSpace__
+#define FreeCtrl FreeCtrl__
+#define CreateGraph CreateGraph__
+#define InitGraph InitGraph__
+#define FreeGraph FreeGraph__
+#define FreeInitialGraphAndRemap FreeInitialGraphAndRemap__
+
+
+/************************/
+/* Adaptive subroutines */
+/************************/
+/* ametis.c */
+#define Adaptive_Partition Adaptive_Partition__
+
+/* rmetis.c */
+
+/* lmatch.c */
+#define Mc_LocalMatch_HEM Mc_LocalMatch_HEM__
+#define Mc_Local_CreateCoarseGraph Mc_Local_CreateCoarseGraph__
+
+/* wave.c */
+#define WavefrontDiffusion WavefrontDiffusion__
+
+/* balancemylink.c */
+#define BalanceMyLink BalanceMyLink__
+
+/* redomylink.c */
+#define RedoMyLink RedoMyLink__
+
+/* initbalance.c */
+#define Balance_Partition Balance_Partition__
+#define Moc_AssembleAdaptiveGraph Moc_AssembleAdaptiveGraph__
+
+/* mdiffusion.c */
+#define Moc_Diffusion Moc_Diffusion__
+#define ExtractGraph ExtractGraph__
+
+/* diffutil.c */
+#define SetUpConnectGraph SetUpConnectGraph__
+#define Mc_ComputeMoveStatistics Mc_ComputeMoveStatistics__
+#define Mc_ComputeSerialTotalV Mc_ComputeSerialTotalV__
+#define ComputeLoad ComputeLoad__
+#define ConjGrad2 ConjGrad2__
+#define mvMult2 mvMult2__
+#define ComputeTransferVector ComputeTransferVector__
+#define ComputeSerialEdgeCut ComputeSerialEdgeCut__
+#define ComputeSerialTotalV ComputeSerialTotalV__
+
+/* akwayfm.c */
+#define Moc_KWayAdaptiveRefine Moc_KWayAdaptiveRefine__
+
+/* selectq.c */
+#define Moc_DynamicSelectQueue Moc_DynamicSelectQueue__
+#define Moc_HashVwgts Moc_HashVwgts__
+#define Moc_HashVRank Moc_HashVRank__
+
+/* csrmatch.c */
+#define CSR_Match_SHEM CSR_Match_SHEM__
+
+/* serial.c */
+#define Moc_SerialKWayAdaptRefine Moc_SerialKWayAdaptRefine__
+#define Moc_ComputeSerialPartitionParams Moc_ComputeSerialPartitionParams__
+#define AreAllHVwgtsBelow AreAllHVwgtsBelow__
+#define ComputeHKWayLoadImbalance ComputeHKWayLoadImbalance__
+#define SerialRemap SerialRemap__
+#define SSMIncKeyCmp SSMIncKeyCmp__
+#define Moc_Serial_FM_2WayRefine Moc_Serial_FM_2WayRefine__
+#define Serial_SelectQueue Serial_SelectQueue__
+#define Serial_BetterBalance Serial_BetterBalance__
+#define Serial_Compute2WayHLoadImbalance Serial_Compute2WayHLoadImbalance__
+#define Moc_Serial_Balance2Way Moc_Serial_Balance2Way__
+#define Moc_Serial_Init2WayBalance Moc_Serial_Init2WayBalance__
+#define Serial_SelectQueueOneWay Serial_SelectQueueOneWay__
+#define Moc_Serial_Compute2WayPartitionParams Moc_Serial_Compute2WayPartitionParams__
+#define Serial_AreAnyVwgtsBelow Serial_AreAnyVwgtsBelow__
+
+/* weird.c */
+#define PartitionSmallGraph PartitionSmallGraph__
+#define CheckInputs CheckInputs__
+
+
+/****************************/
+/* Mesh to Dual subroutines */
+/****************************/
+/* mesh.c */
+/* msetup.c */
+#define SetUpMesh SetUpMesh__
+#define CreateMesh CreateMesh__
+#define InitMesh InitMesh__
+
+
+/************************/
+/* Ordering subroutines */
+/************************/
+/* ometis.c */
+/* pspases.c */
+#define AssembleEntireGraph AssembleEntireGraph__
+
+/* node_refine.c */
+#define ComputeNodePartitionParams0 ComputeNodePartitionParams0__
+#define ComputeNodePartitionParams ComputeNodePartitionParams__
+#define KWayNodeRefine0 KWayNodeRefine0__
+#define KWayNodeRefine KWayNodeRefine__
+#define KWayNodeRefine2 KWayNodeRefine2__
+#define PrintNodeBalanceInfo PrintNodeBalanceInfo__
+
+/* initmsection.c */
+#define InitMultisection InitMultisection__
+#define AssembleMultisectedGraph AssembleMultisectedGraph__
+
+/* order.c */
+#define MultilevelOrder MultilevelOrder__
+#define LabelSeparators LabelSeparators__
+#define CompactGraph CompactGraph__
+#define LocalOrder LocalOrder__
+#define LocalNDOrder LocalNDOrder__
+#define Order_Partition Order_Partition__
+
+/* xyzpart.c */
+#define Coordinate_Partition Coordinate_Partition__
+#define PartSort PartSort__
+
+/***********************/
+/* Utility subroutines */
+/***********************/
+/* fpqueue.c */
+#define FPQueueInit FPQueueInit__
+#define FPQueueReset FPQueueReset__
+#define FPQueueFree FPQueueFree__
+#define FPQueueGetSize FPQueueGetSize__
+#define FPQueueInsert FPQueueInsert__
+#define FPQueueDelete FPQueueDelete__
+#define FPQueueUpdate FPQueueUpdate__
+#define FPQueueUpdateUp FPQueueUpdateUp__
+#define FPQueueGetMax FPQueueGetMax__
+#define FPQueueSeeMaxVtx FPQueueSeeMaxVtx__
+#define FPQueueSeeMaxGain FPQueueSeeMaxGain__
+#define FPQueueGetKey FPQueueGetKey__
+#define FPQueueGetQSize FPQueueGetQSize__
+#define CheckHeapFloat CheckHeapFloat__
+
+/* stat.c */
+#define Moc_ComputeSerialBalance Moc_ComputeSerialBalance__
+#define Moc_ComputeParallelBalance Moc_ComputeParallelBalance__
+#define Moc_PrintThrottleMatrix Moc_PrintThrottleMatrix__
+#define Moc_ComputeRefineStats Moc_ComputeRefineStats__
+
+/* debug.c */
+#define PrintVector PrintVector__
+#define PrintVector2 PrintVector2__
+#define PrintPairs PrintPairs__
+#define PrintGraph PrintGraph__
+#define PrintGraph2 PrintGraph2__
+#define PrintSetUpInfo PrintSetUpInfo__
+#define PrintTransferedGraphs PrintTransferedGraphs__
+#define WriteMetisGraph WriteMetisGraph__
+
+/* comm.c */
+#define CommInterfaceData CommInterfaceData__
+#define CommChangedInterfaceData CommChangedInterfaceData__
+#define GlobalSEMax GlobalSEMax__
+#define GlobalSEMaxDouble GlobalSEMaxDouble__
+#define GlobalSEMin GlobalSEMin__
+#define GlobalSESum GlobalSESum__
+#define GlobalSEMaxFloat GlobalSEMaxFloat__
+#define GlobalSEMinFloat GlobalSEMinFloat__
+#define GlobalSESumFloat GlobalSESumFloat__
+
+/* util.c */
+#define errexit errexit__
+#define myprintf myprintf__
+#define rprintf rprintf__
+#define imalloc imalloc__
+#define idxmalloc idxmalloc__
+#define fmalloc fmalloc__
+#define ismalloc ismalloc__
+#define idxsmalloc idxsmalloc__
+#define GKmalloc GKmalloc__
+#define GKfree GKfree__
+#define iset iset__
+#define idxset idxset__
+#define idxamax idxamax__
+#define idxamin idxamin__
+#define idxasum idxasum__
+#define snorm2 snorm2__
+#define sdot sdot__
+#define saxpy saxpy__
+#define ikeyvalsort_org ikeyvalsort_org__
+#define IncKeyValueCmp IncKeyValueCmp__
+#define dkeyvalsort dkeyvalsort__
+#define DecKeyValueCmp DecKeyValueCmp__
+#define BSearch BSearch__
+#define RandomPermute RandomPermute__
+#define FastRandomPermute FastRandomPermute__
+#define ispow2 ispow2__
+#define log2Int log2Int__
+#define BucketSortKeysDec BucketSortKeysDec__
+#define sset sset__
+#define iamax iamax__
+#define idxamax_strd idxamax_strd__
+#define idxamin_strd idxamin_strd__
+#define samax_strd samax_strd__
+#define sfamax sfamax__
+#define samin_strd samin_strd__
+#define idxavg idxavg__
+#define savg savg__
+#define samax samax__
+#define sfavg sfavg__
+#define samax2 samax2__
+#define samin samin__
+#define idxsum idxsum__
+#define idxsum_strd idxsum_strd__
+#define idxadd idxadd__
+#define ssum ssum__
+#define ssum_strd ssum_strd__
+#define sscale sscale__
+#define saneg saneg__
+#define BetterVBalance BetterVBalance__
+#define IsHBalanceBetterTT IsHBalanceBetterTT__
+#define IsHBalanceBetterFT IsHBalanceBetterFT__
+#define myvalkeycompare myvalkeycompare__
+#define imyvalkeycompare imyvalkeycompare__
+#define fsmalloc fsmalloc__
+#define saxpy2 saxpy2__
+#define GetThreeMax GetThreeMax__
+
+/* qsort_special.c */
+#define iidxsort iidxsort__
+#define iintsort iintsort__
+#define ikeysort ikeysort__
+#define ikeyvalsort ikeyvalsort__
+
+/* grsetup.c */
+#define Moc_SetUpGraph Moc_SetUpGraph__
+#define SetUpCtrl SetUpCtrl__
+#define ChangeNumbering ChangeNumbering__
+#define ChangeNumberingMesh ChangeNumberingMesh__
+#define GraphRandomPermute GraphRandomPermute__
+#define ComputeMoveStatistics ComputeMoveStatistics__
+
+/* timer.c */
+#define InitTimers InitTimers__
+#define PrintTimingInfo PrintTimingInfo__
+#define PrintTimer PrintTimer__
+
+/* setup.c */
+#define SetUp SetUp__
+#define Home_PE Home_PE__
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/rmetis.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/rmetis.c
new file mode 100644
index 0000000..3755209
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/rmetis.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * rmetis.c
+ *
+ * This is the entry point of the partitioning refinement routine
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: rmetis.c,v 1.5 2003/07/25 04:01:05 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+/***********************************************************************************
+* This function is the entry point of the parallel multilevel local diffusion
+* algorithm. It uses parallel undirected diffusion followed by adaptive k-way
+* refinement. This function utilizes local coarsening.
+************************************************************************************/
+void ParMETIS_V3_RefineKway(idxtype *vtxdist, idxtype *xadj, idxtype *adjncy,
+ idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *ncon,
+ int *nparts, float *tpwgts, float *ubvec, int *options, int *edgecut,
+ idxtype *part, MPI_Comm *comm)
+{
+ int h, i;
+ int npes, mype;
+ CtrlType ctrl;
+ WorkSpaceType wspace;
+ GraphType *graph;
+ int tewgt, tvsize, nmoved, maxin, maxout;
+ float gtewgt, gtvsize, avg, maximb;
+ int ps_relation, seed, dbglvl = 0;
+ int iwgtflag, inumflag, incon, inparts, ioptions[10];
+ float *itpwgts, iubvec[MAXNCON];
+
+ MPI_Comm_size(*comm, &npes);
+ MPI_Comm_rank(*comm, &mype);
+
+ /********************************/
+ /* Try and take care bad inputs */
+ /********************************/
+ if (options != NULL && options[0] == 1)
+ dbglvl = options[PMV3_OPTION_DBGLVL];
+ CheckInputs(REFINE_PARTITION, npes, dbglvl, wgtflag, &iwgtflag, numflag, &inumflag,
+ ncon, &incon, nparts, &inparts, tpwgts, &itpwgts, ubvec, iubvec,
+ NULL, NULL, options, ioptions, part, comm);
+
+ /* ADD: take care of disconnected graph */
+ /* ADD: take care of highly unbalanced vtxdist */
+ /*********************************/
+ /* Take care the nparts = 1 case */
+ /*********************************/
+ if (inparts <= 1) {
+ idxset(vtxdist[mype+1]-vtxdist[mype], 0, part);
+ *edgecut = 0;
+ return;
+ }
+
+ /**************************/
+ /* Set up data structures */
+ /**************************/
+ if (inumflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 1);
+
+ /*****************************/
+ /* Set up control structures */
+ /*****************************/
+ if (ioptions[0] == 1) {
+ dbglvl = ioptions[PMV3_OPTION_DBGLVL];
+ seed = ioptions[PMV3_OPTION_SEED];
+ ps_relation = (npes == inparts) ? ioptions[PMV3_OPTION_PSR] : DISCOUPLED;
+ }
+ else {
+ dbglvl = GLOBAL_DBGLVL;
+ seed = GLOBAL_SEED;
+ ps_relation = (npes == inparts) ? COUPLED : DISCOUPLED;
+ }
+
+ SetUpCtrl(&ctrl, inparts, dbglvl, *comm);
+ ctrl.CoarsenTo = amin(vtxdist[npes]+1, 50*incon*amax(npes, inparts));
+ ctrl.ipc_factor = 1000.0;
+ ctrl.redist_factor = 1.0;
+ ctrl.redist_base = 1.0;
+ ctrl.seed = (seed == 0) ? mype : seed*mype;
+ ctrl.sync = GlobalSEMax(&ctrl, seed);
+ ctrl.partType = REFINE_PARTITION;
+ ctrl.ps_relation = ps_relation;
+ ctrl.tpwgts = itpwgts;
+
+ graph = Moc_SetUpGraph(&ctrl, incon, vtxdist, xadj, vwgt, adjncy, adjwgt, &iwgtflag);
+ graph->vsize = idxsmalloc(graph->nvtxs, 1, "vsize");
+
+ graph->home = idxmalloc(graph->nvtxs, "home");
+ if (ctrl.ps_relation == COUPLED)
+ idxset(graph->nvtxs, mype, graph->home);
+ else
+ idxcopy(graph->nvtxs, part, graph->home);
+
+ tewgt = idxsum(graph->nedges, graph->adjwgt);
+ tvsize = idxsum(graph->nvtxs, graph->vsize);
+ gtewgt = (float) GlobalSESum(&ctrl, tewgt) + 1.0/graph->gnvtxs;
+ gtvsize = (float) GlobalSESum(&ctrl, tvsize) + 1.0/graph->gnvtxs;
+ ctrl.edge_size_ratio = gtewgt/gtvsize;
+ scopy(incon, iubvec, ctrl.ubvec);
+
+ PreAllocateMemory(&ctrl, graph, &wspace);
+
+ /***********************/
+ /* Partition and Remap */
+ /***********************/
+ IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
+
+ Adaptive_Partition(&ctrl, graph, &wspace);
+ ParallelReMapGraph(&ctrl, graph, &wspace);
+
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+ IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
+
+ idxcopy(graph->nvtxs, graph->where, part);
+ if (edgecut != NULL)
+ *edgecut = graph->mincut;
+
+ /***********************/
+ /* Take care of output */
+ /***********************/
+ IFSET(ctrl.dbglvl, DBG_TIME, PrintTimingInfo(&ctrl));
+ IFSET(ctrl.dbglvl, DBG_TIME, MPI_Barrier(ctrl.gcomm));
+
+ if (ctrl.dbglvl&DBG_INFO) {
+ Mc_ComputeMoveStatistics(&ctrl, graph, &nmoved, &maxin, &maxout);
+ rprintf(&ctrl, "Final %3d-way Cut: %6d \tBalance: ", inparts, graph->mincut);
+ avg = 0.0;
+ for (h=0; h<incon; h++) {
+ maximb = 0.0;
+ for (i=0; i<inparts; i++)
+ maximb = amax(maximb, graph->gnpwgts[i*incon+h]/itpwgts[i*incon+h]);
+ avg += maximb;
+ rprintf(&ctrl, "%.3f ", maximb);
+ }
+ rprintf(&ctrl, "\nNMoved: %d %d %d %d\n", nmoved, maxin, maxout, maxin+maxout);
+ }
+
+ /*************************************/
+ /* Free memory, renumber, and return */
+ /*************************************/
+ GKfree((void **)&graph->lnpwgts, (void **)&graph->gnpwgts, (void **)&graph->nvwgt, (void **)(&graph->home), (void **)(&graph->vsize), LTERM);
+
+ GKfree((void **)&itpwgts, LTERM);
+ FreeInitialGraphAndRemap(graph, iwgtflag);
+ FreeWSpace(&wspace);
+ FreeCtrl(&ctrl);
+
+ if (inumflag == 1)
+ ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 0);
+
+ return;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/selectq.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/selectq.c
new file mode 100644
index 0000000..5ec9109
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/selectq.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * selectq.c
+ *
+ * This file contains the driving routines for multilevel k-way refinement
+ *
+ * Started 7/28/97
+ * George
+ *
+ * $Id: selectq.c,v 1.2 2003/07/21 17:18:53 karypis Exp $
+ */
+
+#include <parmetislib.h>
+
+/*************************************************************************
+* This stuff is hardcoded for up to four constraints
+**************************************************************************/
+void Moc_DynamicSelectQueue(int nqueues, int ncon, int subdomain1, int subdomain2,
+ idxtype *currentq, float *flows, int *from, int *qnum, int minval, float avgvwgt,
+ float maxdiff)
+{
+ int i, j;
+ int hash, index = -1, current;
+ int cand[MAXNCON], rank[MAXNCON], dont_cares[MAXNCON];
+ int nperms, perm[24][5];
+ float sign = 0.0;
+ KVType array[MAXNCON];
+int mype;
+MPI_Comm_rank(MPI_COMM_WORLD, &mype);
+
+ *qnum = -1;
+
+ if (*from == -1) {
+ for (i=0; i<ncon; i++) {
+ array[i].key = i;
+ array[i].val = (fabs)(flows[i]);
+ }
+
+ qsort(array, ncon, sizeof(KVType), myvalkeycompare);
+ ASSERTS(array[ncon-1].val - array[0].val <= maxdiff)
+
+ if (flows[array[ncon-1].key]>avgvwgt*MOC_GD_GRANULARITY_FACTOR) {
+ *from = subdomain1;
+ sign = 1.0;
+ index = 0;
+ }
+
+ if (flows[array[ncon-1].key]<-1.0*avgvwgt*MOC_GD_GRANULARITY_FACTOR) {
+ *from = subdomain2;
+ sign = -1.0;
+ index = nqueues;
+ }
+
+ if (*from == -1) {
+ return;
+ }
+ }
+ else {
+ ASSERTS(*from == subdomain1 || *from == subdomain2);
+
+ if (*from == subdomain1) {
+ sign = 1.0;
+ index = 0;
+ }
+ else {
+ sign = -1.0;
+ index = nqueues;
+ }
+ }
+
+ for (i=0; i<ncon; i++) {
+ array[i].key = i;
+ array[i].val = flows[i] * sign;
+ }
+
+ qsort(array, ncon, sizeof(KVType), myvalkeycompare);
+
+ iset(ncon, 1, dont_cares);
+
+ current = 0;
+ for (i=0; i<ncon-1; i++)
+ if (array[i+1].val - array[i].val < maxdiff * MC_FLOW_BALANCE_THRESHOLD && dont_cares[current] < ncon-1) {
+ dont_cares[current]++;
+ dont_cares[i+1] = 0;
+ }
+ else
+ current = i+1;
+
+
+ switch (ncon) {
+ /***********************/
+ case 2:
+ nperms = 1;
+ perm[0][0] = 0; perm[0][1] = 1;
+
+ break;
+ /***********************/
+ case 3:
+
+ /* if the first and second flows are close */
+ if (dont_cares[0] == 2 && dont_cares[1] == 0 && dont_cares[2] == 1) {
+ nperms = 4;
+ perm[0][0] = 0; perm[0][1] = 1; perm[0][2] = 2;
+ perm[1][0] = 1; perm[1][1] = 0; perm[1][2] = 2;
+ perm[2][0] = 0; perm[2][1] = 2; perm[2][2] = 1;
+ perm[3][0] = 1; perm[3][1] = 2; perm[3][2] = 0;
+ break;
+ }
+
+ /* if the second and third flows are close */
+ if (dont_cares[0] == 1 && dont_cares[1] == 2 && dont_cares[2] == 0) {
+ nperms = 4;
+ perm[0][0] = 0; perm[0][1] = 1; perm[0][2] = 2;
+ perm[1][0] = 0; perm[1][1] = 2; perm[1][2] = 1;
+ perm[2][0] = 1; perm[2][1] = 0; perm[2][2] = 2;
+ perm[3][0] = 2; perm[3][1] = 0; perm[3][2] = 1;
+ break;
+ }
+
+ /* all or none of the flows are close */
+ nperms = 3;
+ perm[0][0] = 0; perm[0][1] = 1; perm[0][2] = 2;
+ perm[1][0] = 1; perm[1][1] = 0; perm[1][2] = 2;
+ perm[2][0] = 0; perm[2][1] = 2; perm[2][2] = 1;
+
+ break;
+ /***********************/
+ case 4:
+
+ if (dont_cares[0] == 2 && dont_cares[1] == 0 &&
+ dont_cares[2] == 1 && dont_cares[3] == 1) {
+ nperms = 14;
+ perm[0][0] = 0; perm[0][1] = 1; perm[0][2] = 2; perm[0][3] = 3;
+ perm[1][0] = 1; perm[1][1] = 0; perm[1][2] = 2; perm[1][3] = 3;
+ perm[2][0] = 0; perm[2][1] = 2; perm[2][2] = 1; perm[2][3] = 3;
+ perm[3][0] = 1; perm[3][1] = 2; perm[3][2] = 0; perm[3][3] = 3;
+ perm[4][0] = 0; perm[4][1] = 1; perm[4][2] = 3; perm[4][3] = 2;
+ perm[5][0] = 1; perm[5][1] = 0; perm[5][2] = 3; perm[5][3] = 2;
+
+ perm[6][0] = 0; perm[6][1] = 3; perm[6][2] = 1; perm[6][3] = 2;
+ perm[7][0] = 1; perm[7][1] = 3; perm[7][2] = 0; perm[7][3] = 2;
+
+ perm[8][0] = 0; perm[8][1] = 2; perm[8][2] = 3; perm[8][3] = 1;
+ perm[9][0] = 1; perm[9][1] = 2; perm[9][2] = 3; perm[9][3] = 0;
+
+ perm[10][0] = 2; perm[10][1] = 0; perm[10][2] = 1; perm[10][3] = 3;
+ perm[11][0] = 2; perm[11][1] = 1; perm[11][2] = 0; perm[11][3] = 3;
+
+ perm[12][0] = 0; perm[12][1] = 3; perm[12][2] = 2; perm[12][3] = 1;
+ perm[13][0] = 1; perm[13][1] = 3; perm[13][2] = 2; perm[13][3] = 0;
+ break;
+ }
+
+ if (dont_cares[0] == 1 && dont_cares[1] == 1 &&
+ dont_cares[2] == 2 && dont_cares[3] == 0) {
+ nperms = 14;
+ perm[0][0] = 0; perm[0][1] = 1; perm[0][2] = 2; perm[0][3] = 3;
+ perm[1][0] = 0; perm[1][1] = 1; perm[1][2] = 3; perm[1][3] = 2;
+ perm[2][0] = 0; perm[2][1] = 2; perm[2][2] = 1; perm[2][3] = 3;
+ perm[3][0] = 0; perm[3][1] = 3; perm[3][2] = 1; perm[3][3] = 2;
+ perm[4][0] = 1; perm[4][1] = 0; perm[4][2] = 2; perm[4][3] = 3;
+ perm[5][0] = 1; perm[5][1] = 0; perm[5][2] = 3; perm[5][3] = 2;
+
+ perm[6][0] = 1; perm[6][1] = 2; perm[6][2] = 0; perm[6][3] = 3;
+ perm[7][0] = 1; perm[7][1] = 3; perm[7][2] = 0; perm[7][3] = 2;
+
+ perm[8][0] = 2; perm[8][1] = 0; perm[8][2] = 1; perm[8][3] = 3;
+ perm[9][0] = 3; perm[9][1] = 0; perm[9][2] = 1; perm[9][3] = 2;
+
+ perm[10][0] = 0; perm[10][1] = 2; perm[10][2] = 3; perm[10][3] = 1;
+ perm[11][0] = 0; perm[11][1] = 3; perm[11][2] = 2; perm[11][3] = 1;
+
+ perm[12][0] = 2; perm[12][1] = 1; perm[12][2] = 0; perm[12][3] = 3;
+ perm[13][0] = 3; perm[13][1] = 1; perm[13][2] = 0; perm[13][3] = 2;
+ break;
+ }
+
+ if (dont_cares[0] == 2 && dont_cares[1] == 0 &&
+ dont_cares[2] == 2 && dont_cares[3] == 0) {
+ nperms = 14;
+ perm[0][0] = 0; perm[0][1] = 1; perm[0][2] = 2; perm[0][3] = 3;
+ perm[1][0] = 1; perm[1][1] = 0; perm[1][2] = 2; perm[1][3] = 3;
+ perm[2][0] = 0; perm[2][1] = 1; perm[2][2] = 3; perm[2][3] = 2;
+ perm[3][0] = 1; perm[3][1] = 0; perm[3][2] = 3; perm[3][3] = 2;
+
+ perm[4][0] = 0; perm[4][1] = 2; perm[4][2] = 1; perm[4][3] = 3;
+ perm[5][0] = 1; perm[5][1] = 2; perm[5][2] = 0; perm[5][3] = 3;
+ perm[6][0] = 0; perm[6][1] = 3; perm[6][2] = 1; perm[6][3] = 2;
+ perm[7][0] = 1; perm[7][1] = 3; perm[7][2] = 0; perm[7][3] = 2;
+
+ perm[8][0] = 2; perm[8][1] = 0; perm[8][2] = 1; perm[8][3] = 3;
+ perm[9][0] = 0; perm[9][1] = 2; perm[9][2] = 3; perm[9][3] = 1;
+ perm[10][0] = 2; perm[10][1] = 1; perm[10][2] = 0; perm[10][3] = 3;
+ perm[11][0] = 0; perm[11][1] = 3; perm[11][2] = 2; perm[11][3] = 1;
+ perm[12][0] = 3; perm[12][1] = 0; perm[12][2] = 1; perm[12][3] = 2;
+ perm[13][0] = 1; perm[13][1] = 2; perm[13][2] = 3; perm[13][3] = 0;
+ break;
+ }
+
+ if (dont_cares[0] == 3 && dont_cares[1] == 0 &&
+ dont_cares[2] == 0 && dont_cares[3] == 1) {
+ nperms = 14;
+ perm[0][0] = 0; perm[0][1] = 1; perm[0][2] = 2; perm[0][3] = 3;
+ perm[1][0] = 0; perm[1][1] = 2; perm[1][2] = 1; perm[1][3] = 3;
+ perm[2][0] = 1; perm[2][1] = 0; perm[2][2] = 2; perm[2][3] = 3;
+ perm[3][0] = 2; perm[3][1] = 0; perm[3][2] = 1; perm[3][3] = 3;
+ perm[4][0] = 1; perm[4][1] = 2; perm[4][2] = 0; perm[4][3] = 3;
+ perm[5][0] = 2; perm[5][1] = 1; perm[5][2] = 0; perm[5][3] = 3;
+
+ perm[6][0] = 0; perm[6][1] = 1; perm[6][2] = 3; perm[6][3] = 2;
+ perm[7][0] = 1; perm[7][1] = 0; perm[7][2] = 3; perm[7][3] = 2;
+ perm[8][0] = 0; perm[8][1] = 2; perm[8][2] = 3; perm[8][3] = 1;
+ perm[9][0] = 2; perm[9][1] = 0; perm[9][2] = 3; perm[9][3] = 1;
+ perm[10][0] = 1; perm[10][1] = 2; perm[10][2] = 3; perm[10][3] = 0;
+ perm[11][0] = 2; perm[11][1] = 1; perm[11][2] = 3; perm[11][3] = 0;
+
+ perm[12][0] = 0; perm[12][1] = 3; perm[12][2] = 1; perm[12][3] = 2;
+ perm[13][0] = 0; perm[13][1] = 3; perm[13][2] = 2; perm[13][3] = 1;
+ break;
+ }
+
+ if (dont_cares[0] == 1 && dont_cares[1] == 3 &&
+ dont_cares[2] == 0 && dont_cares[3] == 0) {
+ nperms = 14;
+ perm[0][0] = 0; perm[0][1] = 1; perm[0][2] = 2; perm[0][3] = 3;
+ perm[1][0] = 0; perm[1][1] = 2; perm[1][2] = 1; perm[1][3] = 3;
+ perm[2][0] = 0; perm[2][1] = 1; perm[2][2] = 3; perm[2][3] = 2;
+ perm[3][0] = 0; perm[3][1] = 2; perm[3][2] = 3; perm[3][3] = 1;
+ perm[4][0] = 0; perm[4][1] = 3; perm[4][2] = 1; perm[4][3] = 2;
+ perm[5][0] = 0; perm[5][1] = 3; perm[5][2] = 2; perm[5][3] = 1;
+
+ perm[6][0] = 1; perm[6][1] = 0; perm[6][2] = 2; perm[6][3] = 3;
+ perm[7][0] = 1; perm[7][1] = 0; perm[7][2] = 3; perm[7][3] = 2;
+ perm[8][0] = 2; perm[8][1] = 0; perm[8][2] = 1; perm[8][3] = 3;
+ perm[9][0] = 2; perm[9][1] = 0; perm[9][2] = 3; perm[9][3] = 1;
+ perm[10][0] = 3; perm[10][1] = 0; perm[10][2] = 1; perm[10][3] = 2;
+ perm[11][0] = 3; perm[11][1] = 0; perm[11][2] = 2; perm[11][3] = 1;
+
+ perm[12][0] = 1; perm[12][1] = 2; perm[12][2] = 0; perm[12][3] = 3;
+ perm[13][0] = 2; perm[13][1] = 1; perm[13][2] = 0; perm[13][3] = 3;
+
+ break;
+ }
+
+ nperms = 14;
+ perm[0][0] = 0; perm[0][1] = 1; perm[0][2] = 2; perm[0][3] = 3;
+ perm[1][0] = 1; perm[1][1] = 0; perm[1][2] = 2; perm[1][3] = 3;
+ perm[2][0] = 0; perm[2][1] = 2; perm[2][2] = 1; perm[2][3] = 3;
+ perm[3][0] = 0; perm[3][1] = 1; perm[3][2] = 3; perm[3][3] = 2;
+ perm[4][0] = 1; perm[4][1] = 0; perm[4][2] = 3; perm[4][3] = 2;
+
+ perm[5][0] = 2; perm[5][1] = 0; perm[5][2] = 1; perm[5][3] = 3;
+ perm[6][0] = 0; perm[6][1] = 2; perm[6][2] = 3; perm[6][3] = 1;
+
+ perm[7][0] = 1; perm[7][1] = 2; perm[7][2] = 0; perm[7][3] = 3;
+ perm[8][0] = 0; perm[8][1] = 3; perm[8][2] = 1; perm[8][3] = 2;
+
+ perm[9][0] = 2; perm[9][1] = 1; perm[9][2] = 0; perm[9][3] = 3;
+ perm[10][0] = 0; perm[10][1] = 3; perm[10][2] = 2; perm[10][3] = 1;
+ perm[11][0] = 2; perm[11][1] = 0; perm[11][2] = 3; perm[11][3] = 1;
+
+ perm[12][0] = 3; perm[12][1] = 0; perm[12][2] = 1; perm[12][3] = 2;
+ perm[13][0] = 1; perm[13][1] = 2; perm[13][2] = 3; perm[13][3] = 0;
+ break;
+ /***********************/
+ default:
+ return;
+ }
+
+ for (i=0; i<nperms; i++) {
+ for (j=0; j<ncon; j++)
+ cand[j] = array[perm[i][j]].key;
+
+ for (j=0; j<ncon; j++)
+ rank[cand[j]] = j;
+
+
+ hash = Moc_HashVRank(ncon, rank) - minval;
+ if (currentq[hash+index] > 0) {
+ *qnum = hash;
+ return;
+ }
+ }
+
+ return;
+}
+
+
+/*************************************************************************
+* This function sorts the nvwgts of a vertex and returns a hashed value
+**************************************************************************/
+int Moc_HashVwgts(int ncon, float *nvwgt)
+{
+ int i;
+ int multiplier, retval;
+ int rank[MAXNCON];
+ KVType array[MAXNCON];
+
+
+ for (i=0; i<ncon; i++) {
+ array[i].key = i;
+ array[i].val = nvwgt[i];
+ }
+
+ qsort(array, ncon, sizeof(KVType), myvalkeycompare);
+ for (i=0; i<ncon; i++)
+ rank[array[i].key] = i;
+
+ multiplier = 1;
+
+ retval = 0;
+ for (i=0; i<ncon; i++) {
+ multiplier *= (i+1);
+ retval += rank[ncon-i-1] * multiplier;
+ }
+
+ return retval;
+}
+
+
+/*************************************************************************
+* This function sorts the vwgts of a vertex and returns a hashed value
+**************************************************************************/
+int Moc_HashVRank(int ncon, int *vwgt)
+{
+ int i, multiplier, retval;
+
+ multiplier = 1;
+
+ retval = 0;
+ for (i=0; i<ncon; i++) {
+ multiplier *= (i+1);
+ retval += vwgt[ncon-1-i] * multiplier;
+ }
+
+ return retval;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/serial.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/serial.c
new file mode 100644
index 0000000..630d4e5
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/serial.c
@@ -0,0 +1,1251 @@
+/*
+ * serial.c
+ *
+ * This file contains code that implements k-way refinement
+ *
+ * Started 7/28/97
+ * George
+ *
+ * $Id: serial.c,v 1.2 2003/07/21 17:18:53 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function performs k-way refinement
+**************************************************************************/
+void Moc_SerialKWayAdaptRefine(GraphType *graph, int nparts, idxtype *home,
+ float *orgubvec, int npasses)
+{
+ int i, ii, iii, j, k;
+ int nvtxs, ncon, pass, nmoves, myndegrees;
+ int from, me, myhome, to, oldcut, gain, tmp;
+ idxtype *xadj, *adjncy, *adjwgt;
+ idxtype *where;
+ EdgeType *mydegrees;
+ RInfoType *rinfo, *myrinfo;
+ float *npwgts, *nvwgt, *minwgt, *maxwgt, ubvec[MAXNCON];
+ int gain_is_greater, gain_is_same, fit_in_to, fit_in_from, going_home;
+ int zero_gain, better_balance_ft, better_balance_tt;
+ KeyValueType *cand;
+int mype;
+MPI_Comm_rank(MPI_COMM_WORLD, &mype);
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ rinfo = graph->rinfo;
+ npwgts = graph->gnpwgts;
+
+ /* Setup the weight intervals of the various subdomains */
+ cand = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "cand");
+ minwgt = fmalloc(nparts*ncon, "minwgt");
+ maxwgt = fmalloc(nparts*ncon, "maxwgt");
+
+ ComputeHKWayLoadImbalance(ncon, nparts, npwgts, ubvec);
+ for (i=0; i<ncon; i++)
+ ubvec[i] = amax(ubvec[i], orgubvec[i]);
+
+ for (i=0; i<nparts; i++) {
+ for (j=0; j<ncon; j++) {
+ maxwgt[i*ncon+j] = ubvec[j]/(float)nparts;
+ minwgt[i*ncon+j] = ubvec[j]*(float)nparts;
+ }
+ }
+
+ for (pass=0; pass<npasses; pass++) {
+ oldcut = graph->mincut;
+
+ for (i=0; i<nvtxs; i++) {
+ cand[i].key = rinfo[i].id-rinfo[i].ed;
+ cand[i].val = i;
+ }
+ ikeysort(nvtxs, cand);
+
+ nmoves = 0;
+ for (iii=0; iii<nvtxs; iii++) {
+ i = cand[iii].val;
+
+ myrinfo = rinfo+i;
+
+ if (myrinfo->ed >= myrinfo->id) {
+ from = where[i];
+ myhome = home[i];
+ nvwgt = graph->nvwgt+i*ncon;
+
+ if (myrinfo->id > 0 &&
+ AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, -1.0, nvwgt, minwgt+from*ncon))
+ continue;
+
+ mydegrees = myrinfo->degrees;
+ myndegrees = myrinfo->ndegrees;
+
+ for (k=0; k<myndegrees; k++) {
+ to = mydegrees[k].edge;
+ gain = mydegrees[k].ewgt - myrinfo->id;
+ if (gain >= 0 &&
+ (AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon) ||
+ IsHBalanceBetterFT(ncon,npwgts+from*ncon,npwgts+to*ncon,nvwgt,ubvec))) {
+ break;
+ }
+ }
+
+ /* break out if you did not find a candidate */
+ if (k == myndegrees)
+ continue;
+
+ for (j=k+1; j<myndegrees; j++) {
+ to = mydegrees[j].edge;
+ going_home = (myhome == to);
+ gain_is_same = (mydegrees[j].ewgt == mydegrees[k].ewgt);
+ gain_is_greater = (mydegrees[j].ewgt > mydegrees[k].ewgt);
+ fit_in_to = AreAllHVwgtsBelow(ncon,1.0,npwgts+to*ncon,1.0,nvwgt,maxwgt+to*ncon);
+ better_balance_ft = IsHBalanceBetterFT(ncon,npwgts+from*ncon,
+ npwgts+to*ncon,nvwgt,ubvec);
+ better_balance_tt = IsHBalanceBetterTT(ncon,npwgts+mydegrees[k].edge*ncon,
+ npwgts+to*ncon,nvwgt,ubvec);
+
+ if (
+ (gain_is_greater &&
+ (fit_in_to ||
+ better_balance_ft)
+ )
+ ||
+ (gain_is_same &&
+ (
+ (fit_in_to &&
+ going_home)
+ ||
+ better_balance_tt
+ )
+ )
+ ) {
+ k = j;
+ }
+ }
+
+ to = mydegrees[k].edge;
+ going_home = (myhome == to);
+ zero_gain = (mydegrees[k].ewgt == myrinfo->id);
+
+ fit_in_from = AreAllHVwgtsBelow(ncon,1.0,npwgts+from*ncon,0.0,npwgts+from*ncon,
+ maxwgt+from*ncon);
+ better_balance_ft = IsHBalanceBetterFT(ncon,npwgts+from*ncon,
+ npwgts+to*ncon,nvwgt,ubvec);
+
+ if (zero_gain &&
+ !going_home &&
+ !better_balance_ft &&
+ fit_in_from)
+ continue;
+
+ /*=====================================================================
+ * If we got here, we can now move the vertex from 'from' to 'to'
+ *======================================================================*/
+ graph->mincut -= mydegrees[k].ewgt-myrinfo->id;
+
+ /* Update where, weight, and ID/ED information of the vertex you moved */
+ saxpy2(ncon, 1.0, nvwgt, 1, npwgts+to*ncon, 1);
+ saxpy2(ncon, -1.0, nvwgt, 1, npwgts+from*ncon, 1);
+ where[i] = to;
+ myrinfo->ed += myrinfo->id-mydegrees[k].ewgt;
+ SWAP(myrinfo->id, mydegrees[k].ewgt, tmp);
+
+ if (mydegrees[k].ewgt == 0) {
+ myrinfo->ndegrees--;
+ mydegrees[k].edge = mydegrees[myrinfo->ndegrees].edge;
+ mydegrees[k].ewgt = mydegrees[myrinfo->ndegrees].ewgt;
+ }
+ else
+ mydegrees[k].edge = from;
+
+ /* Update the degrees of adjacent vertices */
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ ii = adjncy[j];
+ me = where[ii];
+
+ myrinfo = rinfo+ii;
+ mydegrees = myrinfo->degrees;
+
+ if (me == from) {
+ INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
+ }
+ else {
+ if (me == to) {
+ INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
+ }
+ }
+
+ /* Remove contribution of the ed from 'from' */
+ if (me != from) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (mydegrees[k].edge == from) {
+ if (mydegrees[k].ewgt == adjwgt[j]) {
+ myrinfo->ndegrees--;
+ mydegrees[k].edge = mydegrees[myrinfo->ndegrees].edge;
+ mydegrees[k].ewgt = mydegrees[myrinfo->ndegrees].ewgt;
+ }
+ else
+ mydegrees[k].ewgt -= adjwgt[j];
+ break;
+ }
+ }
+ }
+
+ /* Add contribution of the ed to 'to' */
+ if (me != to) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (mydegrees[k].edge == to) {
+ mydegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ mydegrees[myrinfo->ndegrees].edge = to;
+ mydegrees[myrinfo->ndegrees++].ewgt = adjwgt[j];
+ }
+ }
+
+ }
+ nmoves++;
+ }
+ }
+
+ if (graph->mincut == oldcut)
+ break;
+ }
+
+ GKfree((void **)&minwgt, (void **)&maxwgt, (void **)&cand, LTERM);
+
+ return;
+}
+
+
+/*************************************************************************
+* This function computes the initial id/ed
+**************************************************************************/
+void Moc_ComputeSerialPartitionParams(GraphType *graph, int nparts,
+ EdgeType *degrees)
+{
+ int i, j, k;
+ int nvtxs, nedges, ncon, mincut, me, other;
+ idxtype *xadj, *adjncy, *adjwgt, *where;
+ RInfoType *rinfo, *myrinfo;
+ EdgeType *mydegrees;
+ float *nvwgt, *npwgts;
+int mype;
+MPI_Comm_rank(MPI_COMM_WORLD, &mype);
+
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ nvwgt = graph->nvwgt;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ rinfo = graph->rinfo;
+
+ npwgts = sset(ncon*nparts, 0.0, graph->gnpwgts);
+
+ /*------------------------------------------------------------
+ / Compute now the id/ed degrees
+ /------------------------------------------------------------*/
+ nedges = mincut = 0;
+ for (i=0; i<nvtxs; i++) {
+ me = where[i];
+ saxpy2(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1);
+
+ myrinfo = rinfo+i;
+ myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0;
+ myrinfo->degrees = degrees + nedges;
+ nedges += xadj[i+1]-xadj[i];
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ if (me == where[adjncy[j]]) {
+ myrinfo->id += adjwgt[j];
+ }
+ else {
+ myrinfo->ed += adjwgt[j];
+ }
+ }
+
+ mincut += myrinfo->ed;
+
+ /* Time to compute the particular external degrees */
+ if (myrinfo->ed > 0) {
+ mydegrees = myrinfo->degrees;
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ other = where[adjncy[j]];
+ if (me != other) {
+ for (k=0; k<myrinfo->ndegrees; k++) {
+ if (mydegrees[k].edge == other) {
+ mydegrees[k].ewgt += adjwgt[j];
+ break;
+ }
+ }
+ if (k == myrinfo->ndegrees) {
+ mydegrees[myrinfo->ndegrees].edge = other;
+ mydegrees[myrinfo->ndegrees++].ewgt = adjwgt[j];
+ }
+ }
+ }
+ }
+ }
+
+ graph->mincut = mincut/2;
+
+ return;
+}
+
+
+/*************************************************************************
+* 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 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 subroutine remaps a partitioning on a single processor
+**************************************************************/
+void SerialRemap(GraphType *graph, int nparts, idxtype *base, idxtype *scratch,
+ idxtype *remap, float *tpwgts)
+{
+ int i, ii, j, k;
+ int nvtxs, nmapped, max_mult;
+ int from, to, current_from, smallcount, bigcount;
+ KeyValueType *flowto, *bestflow;
+ KeyKeyValueType *sortvtx;
+ idxtype *vsize, *htable, *map, *rowmap;
+
+ nvtxs = graph->nvtxs;
+ vsize = graph->vsize;
+ max_mult = amin(MAX_NPARTS_MULTIPLIER, nparts);
+
+ sortvtx = (KeyKeyValueType *)GKmalloc(nvtxs*sizeof(KeyKeyValueType), "sortvtx");
+ flowto = (KeyValueType *)GKmalloc((nparts*max_mult+nparts)*sizeof(KeyValueType), "flowto");
+ bestflow = flowto+nparts;
+ map = htable = idxsmalloc(nparts*2, -1, "htable");
+ rowmap = map+nparts;
+
+ for (i=0; i<nvtxs; i++) {
+ sortvtx[i].key1 = base[i];
+ sortvtx[i].key2 = vsize[i];
+ sortvtx[i].val = i;
+ }
+
+ qsort((void *)sortvtx, (size_t)nvtxs, (size_t)sizeof(KeyKeyValueType), SSMIncKeyCmp);
+
+ for (j=0; j<nparts; j++) {
+ flowto[j].key = 0;
+ flowto[j].val = j;
+ }
+
+ /* this step has nparts*nparts*log(nparts) computational complexity */
+ bigcount = smallcount = current_from = 0;
+ for (ii=0; ii<nvtxs; ii++) {
+ i = sortvtx[ii].val;
+ from = base[i];
+ to = scratch[i];
+
+ if (from > current_from) {
+ /* reset the hash table */
+ for (j=0; j<smallcount; j++)
+ htable[flowto[j].val] = -1;
+ ASSERTS(idxsum(nparts, htable) == -nparts);
+
+ ikeysort(smallcount, flowto);
+
+ for (j=0; j<amin(smallcount, max_mult); j++, bigcount++) {
+ bestflow[bigcount].key = flowto[j].key;
+ bestflow[bigcount].val = current_from*nparts+flowto[j].val;
+ }
+
+ smallcount = 0;
+ current_from = from;
+ }
+
+ if (htable[to] == -1) {
+ htable[to] = smallcount;
+ flowto[smallcount].key = -vsize[i];
+ flowto[smallcount].val = to;
+ smallcount++;
+ }
+ else {
+ flowto[htable[to]].key += -vsize[i];
+ }
+ }
+
+ /* reset the hash table */
+ for (j=0; j<smallcount; j++)
+ htable[flowto[j].val] = -1;
+ ASSERTS(idxsum(nparts, htable) == -nparts);
+
+ ikeysort(smallcount, flowto);
+
+ for (j=0; j<amin(smallcount, max_mult); j++, bigcount++) {
+ bestflow[bigcount].key = flowto[j].key;
+ bestflow[bigcount].val = current_from*nparts+flowto[j].val;
+ }
+ ikeysort(bigcount, bestflow);
+
+ ASSERTS(idxsum(nparts, map) == -nparts);
+ ASSERTS(idxsum(nparts, rowmap) == -nparts);
+ nmapped = 0;
+
+ /* now make as many assignments as possible */
+ for (ii=0; ii<bigcount; ii++) {
+ i = bestflow[ii].val;
+ j = i % nparts; /* to */
+ k = i / nparts; /* from */
+
+ if (map[j] == -1 && rowmap[k] == -1 && SimilarTpwgts(tpwgts, graph->ncon, j, k)) {
+ map[j] = k;
+ rowmap[k] = j;
+ nmapped++;
+ }
+
+ if (nmapped == nparts)
+ break;
+ }
+
+
+ /* remap the rest */
+ /* it may help try remapping to the same label first */
+ if (nmapped < nparts) {
+ for (j=0; j<nparts && nmapped<nparts; j++) {
+ if (map[j] == -1) {
+ for (ii=0; ii<nparts; ii++) {
+ i = (j+ii) % nparts;
+ if (rowmap[i] == -1 && SimilarTpwgts(tpwgts, graph->ncon, i, j)) {
+ map[j] = i;
+ rowmap[i] = j;
+ nmapped++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* check to see if remapping fails (due to dis-similar tpwgts) */
+ /* if remapping fails, revert to original mapping */
+ if (nmapped < nparts)
+ for (i=0; i<nparts; i++)
+ map[i] = i;
+
+ for (i=0; i<nvtxs; i++)
+ remap[i] = map[remap[i]];
+
+ GKfree((void **)&sortvtx, (void **)&flowto, (void **)&htable, LTERM);
+}
+
+
+/*************************************************************************
+* This is a comparison function for Serial Remap
+**************************************************************************/
+int SSMIncKeyCmp(const void *fptr, const void *sptr)
+{
+ KeyKeyValueType *first, *second;
+
+ first = (KeyKeyValueType *)(fptr);
+ second = (KeyKeyValueType *)(sptr);
+
+ if (first->key1 > second->key1)
+ return 1;
+
+ if (first->key1 < second->key1)
+ return -1;
+
+ if (first->key2 < second->key2)
+ return 1;
+
+ if (first->key2 > second->key2)
+ return -1;
+
+ return 0;
+}
+
+
+/*************************************************************************
+* This function performs an edge-based FM refinement
+**************************************************************************/
+void Moc_Serial_FM_2WayRefine(GraphType *graph, float *tpwgts, int npasses)
+{
+ int i, ii, j, k;
+ int kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, limit, tmp, cnum;
+ idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
+ idxtype *moved, *swaps, *qnum;
+ float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal;
+ FPQueueType parts[MAXNCON][2];
+ int higain, oldgain, mincut, initcut, newcut, mincutorder;
+ float rtpwgts[MAXNCON*2];
+ KeyValueType *cand;
+int mype;
+MPI_Comm_rank(MPI_COMM_WORLD, &mype);
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ nvwgt = graph->nvwgt;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ id = graph->sendind;
+ ed = graph->recvind;
+ npwgts = graph->gnpwgts;
+ bndptr = graph->sendptr;
+ bndind = graph->recvptr;
+
+ moved = idxmalloc(nvtxs, "moved");
+ swaps = idxmalloc(nvtxs, "swaps");
+ qnum = idxmalloc(nvtxs, "qnum");
+ cand = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "cand");
+
+ limit = amin(amax(0.01*nvtxs, 25), 150);
+
+ /* Initialize the queues */
+ for (i=0; i<ncon; i++) {
+ FPQueueInit(&parts[i][0], nvtxs);
+ FPQueueInit(&parts[i][1], nvtxs);
+ }
+ for (i=0; i<nvtxs; i++)
+ qnum[i] = samax(ncon, nvwgt+i*ncon);
+
+ origbal = Serial_Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
+
+ for (i=0; i<ncon; i++) {
+ rtpwgts[i] = origbal*tpwgts[i];
+ rtpwgts[ncon+i] = origbal*tpwgts[ncon+i];
+ }
+
+ idxset(nvtxs, -1, moved);
+ for (pass=0; pass<npasses; pass++) { /* Do a number of passes */
+ for (i=0; i<ncon; i++) {
+ FPQueueReset(&parts[i][0]);
+ FPQueueReset(&parts[i][1]);
+ }
+
+ mincutorder = -1;
+ newcut = mincut = initcut = graph->mincut;
+ for (i=0; i<ncon; i++)
+ mindiff[i] = fabs(tpwgts[i]-npwgts[i]);
+ minbal = Serial_Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
+
+ /* Insert boundary nodes in the priority queues */
+ nbnd = graph->gnvtxs;
+
+ for (i=0; i<nbnd; i++) {
+ cand[i].key = id[i]-ed[i];
+ cand[i].val = i;
+ }
+ ikeysort(nbnd, cand);
+
+ for (ii=0; ii<nbnd; ii++) {
+ i = bndind[cand[ii].val];
+ FPQueueInsert(&parts[qnum[i]][where[i]], i, (float)(ed[i]-id[i]));
+ }
+
+ for (nswaps=0; nswaps<nvtxs; nswaps++) {
+ Serial_SelectQueue(ncon, npwgts, rtpwgts, &from, &cnum, parts);
+ to = (from+1)%2;
+
+ if (from == -1 || (higain = FPQueueGetMax(&parts[cnum][from])) == -1)
+ break;
+
+ saxpy2(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
+ saxpy2(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
+
+ newcut -= (ed[higain]-id[higain]);
+ newbal = Serial_Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
+
+ if ((newcut < mincut && newbal-origbal <= .00001) ||
+ (newcut == mincut && (newbal < minbal ||
+ (newbal == minbal && Serial_BetterBalance(ncon, npwgts, tpwgts, mindiff))))) {
+ mincut = newcut;
+ minbal = newbal;
+ mincutorder = nswaps;
+ for (i=0; i<ncon; i++)
+ mindiff[i] = fabs(tpwgts[i]-npwgts[i]);
+ }
+ else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
+ newcut += (ed[higain]-id[higain]);
+ saxpy2(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
+ saxpy2(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
+ break;
+ }
+
+ where[higain] = to;
+ moved[higain] = nswaps;
+ swaps[nswaps] = higain;
+
+ /**************************************************************
+ * 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 */
+ FPQueueDelete(&parts[qnum[k]][where[k]], k);
+ }
+ else { /* If it has not been moved, update its position in the queue */
+ if (moved[k] == -1)
+ FPQueueUpdate(&parts[qnum[k]][where[k]], k, (float)oldgain, (float)(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)
+ FPQueueInsert(&parts[qnum[k]][where[k]], k, (float)(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);
+
+ saxpy2(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
+ saxpy2(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);
+ }
+ }
+
+ graph->mincut = mincut;
+ graph->gnvtxs = nbnd;
+
+ if (mincutorder == -1 || mincut == initcut)
+ break;
+ }
+
+ for (i=0; i<ncon; i++) {
+ FPQueueFree(&parts[i][0]);
+ FPQueueFree(&parts[i][1]);
+ }
+
+ GKfree((void **)&cand, (void **)&qnum, (void **)&moved, (void **)&swaps, LTERM);
+ return;
+}
+
+/*************************************************************************
+* This function selects the partition number and the queue from which
+* we will move vertices out
+**************************************************************************/
+void Serial_SelectQueue(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum,
+ FPQueueType queues[MAXNCON][2])
+{
+ int i, part;
+ float maxgain=0.0;
+ float max = -1.0, maxdiff=0.0;
+int mype;
+MPI_Comm_rank(MPI_COMM_WORLD, &mype);
+
+ *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*ncon+i] >= maxdiff) {
+ maxdiff = npwgts[part*ncon+i]-tpwgts[part*ncon+i];
+ *from = part;
+ *cnum = i;
+ }
+ }
+ }
+
+ if (*from != -1 && FPQueueGetQSize(&queues[*cnum][*from]) == 0) {
+ /* The desired queue is empty, select a node from that side anyway */
+ for (i=0; i<ncon; i++) {
+ if (FPQueueGetQSize(&queues[i][*from]) > 0) {
+ max = npwgts[(*from)*ncon + i];
+ *cnum = i;
+ break;
+ }
+ }
+
+ for (i++; i<ncon; i++) {
+ if (npwgts[(*from)*ncon + i] > max && FPQueueGetQSize(&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.0;
+
+ for (part=0; part<2; part++) {
+ for (i=0; i<ncon; i++) {
+ if (FPQueueGetQSize(&queues[i][part]) > 0 &&
+ FPQueueSeeMaxGain(&queues[i][part]) > maxgain) {
+ maxgain = FPQueueSeeMaxGain(&queues[i][part]);
+ *from = part;
+ *cnum = i;
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+/*************************************************************************
+* This function checks if the balance achieved is better than the diff
+* For now, it uses a 2-norm measure
+**************************************************************************/
+int Serial_BetterBalance(int ncon, float *npwgts, float *tpwgts, float *diff)
+{
+ int i;
+ float ndiff[MAXNCON];
+
+ for (i=0; i<ncon; i++)
+ ndiff[i] = fabs(tpwgts[i]-npwgts[i]);
+
+ return snorm2(ncon, ndiff) < snorm2(ncon, diff);
+}
+
+
+
+/*************************************************************************
+* This function computes the load imbalance over all the constrains
+**************************************************************************/
+float Serial_Compute2WayHLoadImbalance(int ncon, float *npwgts, float *tpwgts)
+{
+ int i;
+ float max=0.0, temp;
+
+ for (i=0; i<ncon; i++) {
+ if (tpwgts[i] == 0.0)
+ temp = 0.0;
+ else
+ temp = fabs(tpwgts[i]-npwgts[i])/tpwgts[i];
+ max = (max < temp ? temp : max);
+ }
+ return 1.0+max;
+}
+
+
+
+/*************************************************************************
+* This function performs an edge-based FM refinement
+**************************************************************************/
+void Moc_Serial_Balance2Way(GraphType *graph, float *tpwgts, float lbfactor)
+{
+ int i, ii, j, k, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, limit, tmp, cnum;
+ idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
+ idxtype *moved, *swaps, *qnum;
+ float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal;
+ FPQueueType parts[MAXNCON][2];
+ int higain, oldgain, mincut, newcut, mincutorder;
+ int qsizes[MAXNCON][2];
+ KeyValueType *cand;
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ nvwgt = graph->nvwgt;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ id = graph->sendind;
+ ed = graph->recvind;
+ npwgts = graph->gnpwgts;
+ bndptr = graph->sendptr;
+ bndind = graph->recvptr;
+
+ moved = idxmalloc(nvtxs, "moved");
+ swaps = idxmalloc(nvtxs, "swaps");
+ qnum = idxmalloc(nvtxs, "qnum");
+ cand = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "cand");
+
+
+ limit = amin(amax(0.01*nvtxs, 15), 100);
+
+ /* Initialize the queues */
+ for (i=0; i<ncon; i++) {
+ FPQueueInit(&parts[i][0], nvtxs);
+ FPQueueInit(&parts[i][1], nvtxs);
+ 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]]++;
+ }
+
+ 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;
+ }
+ }
+ }
+ }
+ }
+
+
+ for (i=0; i<ncon; i++)
+ mindiff[i] = fabs(tpwgts[i]-npwgts[i]);
+ minbal = origbal = Serial_Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
+ newcut = mincut = graph->mincut;
+ mincutorder = -1;
+
+ idxset(nvtxs, -1, moved);
+
+ /* Insert all nodes in the priority queues */
+ nbnd = graph->gnvtxs;
+ for (i=0; i<nvtxs; i++) {
+ cand[i].key = id[i]-ed[i];
+ cand[i].val = i;
+ }
+ ikeysort(nvtxs, cand);
+
+ for (ii=0; ii<nvtxs; ii++) {
+ i = cand[ii].val;
+ FPQueueInsert(&parts[qnum[i]][where[i]], i, (float)(ed[i]-id[i]));
+ }
+
+ for (nswaps=0; nswaps<nvtxs; nswaps++) {
+ if (minbal < lbfactor)
+ break;
+
+ Serial_SelectQueue(ncon, npwgts, tpwgts, &from, &cnum, parts);
+ to = (from+1)%2;
+
+ if (from == -1 || (higain = FPQueueGetMax(&parts[cnum][from])) == -1)
+ break;
+
+ saxpy2(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
+ saxpy2(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
+ newcut -= (ed[higain]-id[higain]);
+ newbal = Serial_Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
+
+ if (newbal < minbal || (newbal == minbal &&
+ (newcut < mincut || (newcut == mincut &&
+ Serial_BetterBalance(ncon, npwgts, tpwgts, mindiff))))) {
+ mincut = newcut;
+ minbal = newbal;
+ mincutorder = nswaps;
+ for (i=0; i<ncon; i++)
+ mindiff[i] = fabs(tpwgts[i]-npwgts[i]);
+ }
+ else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
+ newcut += (ed[higain]-id[higain]);
+ saxpy2(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
+ saxpy2(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
+ break;
+ }
+
+ where[higain] = to;
+ moved[higain] = nswaps;
+ swaps[nswaps] = higain;
+
+ /**************************************************************
+ * 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)
+ FPQueueUpdate(&parts[qnum[k]][where[k]], k, (float)(oldgain), (float)(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);
+
+ saxpy2(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
+ saxpy2(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);
+ }
+ }
+
+ graph->mincut = mincut;
+ graph->gnvtxs = nbnd;
+
+
+ for (i=0; i<ncon; i++) {
+ FPQueueFree(&parts[i][0]);
+ FPQueueFree(&parts[i][1]);
+ }
+
+ GKfree((void **)&cand, (void **)&qnum, (void **)&moved, (void **)&swaps, LTERM);
+ return;
+}
+
+/*************************************************************************
+* 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 Moc_Serial_Init2WayBalance(GraphType *graph, float *tpwgts)
+{
+ int i, ii, j, k;
+ int kwgt, nvtxs, nbnd, ncon, nswaps, from, to, cnum, tmp;
+ idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
+ idxtype *qnum;
+ float *nvwgt, *npwgts;
+ FPQueueType parts[MAXNCON][2];
+ int higain, oldgain, mincut;
+ KeyValueType *cand;
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ nvwgt = graph->nvwgt;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ id = graph->sendind;
+ ed = graph->recvind;
+ npwgts = graph->gnpwgts;
+ bndptr = graph->sendptr;
+ bndind = graph->recvptr;
+
+ qnum = idxmalloc(nvtxs, "qnum");
+ cand = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "cand");
+
+ /* This is called for initial partitioning so we know from where to pick nodes */
+ from = 1;
+ to = (from+1)%2;
+
+ for (i=0; i<ncon; i++) {
+ FPQueueInit(&parts[i][0], nvtxs);
+ FPQueueInit(&parts[i][1], nvtxs);
+ }
+
+ /* Compute the queues in which each vertex will be assigned to */
+ for (i=0; i<nvtxs; i++)
+ qnum[i] = samax(ncon, nvwgt+i*ncon);
+
+ for (i=0; i<nvtxs; i++) {
+ cand[i].key = id[i]-ed[i];
+ cand[i].val = i;
+ }
+ ikeysort(nvtxs, cand);
+
+ /* Insert the nodes of the proper partition in the appropriate priority queue */
+ for (ii=0; ii<nvtxs; ii++) {
+ i = cand[ii].val;
+ if (where[i] == from) {
+ if (ed[i] > 0)
+ FPQueueInsert(&parts[qnum[i]][0], i, (float)(ed[i]-id[i]));
+ else
+ FPQueueInsert(&parts[qnum[i]][1], i, (float)(ed[i]-id[i]));
+ }
+ }
+
+ mincut = graph->mincut;
+ nbnd = graph->gnvtxs;
+ for (nswaps=0; nswaps<nvtxs; nswaps++) {
+ if (Serial_AreAnyVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, tpwgts+from*ncon))
+ break;
+
+ if ((cnum = Serial_SelectQueueOneWay(ncon, npwgts, tpwgts, from, parts)) == -1)
+ break;
+
+
+ if ((higain = FPQueueGetMax(&parts[cnum][0])) == -1)
+ higain = FPQueueGetMax(&parts[cnum][1]);
+
+ mincut -= (ed[higain]-id[higain]);
+ saxpy2(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
+ saxpy2(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
+
+ where[higain] = to;
+
+ /**************************************************************
+ * 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 */
+ FPQueueDelete(&parts[qnum[k]][1], k);
+ FPQueueInsert(&parts[qnum[k]][0], k, (float)(ed[k]-id[k]));
+ }
+ else { /* It must be in the boundary already */
+ FPQueueUpdate(&parts[qnum[k]][0], k, (float)(oldgain), (float)(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);
+ }
+ }
+
+ graph->mincut = mincut;
+ graph->gnvtxs = nbnd;
+
+ for (i=0; i<ncon; i++) {
+ FPQueueFree(&parts[i][0]);
+ FPQueueFree(&parts[i][1]);
+ }
+
+ GKfree((void **)&cand, (void **)&qnum, LTERM);
+}
+
+
+/*************************************************************************
+* This function selects the partition number and the queue from which
+* we will move vertices out
+**************************************************************************/
+int Serial_SelectQueueOneWay(int ncon, float *npwgts, float *tpwgts, int from,
+ FPQueueType queues[MAXNCON][2])
+{
+ int i, cnum=-1;
+ float max=0.0;
+
+ for (i=0; i<ncon; i++) {
+ if (npwgts[from*ncon+i]-tpwgts[from*ncon+i] >= max &&
+ FPQueueGetQSize(&queues[i][0]) + FPQueueGetQSize(&queues[i][1]) > 0) {
+ max = npwgts[from*ncon+i]-tpwgts[i];
+ cnum = i;
+ }
+ }
+
+ return cnum;
+}
+
+
+/*************************************************************************
+* This function computes the initial id/ed
+**************************************************************************/
+void Moc_Serial_Compute2WayPartitionParams(GraphType *graph)
+{
+ int i, j, me, nvtxs, ncon, nbnd, mincut;
+ idxtype *xadj, *adjncy, *adjwgt;
+ float *nvwgt, *npwgts;
+ idxtype *id, *ed, *where;
+ idxtype *bndptr, *bndind;
+
+ 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->gnpwgts);
+ id = idxset(nvtxs, 0, graph->sendind);
+ ed = idxset(nvtxs, 0, graph->recvind);
+ bndptr = idxset(nvtxs, -1, graph->sendptr);
+ bndind = graph->recvptr;
+
+ /*------------------------------------------------------------
+ / Compute now the id/ed degrees
+ /------------------------------------------------------------*/
+ nbnd = mincut = 0;
+ for (i=0; i<nvtxs; i++) {
+ me = where[i];
+ saxpy2(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->gnvtxs = nbnd;
+
+}
+
+/*************************************************************************
+* This function checks if the vertex weights of two vertices are below
+* a given set of values
+**************************************************************************/
+int Serial_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[i])
+ return 1;
+
+ return 0;
+}
+
+
+/*************************************************************************
+* This function computes the edge-cut of a serial graph.
+**************************************************************************/
+int ComputeSerialEdgeCut(GraphType *graph)
+{
+ int i, j;
+ int cut = 0;
+
+ for (i=0; i<graph->nvtxs; i++) {
+ for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++)
+ if (graph->where[i] != graph->where[graph->adjncy[j]])
+ cut += graph->adjwgt[j];
+ }
+ graph->mincut = cut/2;
+
+ return graph->mincut;
+}
+
+/*************************************************************************
+* This function computes the TotalV of a serial graph.
+**************************************************************************/
+int ComputeSerialTotalV(GraphType *graph, idxtype *home)
+{
+ int i;
+ int totalv = 0;
+
+ for (i=0; i<graph->nvtxs; i++)
+ if (graph->where[i] != home[i])
+ totalv += (graph->vsize == NULL) ? graph->vwgt[i] : graph->vsize[i];
+
+ return totalv;
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/setup.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/setup.c
new file mode 100644
index 0000000..682a31d
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/setup.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * setup.c
+ *
+ * This file contains functions that setup the various communication
+ * data structures for parallel KWAY
+ *
+ * Started 2/21/96
+ * George
+ *
+ * $Id: setup.c,v 1.3 2003/07/31 16:23:30 karypis Exp $
+ *
+ */
+
+
+#include <parmetislib.h>
+
+#define DEBUG_SETUPINFO_
+
+
+/*************************************************************************
+* This function tests the repeated shmem_put
+**************************************************************************/
+void SetUp(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, j, k, islocal, penum, gnvtxs, nvtxs, nlocal, firstvtx, lastvtx, nsend, nrecv, nnbrs, nadj;
+ int npes=ctrl->npes, mype=ctrl->mype;
+ idxtype *vtxdist, *xadj, *adjncy;
+ idxtype *peind, *recvptr, *recvind, *sendptr, *sendind;
+ idxtype *receive, *pemap, *imap, *lperm;
+ idxtype *pexadj, *peadjncy, *peadjloc, *startsind;
+ KeyValueType *recvrequests, *sendrequests, *adjpairs;
+
+ IFSET(ctrl->dbglvl, DBG_TIME, MPI_Barrier(ctrl->comm));
+ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SetupTmr));
+
+ gnvtxs = graph->gnvtxs;
+ nvtxs = graph->nvtxs;
+ vtxdist = graph->vtxdist;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+
+ firstvtx = vtxdist[mype];
+ lastvtx = vtxdist[mype+1];
+
+ pemap = wspace->pv1;
+ idxset(npes, -1, pemap);
+
+ lperm = graph->lperm = idxmalloc(nvtxs, "SetUp: graph->lperm");
+ for (i=0; i<nvtxs; i++)
+ lperm[i] = i;
+
+ /*************************************************************
+ * Determine what you need to receive
+ *************************************************************/
+ receive = wspace->indices; /* Use the large global received array for now */
+ adjpairs = wspace->pairs;
+
+ for (nlocal = nadj = i = 0; i<nvtxs; i++) {
+ islocal = 1;
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ k = adjncy[j];
+ if (k >= firstvtx && k < lastvtx) {
+ adjncy[j] = k-firstvtx;
+ continue; /* local vertex */
+ }
+ adjpairs[nadj].key = k;
+ adjpairs[nadj++].val = j;
+ islocal = 0;
+ }
+ if (islocal) {
+ lperm[i] = lperm[nlocal];
+ lperm[nlocal++] = i;
+ }
+ }
+
+ /* Take care the received part now */
+ ikeysort(nadj, adjpairs);
+ adjpairs[nadj].key = gnvtxs+1; /* Boundary condition */
+ for (nrecv=i=0; i<nadj; i++) {
+ adjncy[adjpairs[i].val] = nvtxs+nrecv;
+ if (adjpairs[i].key != adjpairs[i+1].key)
+ receive[nrecv++] = adjpairs[i].key;
+ }
+
+
+ /* Allocate space for the setup info attached to this level of the graph */
+ peind = graph->peind = idxmalloc(npes, "SetUp: peind");
+ recvptr = graph->recvptr = idxmalloc(npes+1, "SetUp: recvptr");
+ recvind = graph->recvind = idxmalloc(nrecv, "SetUp: recvind");
+
+ /* Take care of the received portion */
+ idxcopy(nrecv, receive, recvind); /* Copy the vertices to be received into recvind */
+
+ i = nnbrs = recvptr[0] = 0;
+ for (penum=0; penum<npes; penum++) {
+ for (j=i; j<nrecv; j++) {
+ if (recvind[j] >= vtxdist[penum+1])
+ break;
+ }
+ if (j > i) {
+ peind[nnbrs] = penum;
+ recvptr[++nnbrs] = j;
+ i = j;
+ }
+ }
+
+
+ /*************************************************************
+ * Determine what you need to send
+ *************************************************************/
+ /* Tell the other processors what they need to send you */
+ recvrequests = wspace->pepairs1;
+ sendrequests = wspace->pepairs2;
+ for (i=0; i<npes; i++)
+ recvrequests[i].key = 0;
+ for (i=0; i<nnbrs; i++) {
+ recvrequests[peind[i]].key = recvptr[i+1]-recvptr[i];
+ recvrequests[peind[i]].val = nvtxs+recvptr[i];
+ }
+ MPI_Alltoall((void *)recvrequests, 2, IDX_DATATYPE, (void *)sendrequests, 2, IDX_DATATYPE, ctrl->comm);
+
+
+ sendptr = graph->sendptr = idxmalloc(npes+1, "SetUp: sendptr");
+ startsind = wspace->pv2;
+ for (j=i=0; i<npes; i++) {
+ if (sendrequests[i].key > 0) {
+ sendptr[j] = sendrequests[i].key;
+ startsind[j] = sendrequests[i].val;
+ j++;
+ }
+ }
+ ASSERT(ctrl, nnbrs == j);
+ MAKECSR(i, j, sendptr);
+
+ nsend = sendptr[nnbrs];
+ sendind = graph->sendind = idxmalloc(nsend, "SetUp: sendind");
+
+
+ /* Issue the receives for sendind */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Irecv((void *)(sendind+sendptr[i]), sendptr[i+1]-sendptr[i], IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->rreq+i);
+ }
+
+ /* Issue the sends. My recvind[penum] becomes penum's sendind[mype] */
+ for (i=0; i<nnbrs; i++) {
+ MPI_Isend((void *)(recvind+recvptr[i]), recvptr[i+1]-recvptr[i], IDX_DATATYPE,
+ peind[i], 1, ctrl->comm, ctrl->sreq+i);
+ }
+
+ MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+ MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+
+
+
+ /* Create the peadjncy data structure for sparse boundary exchanges */
+ pexadj = graph->pexadj = idxsmalloc(nvtxs+1, 0, "SetUp: pexadj");
+ peadjncy = graph->peadjncy = idxmalloc(nsend, "SetUp: peadjncy");
+ peadjloc = graph->peadjloc = idxmalloc(nsend, "SetUp: peadjloc");
+
+ for (i=0; i<nsend; i++) {
+ ASSERTP(ctrl, sendind[i] >= firstvtx && sendind[i] < lastvtx, (ctrl, "%d %d %d\n", sendind[i], firstvtx, lastvtx));
+ pexadj[sendind[i]-firstvtx]++;
+ }
+ MAKECSR(i, nvtxs, pexadj);
+
+ for (i=0; i<nnbrs; i++) {
+ for (j=sendptr[i]; j<sendptr[i+1]; j++) {
+ k = pexadj[sendind[j]-firstvtx]++;
+ peadjncy[k] = i; /* peind[i] is the actual PE number */
+ peadjloc[k] = startsind[i]++;
+ }
+ }
+ ASSERT(ctrl, pexadj[nvtxs] == nsend);
+
+ for (i=nvtxs; i>0; i--)
+ pexadj[i] = pexadj[i-1];
+ pexadj[0] = 0;
+
+
+ graph->nnbrs = nnbrs;
+ graph->nrecv = nrecv;
+ graph->nsend = nsend;
+ graph->nlocal = nlocal;
+
+
+ /* Create the inverse map from ladjncy to adjncy */
+ imap = graph->imap = idxmalloc(nvtxs+nrecv, "SetUp: imap");
+ for (i=0; i<nvtxs; i++)
+ imap[i] = firstvtx+i;
+ for (i=0; i<nrecv; i++)
+ imap[nvtxs+i] = recvind[i];
+
+
+ /* Check if wspace->nlarge is large enough for nrecv and nsend */
+ if (wspace->nlarge < nrecv+nsend) {
+ free(wspace->indices);
+ free(wspace->pairs);
+ wspace->nlarge = nrecv+nsend;
+ wspace->indices = idxmalloc(wspace->nlarge, "SetUp: wspace->indices");
+ wspace->pairs = (KeyValueType *)GKmalloc(sizeof(KeyValueType)*wspace->nlarge, "SetUp: wspace->pairs");
+ }
+
+ IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SetupTmr));
+
+#ifdef DEBUG_SETUPINFO
+ rprintf(ctrl, "[%5d %5d] \tl:[%5d %5d] \ts:[%5d, %5d] \tr:[%5d, %5d]\n",
+ GlobalSEMin(ctrl, nvtxs), GlobalSEMax(ctrl, nvtxs),
+ GlobalSEMin(ctrl, nlocal), GlobalSEMax(ctrl, nlocal),
+ GlobalSEMin(ctrl, nsend), GlobalSEMax(ctrl, nsend),
+ GlobalSEMin(ctrl, nrecv), GlobalSEMax(ctrl, nrecv));
+
+ PrintSetUpInfo(ctrl, graph);
+#endif
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/stat.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/stat.c
new file mode 100644
index 0000000..4a32bc8
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/stat.c
@@ -0,0 +1,332 @@
+/*
+ * 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.3 2003/07/23 00:54:56 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+/*************************************************************************
+* This function computes the balance of the partitioning
+**************************************************************************/
+void Moc_ComputeSerialBalance(CtrlType *ctrl, GraphType *graph, idxtype *where, float *ubvec)
+{
+ int i, j, nvtxs, ncon, nparts;
+ idxtype *pwgts, *tvwgts, *vwgt;
+ float *tpwgts, maximb;
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ vwgt = graph->vwgt;
+ nparts = ctrl->nparts;
+ tpwgts = ctrl->tpwgts;
+
+ pwgts = idxsmalloc(nparts*ncon, 0, "pwgts");
+ tvwgts = idxsmalloc(ncon, 0, "tvwgts");
+
+ for (i=0; i<graph->nvtxs; i++) {
+ for (j=0; j<ncon; j++) {
+ pwgts[where[i]*ncon+j] += vwgt[i*ncon+j];
+ tvwgts[j] += vwgt[i*ncon+j];
+ }
+ }
+
+ /* The +1 in the following code is to deal with bad cases of tpwgts[i*ncon+j] == 0 */
+ for (j=0; j<ncon; j++) {
+ maximb = 0.0;
+ for (i=0; i<nparts; i++)
+ maximb = amax(maximb, (1.0+(float)pwgts[i*ncon+j])/(1.0+(tpwgts[i*ncon+j]*(float)tvwgts[j])));
+ ubvec[j] = maximb;
+ }
+
+ GKfree((void **)&pwgts, (void **)&tvwgts, LTERM);
+}
+
+
+/*************************************************************************
+* This function computes the balance of the partitioning
+**************************************************************************/
+void Moc_ComputeParallelBalance(CtrlType *ctrl, GraphType *graph, idxtype *where, float *ubvec)
+{
+ int i, j, nvtxs, ncon, nparts;
+ float *nvwgt, *lnpwgts, *gnpwgts;
+ float *tpwgts, maximb;
+ float lminvwgts[MAXNCON], gminvwgts[MAXNCON];
+
+ ncon = graph->ncon;
+ nvtxs = graph->nvtxs;
+ nvwgt = graph->nvwgt;
+ nparts = ctrl->nparts;
+ tpwgts = ctrl->tpwgts;
+
+ lnpwgts = fmalloc(nparts*ncon, "CPB: lnpwgts");
+ gnpwgts = fmalloc(nparts*ncon, "CPB: gnpwgts");
+ sset(nparts*ncon, 0.0, lnpwgts);
+ sset(ncon, 1.0, lminvwgts);
+
+ for (i=0; i<nvtxs; i++) {
+ for (j=0; j<ncon; j++) {
+ lnpwgts[where[i]*ncon+j] += nvwgt[i*ncon+j];
+
+ /* The following is to deal with tpwgts[] that are 0.0 for certain partitions/constraints */
+ lminvwgts[j] = (nvwgt[i*ncon+j] > 0.0 && lminvwgts[j] > nvwgt[i*ncon+j] ? nvwgt[i*ncon+j] : lminvwgts[j]);
+ }
+ }
+
+ MPI_Allreduce((void *)(lnpwgts), (void *)(gnpwgts), nparts*ncon, MPI_FLOAT, MPI_SUM, ctrl->comm);
+ MPI_Allreduce((void *)(lminvwgts), (void *)(gminvwgts), ncon, MPI_FLOAT, MPI_MIN, ctrl->comm);
+
+ /* The +gminvwgts[j] in the following code is to deal with bad cases of tpwgts[i*ncon+j] == 0 */
+ for (j=0; j<ncon; j++) {
+ maximb = 0.0;
+ for (i=0; i<nparts; i++)
+ maximb = amax(maximb, (gminvwgts[j]+gnpwgts[i*ncon+j])/(gminvwgts[j]+tpwgts[i*ncon+j]));
+ ubvec[j] = maximb;
+ }
+
+ GKfree((void **)&lnpwgts, (void **)&gnpwgts, LTERM);
+
+ return;
+}
+
+
+/*************************************************************************
+* This function prints a matrix
+**************************************************************************/
+void Moc_PrintThrottleMatrix(CtrlType *ctrl, GraphType *graph, float *matrix)
+{
+ int i, j;
+
+ for (i=0; i<ctrl->npes; i++) {
+ if (i == ctrl->mype) {
+ for (j=0; j<ctrl->npes; j++)
+ printf("%.3f ", matrix[j]);
+ printf("\n");
+ fflush(stdout);
+ }
+ MPI_Barrier(ctrl->comm);
+ }
+
+ if (ctrl->mype == 0) {
+ printf("****************************\n");
+ fflush(stdout);
+ }
+ MPI_Barrier(ctrl->comm);
+
+ return;
+}
+
+
+/*************************************************************************
+* This function computes stats for refinement
+**************************************************************************/
+void Moc_ComputeRefineStats(CtrlType *ctrl, GraphType *graph, float *ubvec)
+{
+ int h, i, j, k;
+ int nvtxs, ncon;
+ idxtype *xadj, *adjncy, *adjwgt, *where;
+ float *nvwgt, *lnpwgts, *gnpwgts;
+ RInfoType *rinfo;
+ int mype = ctrl->mype, nparts = ctrl->nparts;
+ idxtype *gborder, *border, *gfrom, *from, *gto, *to, *connect, *gconnect;
+ idxtype gain[20] = {0}, ggain[20];
+ int lnborders, gnborders;
+ int bestgain, pmoves, gpmoves, other;
+ float tpwgts[MAXNCON], badmaxpwgt[MAXNCON];
+ int HIST_FACTOR = graph->level + 1;
+
+ nvtxs = graph->nvtxs;
+ ncon = graph->ncon;
+ xadj = graph->xadj;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ lnpwgts = graph->lnpwgts;
+ gnpwgts = graph->gnpwgts;
+ rinfo = graph->rinfo;
+
+ connect = idxsmalloc(nparts*nparts, 0, "CRS: connect");
+ gconnect = idxmalloc(nparts*nparts, "CRS: gconnect");
+ border = idxsmalloc(nparts, 0, "CRS: border");
+ gborder = idxmalloc(nparts, "CRS: gborder");
+ from = idxsmalloc(nparts, 0, "CRS: from");
+ gfrom = idxmalloc(nparts, "CRS: gfrom");
+ to = idxsmalloc(nparts, 0, "CRS: to");
+ gto = idxmalloc(nparts, "CRS: gto");
+
+ for (h=0; h<ncon; h++) {
+ tpwgts[h] = ssum_strd(nparts, gnpwgts+h, ncon)/(float)(nparts);
+ badmaxpwgt[h] = ubvec[h]*tpwgts[h];
+ }
+
+ if (mype == 0) printf("******************************\n");
+ if (mype == 0) printf("******************************\n");
+
+ /***************************************/
+ if (mype == 0) {
+ printf("subdomain weights:\n");
+ for (h=0; h<ncon; h++) {
+ for (i=0; i<nparts; i++)
+ printf("%9.3f ", gnpwgts[i*ncon+h]);
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ /***************************************/
+ if (mype == 0) {
+ printf("subdomain imbalance:\n");
+ for (h=0; h<ncon; h++) {
+ for (i=0; i<nparts; i++)
+ printf("%9.3f ", gnpwgts[i*ncon+h] * (float)(nparts));
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ /***************************************/
+ for (i=0; i<nparts; i++)
+ connect[i*nparts+i] = -1;
+
+ for (i=0; i<nvtxs; i++) {
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ if (where[i] != where[adjncy[j]]) {
+ connect[where[i]*nparts+where[adjncy[j]]] = 1;
+ connect[where[adjncy[j]]*nparts+where[i]] = 1;
+ }
+ }
+ }
+
+ MPI_Reduce((void *)connect, (void *)gconnect, nparts*nparts, IDX_DATATYPE, MPI_MAX, 0, ctrl->comm);
+ if (mype == 0) {
+ printf("connectivity\n");
+ for (i=0; i<nparts; i++) {
+ printf("%d: ", i);
+ for (j=0; j<nparts; j++)
+ printf("%9d ", gconnect[i*nparts+j]);
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ /***************************************/
+ lnborders = 0;
+ for (i=0; i<nvtxs; i++)
+ if (rinfo[i].ndegrees > 0) {
+ lnborders++;
+ border[where[i]]++;
+ }
+
+ MPI_Reduce((void *)border, (void *)gborder, nparts, IDX_DATATYPE, MPI_SUM, 0, ctrl->comm);
+ gnborders = GlobalSESum(ctrl, lnborders);
+ if (mype == 0) {
+ printf("number of borders: %d\n", gnborders);
+ for (i=0; i<nparts; i++)
+ printf("%9d ", gborder[i]);
+ printf("\n\n");
+ }
+
+ /***************************************/
+ pmoves = 0;
+ for (i=0; i<nvtxs; i++) {
+ nvwgt = graph->nvwgt+i*ncon;
+
+ for (j=0; j<rinfo[i].ndegrees; j++) {
+ other = rinfo[i].degrees[j].edge;
+ for (h=0; h<ncon; h++)
+ if (gnpwgts[other*ncon+h]+nvwgt[h] > badmaxpwgt[h])
+ break;
+
+ if (h == ncon)
+ break;
+ }
+
+ if (j < rinfo[i].ndegrees) {
+ pmoves++;
+ from[where[i]]++;
+ to[other]++;
+ for (k=j+1; k<rinfo[i].ndegrees; k++) {
+ other = rinfo[i].degrees[k].edge;
+ for (h=0; h<ncon; h++)
+ if (gnpwgts[other*ncon+h]+nvwgt[h] > badmaxpwgt[h])
+ break;
+
+ if (h == ncon) {
+ pmoves++;
+ from[where[i]]++;
+ to[other]++;
+ }
+ }
+ }
+ }
+
+ gpmoves = GlobalSESum(ctrl, pmoves);
+ MPI_Reduce((void *)from, (void *)gfrom, nparts, IDX_DATATYPE, MPI_SUM, 0, ctrl->comm);
+ MPI_Reduce((void *)to, (void *)gto, nparts, IDX_DATATYPE, MPI_SUM, 0, ctrl->comm);
+
+ if (mype == 0) {
+ printf("possible moves: %d\n", gpmoves);
+ printf("from ");
+ for (i=0; i<nparts; i++) {
+ printf("%9d ", gfrom[i]);
+ }
+ printf("\n");
+ printf("to ");
+ for (i=0; i<nparts; i++) {
+ printf("%9d ", gto[i]);
+ }
+ printf("\n\n");
+ }
+
+ /***************************************/
+ for (i=0; i<nvtxs; i++) {
+ if (rinfo[i].ndegrees > 0) {
+ bestgain = rinfo[i].degrees[0].ewgt-rinfo[i].id;
+ for (j=0; j<rinfo[i].ndegrees; j++)
+ bestgain = amax(bestgain, rinfo[i].degrees[j].ewgt-rinfo[i].id);
+
+ if (bestgain / HIST_FACTOR >= 10) {
+ gain[19]++;
+ continue;
+ }
+
+ if (bestgain / HIST_FACTOR < -10) {
+ gain[0]++;
+ continue;
+ }
+
+ gain[(bestgain/HIST_FACTOR)+10]++;
+ }
+ }
+
+ MPI_Reduce((void *)gain, (void *)ggain, 20, IDX_DATATYPE, MPI_SUM, 0, ctrl->comm);
+ if (mype == 0) {
+ printf("gain histogram (buckets of %d)\n", HIST_FACTOR);
+ for (i=0; i<20; i++) {
+ if (i == 10 || i == 11)
+ printf(" ");
+ printf("%d ", ggain[i]);
+ }
+ printf("\n\n");
+ }
+
+
+
+
+ /***************************************/
+ if (mype == 0) printf("******************************\n");
+ if (mype == 0) printf("******************************\n");
+
+ GKfree((void **)&gconnect, (void **)&connect, (void **)&gborder, (void **)&border, (void **)&gfrom, (void **)&from, (void **)&gto, (void **)&to, LTERM);
+ return;
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/stdheaders.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/stdheaders.h
new file mode 100644
index 0000000..e30f989
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/stdheaders.h
@@ -0,0 +1,25 @@
+/*
+ * 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.4 2003/07/25 14:31:47 karypis Exp $
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <time.h>
+#include <mpi.h>
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/struct.h b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/struct.h
new file mode 100644
index 0000000..3016c5e
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/struct.h
@@ -0,0 +1,290 @@
+/*
+ * 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/21 17:50:22 karypis Exp $
+ */
+
+/* Indexes are as long as integers for now */
+#ifdef IDXTYPE_INT
+#define IDX_DATATYPE MPI_INT
+#define MAX_INT INT_MAX
+#define MIN_INT INT_MIN
+#else
+#define IDX_DATATYPE MPI_SHORT
+#define MAX_INT SHRT_MAX
+#define MIN_INT SHRT_MIN
+#endif
+
+
+/*************************************************************************
+* The following data structure stores key-value pair
+**************************************************************************/
+struct KeyValueType {
+ idxtype key;
+ idxtype val;
+};
+
+typedef struct KeyValueType KeyValueType;
+
+/*************************************************************************
+* The following data structure stores key-value pair
+**************************************************************************/
+struct KVType {
+ int key;
+ float val;
+};
+
+typedef struct KVType KVType;
+
+
+/*************************************************************************
+* The following data structure stores key-value pair
+**************************************************************************/
+struct FKeyValueType {
+ float key;
+ idxtype val;
+};
+
+typedef struct FKeyValueType FKeyValueType;
+
+/*************************************************************************
+* The following data structure stores key-key-value triplets
+**************************************************************************/
+struct KeyKeyValueType {
+ idxtype key1, key2;
+ idxtype val;
+};
+
+typedef struct KeyKeyValueType KeyKeyValueType;
+
+/*************************************************************************
+* The following data structure is used to store the buckets for the
+* refinment algorithms
+**************************************************************************/
+struct PQueueType {
+ int nnodes;
+ int maxnnodes;
+ idxtype *perm, *iperm, *values;
+ /* iperm[i] stores where the ith entry is located
+ perm[i] stores the entry that is located in the ith position */
+};
+
+typedef struct PQueueType PQueueType;
+
+
+/*************************************************************************
+* The following data structure is used to store the buckets for the
+* refinment algorithms
+**************************************************************************/
+struct FPQueueType {
+ int type; /* The type of the representation used */
+ int nnodes;
+ int maxnodes;
+
+ /* Heap version of the data structure */
+ FKeyValueType *heap;
+ idxtype *locator;
+};
+
+typedef struct FPQueueType FPQueueType;
+
+/*************************************************************************
+* The following data structure stores an edge
+**************************************************************************/
+struct edgedef {
+ idxtype edge;
+ idxtype ewgt;
+};
+typedef struct edgedef EdgeType;
+
+
+/*************************************************************************
+* This data structure holds various working space data
+**************************************************************************/
+struct workspacedef {
+ idxtype *core; /* Where pairs, indices, and degrees are coming from */
+ int maxcore;
+
+ int nlarge; /* The size of 'Large' */
+
+ KeyValueType *pairs; /* Large pair array used during setup */
+ idxtype *indices; /* Large array of indxtype used for various purposes */
+
+ /* Auxiliary parameters */
+ idxtype *pv1, *pv2, *pv3, *pv4; /* Vectors of npes+1 size used in various places */
+ KeyValueType *pepairs1, *pepairs2;
+
+ EdgeType *degrees;
+};
+
+typedef struct workspacedef WorkSpaceType;
+
+
+/*************************************************************************
+* The following data structure holds information on degrees for k-way
+* partition
+**************************************************************************/
+struct rinfodef {
+ int id, ed; /* ID/ED of edges */
+ int ndegrees; /* The number of different ext-degrees */
+ EdgeType *degrees; /* List of edges */
+};
+
+typedef struct rinfodef RInfoType;
+
+
+/*************************************************************************
+* The following data structure holds information on degrees for k-way
+* partition
+**************************************************************************/
+struct nrinfodef {
+ int edegrees[2];
+};
+
+typedef struct nrinfodef NRInfoType;
+
+
+/*************************************************************************
+* The following data structure stores a sparse matrix in CSR format
+* The diagonal entry is in the first position of each row.
+**************************************************************************/
+struct matrixdef {
+ int nrows, nnzs; /* Number of rows and nonzeros in the matrix */
+ idxtype *rowptr;
+ idxtype *colind;
+ float *values;
+ float *transfer;
+};
+
+typedef struct matrixdef MatrixType;
+
+
+/*************************************************************************
+* This data structure holds the input graph
+**************************************************************************/
+struct graphdef {
+ int gnvtxs, nvtxs, nedges, ncon, nobj;
+ idxtype *xadj; /* Pointers to the locally stored vertices */
+ idxtype *vwgt; /* Vertex weights */
+ float *nvwgt; /* Vertex weights */
+ idxtype *vsize; /* Vertex size */
+ idxtype *adjncy; /* Array that stores the adjacency lists of nvtxs */
+ idxtype *adjwgt; /* Array that stores the weights of the adjacency lists */
+ idxtype *vtxdist; /* Distribution of vertices */
+
+ idxtype *match;
+ idxtype *cmap;
+
+ idxtype *label;
+
+ /* Communication/Setup parameters */
+ int nnbrs, nrecv, nsend; /* The number of neighboring processors */
+ idxtype *peind; /* Array of size nnbrs storing the neighboring PEs */
+ idxtype *sendptr, *sendind; /* CSR format of the vertices that are sent */
+ idxtype *recvptr, *recvind; /* CSR format of the vertices that are received */
+ idxtype *imap; /* The inverse map of local to global indices */
+ idxtype *pexadj, *peadjncy,
+ *peadjloc; /* CSR format of the PEs each vertex is adjancent to */
+
+ int nlocal; /* Number of interior vertices */
+ idxtype *lperm; /* lperm[0:nlocal] points to interior vertices, the rest are interface */
+
+ /* Communication parameters for projecting the partition.
+ * These are computed during CreateCoarseGraph and used during projection
+ * Note that during projection, the meaning of received and sent is reversed! */
+ idxtype *rlens, *slens; /* Arrays of size nnbrs of how many vertices you are sending and receiving */
+ KeyValueType *rcand;
+
+
+ /* Partition parameters */
+ idxtype *where, *home;
+ idxtype *lpwgts, *gpwgts;
+ float *lnpwgts, *gnpwgts;
+ RInfoType *rinfo;
+
+ /* Node refinement information */
+ NRInfoType *nrinfo;
+ int nsep; /* The number of vertices in the separator */
+ idxtype *sepind; /* The indices of the vertices in the separator */
+
+ int lmincut, mincut;
+
+ int level;
+ int match_type;
+ int edgewgt_type;
+
+ 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 parallel kmetis
+**************************************************************************/
+struct controldef {
+ int mype, npes; /* Info about the parallel system */
+ int CoarsenTo; /* The # of vertices in the coarsest graph */
+ int dbglvl; /* Controls the debuging output of the program */
+ int nparts; /* The number of partitions */
+ int foldf; /* What is the folding factor */
+ int ipart; /* The type of initial partitioning */
+ int xyztype; /* The type of coordinate indexing */
+ int seed; /* Random number seed */
+ int sync; /* Random number seed */
+ float *tpwgts; /* Target subdomain weights */
+ int tvwgts[MAXNCON];
+ float ubvec[MAXNCON];
+ int partType;
+ int ps_relation;
+
+ float redist_factor, redist_base, ipc_factor;
+ float edge_size_ratio;
+ MatrixType *matrix;
+
+ MPI_Comm gcomm;
+ MPI_Comm comm; /* MPI Communicator */
+ MPI_Request sreq[MAX_PES],
+ rreq[MAX_PES]; /* MPI send and receive requests */
+ MPI_Status statuses[MAX_PES];
+ MPI_Status status;
+
+ /* Various Timers */
+ timer TotalTmr, InitPartTmr, MatchTmr, ContractTmr, CoarsenTmr, RefTmr,
+ SetupTmr, ColorTmr, ProjectTmr, KWayInitTmr, KWayTmr, MoveTmr,
+ RemapTmr, AuxTmr1, AuxTmr2, AuxTmr3, AuxTmr4, AuxTmr5, AuxTmr6;
+};
+
+typedef struct controldef CtrlType;
+
+
+
+/*************************************************************************
+* The following data structure stores a mesh.
+**************************************************************************/
+struct meshdef {
+ int etype;
+ int gnelms, gnns;
+ int nelms, nns;
+ int ncon;
+ int esize, gminnode;
+ idxtype *elmdist;
+ idxtype *elements;
+ idxtype *elmwgt;
+};
+
+typedef struct meshdef MeshType;
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/sync b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/sync
new file mode 100644
index 0000000..11a0cfb
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/sync
@@ -0,0 +1,186 @@
+adrivers.c: ubavg = savg(graph->ncon, ctrl->ubvec);
+adrivers.c: ctrl->redist_factor = ctrl->redist_base * ((gtewgt/gtvsize)/ ctrl->edge_size_ratio);
+adrivers.c: IFSET(ctrl->dbglvl, DBG_PROGRESS, rprintf(ctrl, "[%6d %8d %5d %5d][%d]\n",
+adrivers.c: graph->gnvtxs, GlobalSESum(ctrl, graph->nedges), GlobalSEMin(ctrl, graph->nvtxs), GlobalSEMax(ctrl, graph->nvtxs), ctrl->CoarsenTo));
+adrivers.c: if (graph->gnvtxs < 1.3*ctrl->CoarsenTo ||
+adrivers.c: if (lbavg > ubavg + 0.035 && ctrl->partType != REFINE_PARTITION)
+adrivers.c: if (ctrl->dbglvl&DBG_PROGRESS) {
+adrivers.c: switch (ctrl->ps_relation) {
+adrivers.c: if (ctrl->dbglvl&DBG_PROGRESS) {
+akwayfm.c: int npes = ctrl->npes, mype = ctrl->mype, nparts = ctrl->nparts;
+akwayfm.c: IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->KWayTmr));
+akwayfm.c: ubvec = ctrl->ubvec;
+akwayfm.c: tpwgts = ctrl->tpwgts;
+akwayfm.c: ipc_factor = ctrl->ipc_factor;
+akwayfm.c: redist_factor = ctrl->redist_factor;
+akwayfm.c: MPI_Bcast((void *)pperm, nparts, IDX_DATATYPE, 0, ctrl->comm);
+akwayfm.c: switch (ctrl->ps_relation) {
+akwayfm.c: switch (ctrl->ps_relation) {
+akwayfm.c: MPI_Allreduce((void *)lnpwgts, (void *)pgnpwgts, nparts*ncon, MPI_FLOAT, MPI_SUM, ctrl->comm);
+akwayfm.c: IFSET(ctrl->dbglvl, DBG_RMOVEINFO, rprintf(ctrl, "\t[%d %d], [%.4f], [%d %d %d]\n",
+akwayfm.c: MPI_Irecv((void *)(rupdate+sendptr[i]), sendptr[i+1]-sendptr[i], IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->rreq+i);
+akwayfm.c: MPI_Isend((void *)(supdate+j), k-j, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+akwayfm.c: MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+akwayfm.c: MPI_Get_count(ctrl->statuses+i, IDX_DATATYPE, nupds_pe+i);
+akwayfm.c: MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+akwayfm.c: MPI_Allreduce((void *)lnpwgts, (void *)gnpwgts, nparts*ncon, MPI_FLOAT, MPI_SUM, ctrl->comm);
+akwayfm.c: IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->KWayTmr));
+balancemylink.c: ipc_factor = ctrl->ipc_factor;
+balancemylink.c: redist_factor = ctrl->redist_factor;
+coarsen.c: int npes=ctrl->npes, mype=ctrl->mype;
+coarsen.c: MPI_Allgather((void *)(cvtxdist+npes), 1, IDX_DATATYPE, (void *)cvtxdist, 1, IDX_DATATYPE, ctrl->comm);
+coarsen.c: MPI_Irecv((void *)(rsizes+i), 1, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->rreq+i);
+coarsen.c: MPI_Isend((void *)(ssizes+i), 1, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+coarsen.c: MPI_Wait(ctrl->rreq+i, &ctrl->status);
+coarsen.c: MPI_Wait(ctrl->sreq+i, &ctrl->status);
+coarsen.c: MPI_Irecv((void *)(rgraph+l), (4+ncon)*(rlens[i+1]-rlens[i])+2*rsizes[i], IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->rreq+i);
+coarsen.c: sgraph[ll++] = (ctrl->partType == STATIC_PARTITION) ? -1 : vsize[ii];
+coarsen.c: sgraph[ll++] = (ctrl->partType == STATIC_PARTITION) ? -1 : home[ii];
+coarsen.c: MPI_Isend((void *)(sgraph+l), ll-l, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+coarsen.c: MPI_Wait(ctrl->rreq+i, &ctrl->status);
+coarsen.c: MPI_Wait(ctrl->sreq+i, &ctrl->status);
+coarsen.c: if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+coarsen.c: if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+coarsen.c: if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+coarsen.c: if (ctrl->partType == ADAPTIVE_PARTITION || ctrl->partType == REFINE_PARTITION) {
+coarsen.c: cgraph->nvwgt[j*ncon+h] = (float)(cvwgt[j*ncon+h])/(float)(ctrl->tvwgts[h]);
+comm.c: firstvtx = graph->vtxdist[ctrl->mype];
+comm.c: peind[i], 1, ctrl->comm, ctrl->rreq+i);
+comm.c: peind[i], 1, ctrl->comm, ctrl->sreq+i);
+comm.c: MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses);
+comm.c: MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+comm.c: firstvtx = graph->vtxdist[ctrl->mype];
+comm.c: peind[i], 1, ctrl->comm, ctrl->rreq+i);
+comm.c: idxcopy(ctrl->npes, sendptr, psendptr);
+comm.c: peind[i], 1, ctrl->comm, ctrl->sreq+i);
+comm.c: MPI_Isend((void *)(sendpairs), 0, IDX_DATATYPE, peind[i], 1, ctrl->comm, ctrl->sreq+i);
+comm.c: MPI_Wait(ctrl->rreq+i, &(ctrl->status));
+comm.c: MPI_Get_count(&ctrl->status, IDX_DATATYPE, &n);
+comm.c: MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses);
+comm.c: MPI_Allreduce((void *)&value, (void *)&max, 1, MPI_INT, MPI_MAX, ctrl->comm);
+comm.c: MPI_Allreduce((void *)&value, (void *)&max, 1, MPI_DOUBLE, MPI_MAX, ctrl->comm);
+comm.c: MPI_Allreduce((void *)&value, (void *)&min, 1, MPI_INT, MPI_MIN, ctrl->comm);
+comm.c: MPI_Allreduce((void *)&value, (void *)&sum, 1, MPI_INT, MPI_SUM, ctrl->comm);
+comm.c: MPI_Allreduce((void *)&value, (void *)&max, 1, MPI_FLOAT, MPI_MAX, ctrl->comm);
+comm.c: MPI_Allreduce((void *)&value, (void *)&min, 1, MPI_FLOAT, MPI_MIN, ctrl->comm);
+comm.c: MPI_Allreduce((void *)&value, (void *)&sum, 1, MPI_FLOAT, MPI_SUM, ctrl->comm);
+debug.c: for (penum=0; penum<ctrl->npes; penum++) {
+debug.c: if (ctrl->mype == penum) {
+debug.c: if (ctrl->mype == 0)
+debug.c: printf("\t%3d. ", ctrl->mype);
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: for (penum=0; penum<ctrl->npes; penum++) {
+debug.c: if (ctrl->mype == penum) {
+debug.c: if (ctrl->mype == 0)
+debug.c: printf("\t%3d. ", ctrl->mype);
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: for (penum=0; penum<ctrl->npes; penum++) {
+debug.c: if (ctrl->mype == penum) {
+debug.c: if (ctrl->mype == 0)
+debug.c: printf("\t%3d. ", ctrl->mype);
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: firstvtx = graph->vtxdist[ctrl->mype];
+debug.c: for (penum=0; penum<ctrl->npes; penum++) {
+debug.c: if (ctrl->mype == penum) {
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: firstvtx = graph->vtxdist[ctrl->mype];
+debug.c: for (penum=0; penum<ctrl->npes; penum++) {
+debug.c: if (ctrl->mype == penum) {
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: for (penum=0; penum<ctrl->npes; penum++) {
+debug.c: if (ctrl->mype == penum) {
+debug.c: printf("PE: %d, nnbrs: %d\n", ctrl->mype, graph->nnbrs);
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: MPI_Barrier(ctrl->comm);
+debug.c: for (penum=0; penum<ctrl->npes; penum++) {
+debug.c: if (ctrl->mype == penum) {
+debug.c: printf("PE: %d, nnbrs: %d", ctrl->mype, nnbrs);
+debug.c: MPI_Barrier(ctrl->comm);
+diffutil.c: nparts = ctrl->nparts;
+diffutil.c: myhome = (ctrl->ps_relation == COUPLED) ? ctrl->mype : graph->home[i];
+diffutil.c: /* PrintVector(ctrl, ctrl->npes, 0, lend, "Lend: "); */
+diffutil.c: MPI_Allreduce((void *)lstart, (void *)gstart, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+diffutil.c: MPI_Allreduce((void *)lleft, (void *)gleft, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+diffutil.c: MPI_Allreduce((void *)lend, (void *)gend, nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+grsetup.c: graph->gnvtxs = vtxdist[ctrl->npes];
+grsetup.c: graph->nvtxs = vtxdist[ctrl->mype+1]-vtxdist[ctrl->mype];
+grsetup.c: ctrl->tvwgts[j] = GlobalSESum(ctrl, ltvwgts[j]);
+grsetup.c: if (ctrl->tvwgts[i] == 0) {
+grsetup.c: graph->nvwgt[i*ncon+j] = (float)(graph->vwgt[i*ncon+j]) / (float)(ctrl->tvwgts[j]);
+grsetup.c: srand(ctrl->seed);
+grsetup.c: MPI_Comm_dup(comm, &(ctrl->gcomm));
+grsetup.c: MPI_Comm_rank(ctrl->gcomm, &ctrl->mype);
+grsetup.c: MPI_Comm_size(ctrl->gcomm, &ctrl->npes);
+grsetup.c: ctrl->dbglvl = dbglvl;
+grsetup.c: ctrl->nparts = nparts; /* Set the # of partitions is de-coupled from the # of domains */
+grsetup.c: ctrl->comm = ctrl->gcomm;
+grsetup.c: ctrl->xyztype = XYZ_SPFILL;
+grsetup.c: srand(ctrl->mype);
+grsetup.c: lpvtxs = idxsmalloc(ctrl->nparts, 0, "ComputeMoveStatistics: lpvtxs");
+grsetup.c: gpvtxs = idxsmalloc(ctrl->nparts, 0, "ComputeMoveStatistics: gpvtxs");
+grsetup.c: if (where[i] != ctrl->mype)
+grsetup.c: /* PrintVector(ctrl, ctrl->npes, 0, lpvtxs, "Lpvtxs: "); */
+grsetup.c: MPI_Allreduce((void *)lpvtxs, (void *)gpvtxs, ctrl->nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm);
+grsetup.c: *maxin = GlobalSEMax(ctrl, gpvtxs[ctrl->mype]-(nvtxs-j));
+initbalance.c: IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
+initbalance.c: mytpwgts = fsmalloc(ctrl->nparts, 0.0, "mytpwgts");
+initbalance.c: for (i=0; i<ctrl->nparts; i++)
+initbalance.c: mytpwgts[i] += ctrl->tpwgts[i*ncon+j];
+initbalance.c: for (i=0; i<ctrl->nparts; i++)
+initbalance.c: if (ctrl->ps_relation == DISCOUPLED) {
+initbalance.c: rcounts = imalloc(ctrl->npes, "rcounts");
+initbalance.c: rdispls = imalloc(ctrl->npes+1, "rdispls");
+initbalance.c: for (i=0; i<ctrl->npes; i++) {
+initbalance.c: MAKECSR(i, ctrl->npes, rdispls);
+initbalance.c: (void *)part, rcounts, rdispls, IDX_DATATYPE, ctrl->comm);
+initbalance.c: for (i=0; i<ctrl->npes; i++)
+initbalance.c: if (part[i] >= ctrl->nparts)
+initbalance.c: part[i] = home[i] = part[i] % ctrl->nparts;
+initbalance.c: part[i] = home[i] = (-1*part[i]) % ctrl->nparts;
+initbalance.c: IFSET(ctrl->dbglvl, DBG_REFINEINFO, Moc_ComputeSerialBalance(ctrl, agraph, agraph->where, lbvec));
+initbalance.c: IFSET(ctrl->dbglvl, DBG_REFINEINFO, rprintf(ctrl, "input cut: %d, balance: ", ComputeSerialEdgeCut(agraph)));
+initbalance.c: IFSET(ctrl->dbglvl, DBG_REFINEINFO, rprintf(ctrl, "%.3f ", lbvec[i]));
+initbalance.c: IFSET(ctrl->dbglvl, DBG_REFINEINFO, rprintf(ctrl, "\n"));
+initbalance.c: sr = (ctrl->mype % 2 == 0) ? 1 : 0;
+initbalance.c: gd = (ctrl->mype % 2 == 1) ? 1 : 0;
+initbalance.c: if (graph->ncon > MAX_NCON_FOR_DIFFUSION || ctrl->npes == 1) {
+initbalance.c: MPI_Comm_split(ctrl->gcomm, sr, 0, &ipcomm);
+initbalance.c: myctrl.sync = ctrl->sync;
+initbalance.c: myctrl.seed = ctrl->seed;
+initbalance.c: myctrl.nparts = ctrl->nparts;
+initbalance.c: myctrl.ipc_factor = ctrl->ipc_factor;
+initbalance.c: myctrl.redist_factor = ctrl->redist_base;
+initbalance.c: myctrl.tpwgts = ctrl->tpwgts;
+initbalance.c: icopy(ncon, ctrl->tvwgts, myctrl.tvwgts);
+initbalance.c: icopy(ncon, ctrl->ubvec, myctrl.ubvec);
+initbalance.c: moptions[7] = ctrl->sync + (mype % ngroups) + 1;
+initbalance.c: lnparts = ctrl->nparts;
+initbalance.c: lpecost.rank = ctrl->mype;
+initbalance.c: if (ctrl->mype == gpecost.rank && ctrl->mype != sr_pe) {
+initbalance.c: MPI_Send((void *)part, nvtxs, IDX_DATATYPE, sr_pe, 1, ctrl->comm);
+initbalance.c: if (ctrl->mype != gpecost.rank && ctrl->mype == sr_pe) {
+initbalance.c: MPI_Recv((void *)part, nvtxs, IDX_DATATYPE, gpecost.rank, 1, ctrl->comm, &status);
+initbalance.c: if (ctrl->mype == sr_pe) {
+initbalance.c: SerialRemap(&cgraph, ctrl->nparts, home, lwhere, part, ctrl->tpwgts);
+initbalance.c: lpecost.rank = ctrl->mype;
+initbalance.c: if (ctrl->mype == gpecost.rank && ctrl->mype != gd_pe)
+initbalance.c: MPI_Send((void *)part, nvtxs, IDX_DATATYPE, gd_pe, 1, ctrl->comm);
+initbalance.c: if (ctrl->mype != gpecost.rank && ctrl->mype == gd_pe)
+initbalance.c: MPI_Recv((void *)part, nvtxs, IDX_DATATYPE, gpecost.rank, 1, ctrl->comm, &status);
+initbalance.c: if (ctrl->mype == gd_pe) {
+initbalance.c: SerialRemap(&cgraph, ctrl->nparts, home, lwhere, part, ctrl->tpwgts);
+initbalance.c: if (ctrl->mype == sr_pe || ctrl->mype == gd_pe) {
+initbalance.c: my_cost = ctrl->ipc_factor * my_cut + REDIST_WGT * ctrl->redist_base * my_totalv;
+initbalance.c: IFSET(ctrl->dbglvl, DBG_REFINEINFO, printf("%s initial cut: %.1f, totalv: %.1f, balance: %.3f\n",
+initbalance.c: (ctrl->mype == sr_pe ? "scratch-remap" : "diffusion"), my_cut, my_totalv, my_balance));
+initbalance.c: if (ctrl->mype == gd_pe) {
+initbalance.c: MPI_Send((void *)buffer, 2, MPI_FLOAT, sr_pe, 1, ctrl->comm);
+initbalance.c: MPI_Recv((void *)buffer, 2, MPI_FLOAT, gd_pe, 1, ctrl->comm, &status);
+initbalance.c: if (ctrl->mype == sr_pe) {
+initbalance.c: MPI_Bcast((void *)&who_wins, 1, MPI_INT, sr_pe, ctrl->comm);
+initbalance.c: MPI_Bcast((void *)part, nvtxs, IDX_DATATYPE, who_wins, ctrl->comm);
+initbalance.c: idxcopy(graph->nvtxs, part+vtxdist[ctrl->mype], graph->where);
+initbalance.c: IFSET(ctrl->dbglvl, DBG_TIME, stoptim \ No newline at end of file
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/timer.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/timer.c
new file mode 100644
index 0000000..73cc11a
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/timer.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * timer.c
+ *
+ * This file contain various timing routines
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: timer.c,v 1.2 2003/07/21 17:18:54 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+
+/*************************************************************************
+* This function initializes the various timers
+**************************************************************************/
+void InitTimers(CtrlType *ctrl)
+{
+ cleartimer(ctrl->TotalTmr);
+ cleartimer(ctrl->InitPartTmr);
+ cleartimer(ctrl->MatchTmr);
+ cleartimer(ctrl->ContractTmr);
+ cleartimer(ctrl->CoarsenTmr);
+ cleartimer(ctrl->RefTmr);
+ cleartimer(ctrl->SetupTmr);
+ cleartimer(ctrl->ProjectTmr);
+ cleartimer(ctrl->KWayInitTmr);
+ cleartimer(ctrl->KWayTmr);
+ cleartimer(ctrl->MoveTmr);
+ cleartimer(ctrl->RemapTmr);
+
+ cleartimer(ctrl->AuxTmr1);
+ cleartimer(ctrl->AuxTmr2);
+ cleartimer(ctrl->AuxTmr3);
+ cleartimer(ctrl->AuxTmr4);
+ cleartimer(ctrl->AuxTmr5);
+ cleartimer(ctrl->AuxTmr6);
+}
+
+
+/*************************************************************************
+* This function prints timing information about KMETIS
+**************************************************************************/
+void PrintTimingInfo(CtrlType *ctrl)
+{
+/* PrintTimer(ctrl, ctrl->CoarsenTmr, " Coarsening"); */
+ PrintTimer(ctrl, ctrl->SetupTmr, " Setup");
+ PrintTimer(ctrl, ctrl->MatchTmr, " Matching");
+ PrintTimer(ctrl, ctrl->ContractTmr, "Contraction");
+ PrintTimer(ctrl, ctrl->InitPartTmr, " InitPart");
+/* PrintTimer(ctrl, ctrl->RefTmr, " Refinement"); */
+ PrintTimer(ctrl, ctrl->ProjectTmr, " Project");
+ PrintTimer(ctrl, ctrl->KWayInitTmr, " Initialize");
+ PrintTimer(ctrl, ctrl->KWayTmr, " K-way");
+ PrintTimer(ctrl, ctrl->MoveTmr, " Move");
+ PrintTimer(ctrl, ctrl->RemapTmr, " Remap");
+ PrintTimer(ctrl, ctrl->TotalTmr, " Total");
+ PrintTimer(ctrl, ctrl->AuxTmr1, " Aux1");
+ PrintTimer(ctrl, ctrl->AuxTmr2, " Aux2");
+ PrintTimer(ctrl, ctrl->AuxTmr3, " Aux3");
+ PrintTimer(ctrl, ctrl->AuxTmr4, " Aux4");
+ PrintTimer(ctrl, ctrl->AuxTmr5, " Aux5");
+ PrintTimer(ctrl, ctrl->AuxTmr6, " Aux6");
+}
+
+
+/*************************************************************************
+* This function prints timer stat
+**************************************************************************/
+void PrintTimer(CtrlType *ctrl, timer tmr, char *msg)
+{
+ double sum, max, tsec;
+
+ tsec = gettimer(tmr);
+ MPI_Reduce((void *)&tsec, (void *)&sum, 1, MPI_DOUBLE, MPI_SUM, 0, ctrl->comm);
+
+ tsec = gettimer(tmr);
+ MPI_Reduce((void *)&tsec, (void *)&max, 1, MPI_DOUBLE, MPI_MAX, 0, ctrl->comm);
+
+ if (ctrl->mype == 0 && sum != 0.0)
+ printf("%s: Max: %7.3f, Sum: %7.3f, Balance: %7.3f\n",
+ msg, (float)max, (float)sum, (float)(max*ctrl->npes/sum));
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/util.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/util.c
new file mode 100644
index 0000000..34c657d
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/util.c
@@ -0,0 +1,983 @@
+/*
+ * 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 17:18:54 karypis Exp $
+ */
+
+#include <parmetislib.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();
+}
+
+
+/*************************************************************************
+* This function prints an error message and exits
+**************************************************************************/
+void myprintf(CtrlType *ctrl, 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, "[%2d] %s", ctrl->mype, out1);
+
+ fprintf(stdout, out2);
+ fflush(stdout);
+
+}
+
+
+
+/*************************************************************************
+* This function prints an error message and exits
+**************************************************************************/
+void rprintf(CtrlType *ctrl, char *f_str,...)
+{
+ va_list argp;
+
+ if (ctrl->mype == 0) {
+ va_start(argp, f_str);
+ vfprintf(stdout, f_str, argp);
+ va_end(argp);
+ }
+
+ fflush(stdout);
+
+ MPI_Barrier(ctrl->comm);
+
+}
+
+
+#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 ((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 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 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;
+}
+
+
+/*************************************************************************
+* 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 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 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, float *y)
+{
+ int i;
+
+ for (i=0; i<n; i++)
+ y[i] += alpha*x[i];
+}
+
+
+
+
+
+
+/*************************************************************************
+* This function sorts an array of type KeyValueType in increasing order
+**************************************************************************/
+void ikeyvalsort_org(int n, KeyValueType *nodes)
+{
+ qsort((void *)nodes, (size_t)n, (size_t)sizeof(KeyValueType), IncKeyValueCmp);
+}
+
+
+/*************************************************************************
+* This function compares 2 KeyValueType variables for sorting in inc order
+**************************************************************************/
+int IncKeyValueCmp(const void *v1, const void *v2)
+{
+ KeyValueType *n1, *n2;
+
+ n1 = (KeyValueType *)v1;
+ n2 = (KeyValueType *)v2;
+
+ return (n1->key != n2->key ? n1->key - n2->key : n1->val - n2->val);
+}
+
+
+
+/*************************************************************************
+* This function sorts an array of type KeyValueType in increasing order
+**************************************************************************/
+void dkeyvalsort(int n, KeyValueType *nodes)
+{
+ qsort((void *)nodes, (size_t)n, (size_t)sizeof(KeyValueType), DecKeyValueCmp);
+}
+
+
+/*************************************************************************
+* This function compares 2 KeyValueType variables for sorting in inc order
+**************************************************************************/
+int DecKeyValueCmp(const void *v1, const void *v2)
+{
+ KeyValueType *n1, *n2;
+
+ n1 = (KeyValueType *)v1;
+ n2 = (KeyValueType *)v2;
+
+ return n2->key - n1->key;
+
+}
+
+
+
+/*************************************************************************
+* This function does a binary search on an array for a key and returns
+* the index
+**************************************************************************/
+int BSearch(int n, idxtype *array, int key)
+{
+ int a=0, b=n, c;
+
+ while (b-a > 8) {
+ c = (a+b)>>1;
+ if (array[c] > key)
+ b = c;
+ else
+ a = c;
+ }
+
+ for (c=a; c<b; c++) {
+ if (array[c] == key)
+ return c;
+ }
+
+ errexit("Key %d not found!\n", key);
+
+ return 0;
+}
+
+
+
+/*************************************************************************
+* 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;
+ }
+
+ for (i=0; i<n; i++) {
+ v = RandomInRange(n);
+ u = RandomInRange(n);
+ SWAP(p[v], p[u], tmp);
+ }
+}
+
+
+/*************************************************************************
+* This file randomly permutes the contents of an array.
+* flag == 0, don't initialize perm
+* flag == 1, set p[i] = i
+**************************************************************************/
+void FastRandomPermute(int n, idxtype *p, int flag)
+{
+ int i, u, v;
+ idxtype tmp;
+
+ /* this is for very small arrays */
+ if (n < 25) {
+ RandomPermute(n, p, flag);
+ return;
+ }
+
+ if (flag == 1) {
+ for (i=0; i<n; i++)
+ p[i] = i;
+ }
+
+ for (i=0; i<n; i+=8) {
+ v = RandomInRange(n-4);
+ u = 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 returns the log2(x)
+**************************************************************************/
+int log2Int(int a)
+{
+ int i;
+
+ for (i=1; a > 1; i++, a = a>>1);
+ return i-1;
+}
+
+
+/*************************************************************************
+* 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 samax_strd(int n, float *x, int incx)
+{
+ int i;
+ int 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 sfamax(int n, float *x)
+{
+ int i;
+ int max=0;
+
+ for (i=1; i<n; i++)
+ max = (fabs(x[i]) > fabs(x[max]) ? i : max);
+
+ return max;
+}
+
+
+
+/*************************************************************************
+* These functions return the index of the maximum element in a vector
+**************************************************************************/
+int samin_strd(int n, float *x, int incx)
+{
+ int i;
+ int min=0;
+
+ n *= incx;
+ for (i=incx; i<n; i+=incx)
+ min = (x[i] < x[min] ? i : min);
+
+ return min/incx;
+}
+
+
+/*************************************************************************
+* 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 idxamin_strd(int n, idxtype *x, int incx)
+{
+ int i, min=0;
+
+ n *= incx;
+ for (i=incx; i<n; i+=incx)
+ min = (x[i] < x[min] ? i : min);
+
+ return min/incx;
+}
+
+
+/*************************************************************************
+* This function returns the average value of an array
+**************************************************************************/
+float idxavg(int n, idxtype *x)
+{
+ int i;
+ float retval = 0.0;
+
+ for (i=0; i<n; i++)
+ retval += (float)(x[i]);
+
+ return retval / (float)(n);
+}
+
+
+/*************************************************************************
+* This function returns the average value of an array
+**************************************************************************/
+float savg(int n, float *x)
+{
+ int i;
+ float retval = 0.0;
+
+ for (i=0; i<n; i++)
+ retval += x[i];
+
+ return retval / (float)(n);
+}
+
+
+/*************************************************************************
+* 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 maximum element in a vector
+**************************************************************************/
+int sfavg(int n, float *x)
+{
+ int i;
+ float total = 0.0;
+
+ if (n == 0)
+ return 0.0;
+
+ for (i=0; i<n; i++)
+ total += fabs(x[i]);
+
+ return total / (float) n;
+}
+
+
+/*************************************************************************
+* 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 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_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
+**************************************************************************/
+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 negates the entries in an array
+**************************************************************************/
+void saneg(int n, float *x)
+{
+ int i;
+
+ for (i=0; i<n; i++)
+ x[i] = -1.0*x[i];
+}
+
+
+
+/*************************************************************************
+* This function checks if v+u2 provides a better balance in the weight
+* vector that v+u1
+**************************************************************************/
+float BetterVBalance(int ncon, float *vwgt, float *u1wgt, float *u2wgt)
+{
+ int i;
+ float sum1, sum2, diff1, diff2;
+
+ if (ncon == 1)
+ return u1wgt[0] - u1wgt[0];
+
+ 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;
+
+}
+
+
+/*************************************************************************
+* 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, float *pfrom, float *pto, float *nvwgt, float *ubvec)
+{
+ int i;
+ 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])/ubvec[i];
+ if (blb1 < temp) {
+ blb2 = blb1;
+ blb1 = temp;
+ }
+ else if (blb2 < temp)
+ blb2 = temp;
+ sblb += temp;
+
+ temp = amax(pfrom[i]-nvwgt[i], pto[i]+nvwgt[i])/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, float *pt1, float *pt2, float *nvwgt, 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]+nvwgt[i])/ubvec[i];
+ if (m11 < temp) {
+ m12 = m11;
+ m11 = temp;
+ }
+ else if (m12 < temp)
+ m12 = temp;
+ sm1 += temp;
+ temp = (pt2[i]+nvwgt[i])/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;
+}
+
+/*************************************************************************
+* This is a comparison function
+**************************************************************************/
+int myvalkeycompare(const void *fptr, const void *sptr)
+{
+ KVType *first, *second;
+
+ first = (KVType *)(fptr);
+ second = (KVType *)(sptr);
+
+ if (first->val > second->val)
+ return 1;
+
+ if (first->val < second->val)
+ return -1;
+
+ return 0;
+}
+
+/*************************************************************************
+* This is the inverse comparison function
+**************************************************************************/
+int imyvalkeycompare(const void *fptr, const void *sptr)
+{
+ KVType *first, *second;
+
+ first = (KVType *)(fptr);
+ second = (KVType *)(sptr);
+
+ if (first->val > second->val)
+ return -1;
+
+ if (first->val < second->val)
+ return 1;
+
+ return 0;
+}
+
+
+/*************************************************************************
+* The following function allocates and sets an array of floats
+**************************************************************************/
+float *fsmalloc(int n, float fval, char *msg)
+{
+ if (n == 0)
+ return NULL;
+
+ return sset(n, fval, (float *)GKmalloc(sizeof(float)*n, msg));
+}
+
+
+/*************************************************************************
+* This function computes a 2-norm
+**************************************************************************/
+void saxpy2(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 function computes the top three values of a float array
+**************************************************************************/
+void GetThreeMax(int n, float *x, int *first, int *second, int *third)
+{
+ int i;
+
+ if (n <= 0) {
+ *first = *second = *third = -1;
+ return;
+ }
+
+ *second = *third = -1;
+ *first = 0;
+
+ for (i=1; i<n; i++) {
+ if (x[i] > x[*first]) {
+ *third = *second;
+ *second = *first;
+ *first = i;
+ continue;
+ }
+
+ if (*second == -1 || x[i] > x[*second]) {
+ *third = *second;
+ *second = i;
+ continue;
+ }
+
+ if (*third == -1 || x[i] > x[*third])
+ *third = i;
+ }
+
+ return;
+}
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/wave.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/wave.c
new file mode 100644
index 0000000..0f1cb3f
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/wave.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * wave.c
+ *
+ * This file contains code for directed diffusion at the coarsest graph
+ *
+ * Started 5/19/97, Kirk, George
+ *
+ * $Id: wave.c,v 1.3 2003/07/22 21:47:18 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+/*************************************************************************
+* This function performs a k-way directed diffusion
+**************************************************************************/
+float WavefrontDiffusion(CtrlType *ctrl, GraphType *graph, idxtype *home)
+{
+ int ii, i, j, k, l, nvtxs, nedges, nparts;
+ int from, to, edge, done, nswaps, noswaps, totalv, wsize;
+ int npasses, first, second, third, mind, maxd;
+ idxtype *xadj, *adjncy, *adjwgt, *where, *perm;
+ idxtype *rowptr, *colind, *ed, *psize;
+ float *transfer, *tmpvec;
+ float balance = -1.0, *load, *solution, *workspace;
+ float *nvwgt, *npwgts, flowFactor, cost, ubfactor;
+ MatrixType matrix;
+ KeyValueType *cand;
+ int ndirty, nclean, dptr, clean;
+
+ nvtxs = graph->nvtxs;
+ nedges = graph->nedges;
+ xadj = graph->xadj;
+ nvwgt = graph->nvwgt;
+ adjncy = graph->adjncy;
+ adjwgt = graph->adjwgt;
+ where = graph->where;
+ nparts = ctrl->nparts;
+ ubfactor = ctrl->ubvec[0];
+ matrix.nrows = nparts;
+
+ flowFactor = 0.35;
+ flowFactor = (ctrl->mype == 2) ? 0.50 : flowFactor;
+ flowFactor = (ctrl->mype == 3) ? 0.75 : flowFactor;
+ flowFactor = (ctrl->mype == 4) ? 1.00 : flowFactor;
+
+ /* allocate memory */
+ solution = fmalloc(4*nparts+2*nedges, "WavefrontDiffusion: solution");
+ tmpvec = solution + nparts;
+ npwgts = solution + 2*nparts;
+ load = solution + 3*nparts;
+ matrix.values = solution + 4*nparts;
+ transfer = matrix.transfer = solution + 4*nparts + nedges;
+
+ perm = idxmalloc(2*nvtxs+2*nparts+nedges+1, "WavefrontDiffusion: perm");
+ ed = perm + nvtxs;
+ psize = perm + 2*nvtxs;
+ rowptr = matrix.rowptr = perm + 2*nvtxs + nparts;
+ colind = matrix.colind = perm + 2*nvtxs + 2*nparts + 1;
+
+ wsize = amax(sizeof(float)*nparts*6, sizeof(idxtype)*(nvtxs+nparts*2+1));
+ workspace = (float *)GKmalloc(wsize, "WavefrontDiffusion: workspace");
+ cand = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "WavefrontDiffusion: cand");
+
+
+ /*****************************/
+ /* Populate empty subdomains */
+ /*****************************/
+ idxset(nparts, 0, psize);
+ for (i=0; i<nvtxs; i++)
+ psize[where[i]]++;
+
+ mind = idxamin(nparts, psize);
+ maxd = idxamax(nparts, psize);
+ if (psize[mind] == 0) {
+ for (i=0; i<nvtxs; i++) {
+ k = (RandomInRange(nvtxs)+i)%nvtxs;
+ if (where[k] == maxd) {
+ where[k] = mind;
+ psize[mind]++;
+ psize[maxd]--;
+ break;
+ }
+ }
+ }
+ idxset(nvtxs, 0, ed);
+ sset(nparts, 0.0, npwgts);
+ for (i=0; i<nvtxs; i++) {
+ npwgts[where[i]] += nvwgt[i];
+ for (j=xadj[i]; j<xadj[i+1]; j++)
+ ed[i] += (where[i] != where[adjncy[j]] ? adjwgt[j] : 0);
+ }
+
+ ComputeLoad(graph, nparts, load, ctrl->tpwgts, 0);
+ done = 0;
+
+ npasses = amin(nparts/2, NGD_PASSES);
+ for (l=0; l<npasses; l++) {
+ /* Set-up and solve the diffusion equation */
+ nswaps = 0;
+
+ /************************/
+ /* Solve flow equations */
+ /************************/
+ SetUpConnectGraph(graph, &matrix, (idxtype *)workspace);
+
+ /* check for disconnected subdomains */
+ for(i=0; i<matrix.nrows; i++) {
+ if (matrix.rowptr[i]+1 == matrix.rowptr[i+1]) {
+ cost = (float)(ctrl->mype);
+ goto CleanUpAndExit;
+ }
+ }
+
+ ConjGrad2(&matrix, load, solution, 0.001, workspace);
+ ComputeTransferVector(1, &matrix, solution, transfer, 0);
+
+ GetThreeMax(nparts, load, &first, &second, &third);
+
+ if (l%3 == 0) {
+ FastRandomPermute(nvtxs, perm, 1);
+ }
+ else {
+ /*****************************/
+ /* move dirty vertices first */
+ /*****************************/
+ ndirty = 0;
+ for (i=0; i<nvtxs; i++)
+ if (where[i] != home[i])
+ ndirty++;
+
+ dptr = 0;
+ for (i=0; i<nvtxs; i++)
+ if (where[i] != home[i])
+ perm[dptr++] = i;
+ else
+ perm[ndirty++] = i;
+
+ ASSERT(ctrl, ndirty == nvtxs);
+ ndirty = dptr;
+ nclean = nvtxs-dptr;
+ FastRandomPermute(ndirty, perm, 0);
+ FastRandomPermute(nclean, perm+ndirty, 0);
+ }
+
+ if (ctrl->mype == 0) {
+ for (j=nvtxs, k=0, ii=0; ii<nvtxs; ii++) {
+ i = perm[ii];
+ if (ed[i] != 0) {
+ cand[k].key = -ed[i];
+ cand[k++].val = i;
+ }
+ else {
+ cand[--j].key = 0;
+ cand[j].val = i;
+ }
+ }
+ ikeysort(k, cand);
+ }
+
+ for (ii=0; ii<nvtxs/3; ii++) {
+ i = (ctrl->mype == 0) ? cand[ii].val : perm[ii];
+ from = where[i];
+
+ /* don't move out the last vertex in a subdomain */
+ if (psize[from] == 1)
+ continue;
+
+ clean = (from == home[i]) ? 1 : 0;
+
+ /* only move from top three or dirty vertices */
+ if (from != first && from != second && from != third && clean)
+ continue;
+
+ /* Scatter the sparse transfer row into the dense tmpvec row */
+ for (j=rowptr[from]+1; j<rowptr[from+1]; j++)
+ tmpvec[colind[j]] = transfer[j];
+
+ for (j=xadj[i]; j<xadj[i+1]; j++) {
+ to = where[adjncy[j]];
+ if (from != to) {
+ if (tmpvec[to] > (flowFactor * nvwgt[i])) {
+ tmpvec[to] -= nvwgt[i];
+ INC_DEC(psize[to], psize[from], 1);
+ INC_DEC(npwgts[to], npwgts[from], nvwgt[i]);
+ INC_DEC(load[to], load[from], nvwgt[i]);
+ where[i] = to;
+ nswaps++;
+
+ /* Update external degrees */
+ ed[i] = 0;
+ for (k=xadj[i]; k<xadj[i+1]; k++) {
+ edge = adjncy[k];
+ ed[i] += (to != where[edge] ? adjwgt[k] : 0);
+
+ if (where[edge] == from)
+ ed[edge] += adjwgt[k];
+ if (where[edge] == to)
+ ed[edge] -= adjwgt[k];
+ }
+ break;
+ }
+ }
+ }
+
+ /* Gather the dense tmpvec row into the sparse transfer row */
+ for (j=rowptr[from]+1; j<rowptr[from+1]; j++) {
+ transfer[j] = tmpvec[colind[j]];
+ tmpvec[colind[j]] = 0.0;
+ }
+ ASSERTS(fabs(ssum(nparts, tmpvec)) < .0001)
+ }
+
+ if (l % 2 == 1) {
+ balance = npwgts[samax(nparts, npwgts)] * (float)nparts;
+ if (balance < ubfactor + 0.035)
+ done = 1;
+
+ if (GlobalSESum(ctrl, done) > 0)
+ break;
+
+ noswaps = (nswaps > 0) ? 0 : 1;
+ if (GlobalSESum(ctrl, noswaps) > ctrl->npes/2)
+ break;
+
+ }
+ }
+
+ graph->mincut = ComputeSerialEdgeCut(graph);
+ totalv = Mc_ComputeSerialTotalV(graph, home);
+ cost = ctrl->ipc_factor * (float)graph->mincut + ctrl->redist_factor * (float)totalv;
+
+
+CleanUpAndExit:
+ GKfree((void **)&solution, (void **)&perm, (void **)&workspace, (void **)&cand, LTERM);
+
+ return cost;
+}
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/weird.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/weird.c
new file mode 100644
index 0000000..69d0e5d
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/weird.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * weird.c
+ *
+ * This file contain various graph setting up routines
+ *
+ * Started 10/19/96
+ * George
+ *
+ * $Id: weird.c,v 1.9 2003/07/31 16:27:28 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+
+/*************************************************************************
+* This function computes a partitioning of a small graph
+**************************************************************************/
+void PartitionSmallGraph(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace)
+{
+ int i, h, ncon, nparts, npes, mype;
+ int moptions[10];
+ int mynumflag, mywgtflag, me;
+ idxtype *mypart;
+ int lpecut[2], gpecut[2];
+ GraphType *agraph;
+ int *sendcounts, *displs;
+ float *mytpwgts, *gnpwgts, *lnpwgts;
+
+ ncon = graph->ncon;
+ nparts = ctrl->nparts;
+
+ MPI_Comm_size(ctrl->comm, &npes);
+ MPI_Comm_rank(ctrl->comm, &mype);
+
+ SetUp(ctrl, graph, wspace);
+ graph->where = idxmalloc(graph->nvtxs+graph->nrecv, "PartitionSmallGraph: where");
+ agraph = Moc_AssembleAdaptiveGraph(ctrl, graph, wspace);
+ mypart = idxmalloc(agraph->nvtxs, "mypart");
+
+ moptions[0] = 0;
+ moptions[7] = ctrl->sync + mype;
+ mynumflag = 0;
+ mywgtflag = 3;
+ if (ncon == 1) {
+ METIS_WPartGraphKway2(&agraph->nvtxs, agraph->xadj, agraph->adjncy, agraph->vwgt,
+ agraph->adjwgt, &mywgtflag, &mynumflag, &nparts, ctrl->tpwgts, moptions,
+ &graph->mincut, mypart);
+ }
+ else {
+ mytpwgts = fmalloc(nparts, "mytpwgts");
+ for (i=0; i<nparts; i++)
+ mytpwgts[i] = ctrl->tpwgts[i*ncon];
+
+ METIS_mCPartGraphRecursive2(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy,
+ agraph->vwgt, agraph->adjwgt, &mywgtflag, &mynumflag, &nparts, mytpwgts,
+ moptions, &graph->mincut, mypart);
+
+ free(mytpwgts);
+ }
+
+ lpecut[0] = graph->mincut;
+ lpecut[1] = mype;
+ MPI_Allreduce(lpecut, gpecut, 1, MPI_2INT, MPI_MINLOC, ctrl->comm);
+ graph->mincut = gpecut[0];
+
+ if (lpecut[1] == gpecut[1] && gpecut[1] != 0)
+ MPI_Send((void *)mypart, agraph->nvtxs, IDX_DATATYPE, 0, 1, ctrl->comm);
+ if (lpecut[1] == 0 && gpecut[1] != 0)
+ MPI_Recv((void *)mypart, agraph->nvtxs, IDX_DATATYPE, gpecut[1], 1, ctrl->comm, &ctrl->status);
+
+ sendcounts = imalloc(npes, "sendcounts");
+ displs = imalloc(npes, "displs");
+
+ for (i=0; i<npes; i++) {
+ sendcounts[i] = graph->vtxdist[i+1]-graph->vtxdist[i];
+ displs[i] = graph->vtxdist[i];
+ }
+
+ MPI_Scatterv((void *)mypart, sendcounts, displs, IDX_DATATYPE,
+ (void *)graph->where, graph->nvtxs, IDX_DATATYPE, 0, ctrl->comm);
+
+ lnpwgts = graph->lnpwgts = fmalloc(nparts*ncon, "lnpwgts");
+ gnpwgts = graph->gnpwgts = fmalloc(nparts*ncon, "gnpwgts");
+ sset(nparts*ncon, 0, lnpwgts);
+ for (i=0; i<graph->nvtxs; i++) {
+ me = graph->where[i];
+ for (h=0; h<ncon; h++)
+ lnpwgts[me*ncon+h] += graph->nvwgt[i*ncon+h];
+ }
+ MPI_Allreduce((void *)lnpwgts, (void *)gnpwgts, nparts*ncon, MPI_FLOAT, MPI_SUM, ctrl->comm);
+ GKfree((void**)&mypart, (void**)&sendcounts, (void**)&displs, LTERM);
+ FreeGraph(agraph);
+
+ return;
+}
+
+
+
+/*************************************************************************
+* This function checks the inputs for the partitioning routines
+**************************************************************************/
+void CheckInputs(int partType, int npes, int dbglvl, int *wgtflag, int *iwgtflag,
+ int *numflag, int *inumflag, int *ncon, int *incon, int *nparts,
+ int *inparts, float *tpwgts, float **itpwgts, float *ubvec,
+ float *iubvec, float *ipc2redist, float *iipc2redist, int *options,
+ int *ioptions, idxtype *part, MPI_Comm *comm)
+{
+ int i, j;
+ int doweabort, doiabort = 0;
+ float tsum, *myitpwgts;
+ int mgcnums[5] = {-1, 2, 3, 4, 2};
+
+ /**************************************/
+ if (part == NULL) {
+ doiabort = 1;
+ IFSET(dbglvl, DBG_INFO, printf("ERROR: part array is set to NULL.\n"));
+ }
+ /**************************************/
+
+
+ /**************************************/
+ if (wgtflag == NULL) {
+ *iwgtflag = 0;
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: wgtflag is NULL. Using a value of 0.\n"));
+ }
+ else {
+ *iwgtflag = *wgtflag;
+ }
+ /**************************************/
+
+
+ /**************************************/
+ if (numflag == NULL) {
+ *inumflag = 0;
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: numflag is NULL. Using a value of 0.\n"));
+ }
+ else {
+ if (*numflag != 0 && *numflag != 1) {
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: bad value for numflag %d. Using a value of 0.\n", *numflag));
+ *inumflag = 0;
+ }
+ else {
+ *inumflag = *numflag;
+ }
+ }
+ /**************************************/
+
+
+ /**************************************/
+ if (ncon == NULL) {
+ *incon = 1;
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: ncon is NULL. Using a value of 1.\n"));
+ }
+ else {
+ if (*ncon < 1 || *ncon > MAXNCON) {
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: bad value for ncon %d. Using a value of 1.\n", *ncon));
+ *incon = 1;
+ }
+ else {
+ *incon = *ncon;
+ }
+ }
+ /**************************************/
+
+
+ /**************************************/
+ if (nparts == NULL) {
+ *inparts = npes;
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: nparts is NULL. Using a value of %d.\n", npes));
+ }
+ else {
+ if (*nparts < 1 || *nparts > MAX_NPARTS) {
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: bad value for nparts %d. Using a value of %d.\n", *nparts, npes));
+ *inparts = npes;
+ }
+ else {
+ *inparts = *nparts;
+ }
+ }
+ /**************************************/
+
+
+ /**************************************/
+ myitpwgts = *itpwgts = fmalloc((*inparts)*(*incon), "CheckInputs: itpwgts");
+ if (tpwgts == NULL) {
+ sset((*inparts)*(*incon), 1.0/(float)(*inparts), myitpwgts);
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: tpwgts is NULL. Setting all array elements to %.3f.\n", 1.0/(float)(*inparts)));
+ }
+ else {
+ for (i=0; i<*incon; i++) {
+ tsum = 0.0;
+ for (j=0; j<*inparts; j++) {
+ tsum += tpwgts[j*(*incon)+i];
+ }
+ if (fabs(1.0-tsum) < SMALLFLOAT)
+ tsum = 1.0;
+ for (j=0; j<*inparts; j++)
+ myitpwgts[j*(*incon)+i] = tpwgts[j*(*incon)+i] / tsum;
+ }
+ }
+ /**************************************/
+
+
+ /**************************************/
+ if (ubvec == NULL) {
+ sset(*incon, 1.05, iubvec);
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: ubvec is NULL. Setting all array elements to 1.05.\n"));
+ }
+ else {
+ for (i=0; i<*incon; i++) {
+ if (ubvec[i] < 1.0 || ubvec[i] > (float)(*inparts)) {
+ iubvec[i] = 1.05;
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: bad value for ubvec[%d]: %.3f. Setting value to 1.05.[%d]\n", i, ubvec[i], *inparts));
+ }
+ else {
+ iubvec[i] = ubvec[i];
+ }
+ }
+ }
+ /**************************************/
+
+
+ /**************************************/
+ if (partType == ADAPTIVE_PARTITION) {
+ if (ipc2redist != NULL) {
+ if (*ipc2redist < SMALLFLOAT || *ipc2redist > 1000000.0) {
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: bad value for ipc2redist %.3f. Using a value of 1000.\n", *ipc2redist));
+ *iipc2redist = 1000.0;
+ }
+ else {
+ *iipc2redist = *ipc2redist;
+ }
+ }
+ else {
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: ipc2redist is NULL. Using a value of 1000.\n"));
+ *iipc2redist = 1000.0;
+ }
+ }
+ /**************************************/
+
+
+ /**************************************/
+ if (options == NULL) {
+ ioptions[0] = 0;
+ IFSET(dbglvl, DBG_INFO, printf("WARNING: options is NULL. Using defaults\n"));
+ }
+ else {
+ ioptions[0] = options[0];
+ ioptions[1] = options[1];
+ ioptions[2] = options[2];
+ if (partType == ADAPTIVE_PARTITION || partType == REFINE_PARTITION)
+ ioptions[3] = options[3];
+ }
+ /**************************************/
+
+
+ /**************************************/
+ if (comm == NULL) {
+ IFSET(dbglvl, DBG_INFO, printf("ERROR: comm is NULL. Aborting\n"));
+ abort();
+ }
+ else {
+ MPI_Allreduce((void *)&doiabort, (void *)&doweabort, 1, MPI_INT, MPI_MAX, *comm);
+ if (doweabort > 0)
+ abort();
+ }
+ /**************************************/
+
+}
+
+
diff --git a/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/xyzpart.c b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/xyzpart.c
new file mode 100644
index 0000000..e538034
--- /dev/null
+++ b/benchmarks/CUDA/DG/3rdParty/ParMetis-3.1/ParMETISLib/xyzpart.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright 1997, Regents of the University of Minnesota
+ *
+ * xyzpart.c
+ *
+ * This file contains code that implements a coordinate based partitioning
+ *
+ * Started 7/11/97
+ * George
+ *
+ * $Id: xyzpart.c,v 1.3 2003/07/30 18:37:59 karypis Exp $
+ *
+ */
+
+#include <parmetislib.h>
+
+
+/*************************************************************************
+* This function implements a simple coordinate based partitioning
+**************************************************************************/
+void Coordinate_Partition(CtrlType *ctrl, GraphType *graph, int ndims, float *xyz,
+ int setup, WorkSpaceType *wspace)
+{
+ int i, j, k, nvtxs, firstvtx, icoord, coords[3];
+ idxtype *vtxdist;
+ float max[3], min[3], gmin[3], gmax[3], shift[3], scale[3];
+ KeyValueType *cand;
+
+ if (setup)
+ SetUp(ctrl, graph, wspace);
+ else
+ graph->nrecv = 0;
+
+ nvtxs = graph->nvtxs;
+ vtxdist = graph->vtxdist;
+
+ firstvtx = vtxdist[ctrl->mype];
+
+ cand = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "Coordinate_Partition: cand");
+
+ /* Compute parameters for coordinate transformation */
+ for (k=0; k<ndims; k++) {
+ min[k] = +10000000;
+ max[k] = -10000000;
+ }
+ for (i=0; i<nvtxs; i++) {
+ for (k=0; k<ndims; k++) {
+ if (xyz[i*ndims+k] < min[k])
+ min[k] = xyz[i*ndims+k];
+ if (xyz[i*ndims+k] > max[k])
+ max[k] = xyz[i*ndims+k];
+ }
+ }
+
+ /* Compute global min and max */
+ MPI_Allreduce((void *)min, (void *)gmin, ndims, MPI_FLOAT, MPI_MIN, ctrl->comm);
+ MPI_Allreduce((void *)max, (void *)gmax, ndims, MPI_FLOAT, MPI_MAX, ctrl->comm);
+
+ /* myprintf(ctrl, "Coordinate Range: %e %e, Global %e %e\n", min[0], max[0], gmin[0], gmax[0]); */
+
+ for (k=0; k<ndims; k++) {
+ /* rprintf(ctrl, "Dim#%d: %e %e, span: %e\n", k, gmin[k], gmax[k], gmax[k]-gmin[k]); */
+ shift[k] = -gmin[k];
+ if (gmax[k] != gmin[k])
+ scale[k] = 1.0/(gmax[k]-gmin[k]);
+ else
+ scale[k] = 1.0;
+ }
+
+ switch (ctrl->xyztype) {
+ case XYZ_XCOORD:
+ for (i=0; i<nvtxs; i++) {
+ cand[i].key = 1000000*((xyz[i*ndims]+shift[0])*scale[0]);
+ ASSERT(ctrl, cand[i].key>=0 && cand[i].key<=1000000);
+ cand[i].val = firstvtx+i;
+ }
+ break;
+ case XYZ_SPFILL:
+ for (i=0; i<nvtxs; i++) {
+ for (k=0; k<ndims; k++)
+ coords[k] = 1024*((xyz[i*ndims+k]+shift[k])*scale[k]);
+ for (icoord=0, j=9; j>=0; j--) {
+ for (k=0; k<ndims; k++)
+ icoord = (icoord<<1) + (coords[k]&(1<<j) ? 1 : 0);
+ }
+ cand[i].key = icoord;
+ cand[i].val = firstvtx+i;
+ }
+ break;
+ default:
+ errexit("Unknown XYZ_Type type!\n");
+ }
+
+
+ /* Partition using sorting */
+ PartSort(ctrl, graph, cand, wspace);
+
+ free(cand);
+
+}
+
+
+
+/*************************************************************************
+* This function sorts a distributed list of KeyValueType in increasing
+* order, and uses it to compute a partition. It uses samplesort.
+**************************************************************************/
+void PartSort(CtrlType *ctrl, GraphType *graph, KeyValueType *elmnts, WorkSpaceType *wspace)
+{
+ int i, j, k, nvtxs, nrecv, npes=ctrl->npes, mype=ctrl->mype, firstvtx, lastvtx;
+ idxtype *scounts, *rcounts, *vtxdist, *perm;
+ KeyValueType *relmnts, *mypicks, *allpicks;
+
+ nvtxs = graph->nvtxs;
+ vtxdist = graph->vtxdist;
+
+ scounts = wspace->pv1;
+ rcounts = wspace->pv2;
+
+ /* Allocate memory for the splitters */
+ mypicks = (KeyValueType *)GKmalloc(sizeof(KeyValueType)*(npes+1), "ParSort: mypicks");
+ allpicks = (KeyValueType *)GKmalloc(sizeof(KeyValueType)*npes*npes, "ParSort: allpicks");
+
+ /* Sort the local elements */
+ ikeysort(nvtxs, elmnts);
+
+ /* Select the local npes-1 equally spaced elements */
+ for (i=1; i<npes; i++) {
+ mypicks[i-1].key = elmnts[i*(nvtxs/npes)].key;
+ mypicks[i-1].val = elmnts[i*(nvtxs/npes)].val;
+ }
+
+ /* PrintPairs(ctrl, npes-1, mypicks, "Mypicks"); */
+
+ /* Gather the picks to all the processors */
+ MPI_Allgather((void *)mypicks, 2*(npes-1), IDX_DATATYPE, (void *)allpicks, 2*(npes-1), IDX_DATATYPE, ctrl->comm);
+
+ /* PrintPairs(ctrl, npes*(npes-1), allpicks, "Allpicks"); */
+
+ /* Sort all the picks */
+ ikeyvalsort(npes*(npes-1), allpicks);
+
+ /* PrintPairs(ctrl, npes*(npes-1), allpicks, "Allpicks"); */
+
+ /* Select the final splitters. Set the boundaries to simplify coding */
+ for (i=1; i<npes; i++)
+ mypicks[i] = allpicks[i*(npes-1)];
+ mypicks[0].key = MIN_INT;
+ mypicks[npes].key = MAX_INT;
+
+ /* PrintPairs(ctrl, npes+1, mypicks, "Mypicks"); */
+
+ /* Compute the number of elements that belong to each bucket */
+ idxset(npes, 0, scounts);
+ for (j=i=0; i<nvtxs; i++) {
+ if (elmnts[i].key < mypicks[j+1].key || (elmnts[i].key == mypicks[j+1].key && elmnts[i].val < mypicks[j+1].val))
+ scounts[j]++;
+ else
+ scounts[++j]++;
+ }
+ MPI_Alltoall(scounts, 1, IDX_DATATYPE, rcounts, 1, IDX_DATATYPE, ctrl->comm);
+
+/*
+ PrintVector(ctrl, npes, 0, scounts, "Scounts");
+ PrintVector(ctrl, npes, 0, rcounts, "Rcounts");
+*/
+
+ /* Allocate memory for sorted elements and receive them */
+ MAKECSR(i, npes, scounts);
+ MAKECSR(i, npes, rcounts);
+ nrecv = rcounts[npes];
+ if (wspace->nlarge >= nrecv)
+ relmnts = (KeyValueType *)wspace->pairs;
+ else
+ relmnts = (KeyValueType *)GKmalloc(sizeof(KeyValueType)*nrecv, "ParSort: relmnts");
+
+ /* Issue the receives first */
+ for (i=0; i<npes; i++)
+ MPI_Irecv((void *)(relmnts+rcounts[i]), 2*(rcounts[i+1]-rcounts[i]), IDX_DATATYPE, i, 1, ctrl->comm, ctrl->rreq+i);
+
+ /* Issue the sends next */
+ for (i=0; i<npes; i++)
+ MPI_Isend((void *)(elmnts+scounts[i]), 2*(scounts[i+1]-scounts[i]), IDX_DATATYPE, i, 1, ctrl->comm, ctrl->sreq+i);
+
+ MPI_Waitall(npes, ctrl->rreq, ctrl->statuses);
+ MPI_Waitall(npes, ctrl->sreq, ctrl->statuses);
+
+
+ /* OK, now do the local sort of the relmnts. Use perm to keep track original order */
+ perm = idxmalloc(nrecv, "ParSort: perm");
+ for (i=0; i<nrecv; i++) {
+ perm[i] = relmnts[i].val;
+ relmnts[i].val = i;
+ }
+ ikeysort(nrecv, relmnts);
+
+
+ /* Compute what needs to be shifted */
+ MPI_Scan((void *)(&nrecv), (void *)(&lastvtx), 1, MPI_INT, MPI_SUM, ctrl->comm);
+ firstvtx = lastvtx-nrecv;
+
+ /*myprintf(ctrl, "first, last: %d %d\n", firstvtx, lastvtx); */
+
+ for (j=0, i=0; i<npes; i++) {
+ if (vtxdist[i+1] > firstvtx) { /* Found the first PE that is passed me */
+ if (vtxdist[i+1] >= lastvtx) {
+ /* myprintf(ctrl, "Shifting %d elements to processor %d\n", lastvtx-firstvtx, i); */
+ for (k=0; k<lastvtx-firstvtx; k++, j++)
+ relmnts[relmnts[j].val].key = i;
+ }
+ else {
+ /* myprintf(ctrl, "Shifting %d elements to processor %d\n", vtxdist[i+1]-firstvtx, i); */
+ for (k=0; k<vtxdist[i+1]-firstvtx; k++, j++)
+ relmnts[relmnts[j].val].key = i;
+
+ firstvtx = vtxdist[i+1];
+ }
+ }
+ if (vtxdist[i+1] >= lastvtx)
+ break;
+ }
+
+ /* Reverse the ordering on the relmnts[].val */
+ for (i=0; i<nrecv; i++) {
+ ASSERTP(ctrl, relmnts[i].key>=0 && relmnts[i].key<npes, (ctrl, "%d %d\n", i, relmnts[i].key));
+ relmnts[i].val = perm[i];
+ }
+
+ /* OK, now sent it back */
+ /* Issue the receives first */
+ for (i=0; i<npes; i++)
+ MPI_Irecv((void *)(elmnts+scounts[i]), 2*(scounts[i+1]-scounts[i]), IDX_DATATYPE, i, 1, ctrl->comm, ctrl->rreq+i);
+
+ /* Issue the sends next */
+ for (i=0; i<npes; i++)
+ MPI_Isend((void *)(relmnts+rcounts[i]), 2*(rcounts[i+1]-rcounts[i]), IDX_DATATYPE, i, 1, ctrl->comm, ctrl->sreq+i);
+
+ MPI_Waitall(npes, ctrl->rreq, ctrl->statuses);
+ MPI_Waitall(npes, ctrl->sreq, ctrl->statuses);
+
+
+ /* Construct a partition for the graph */
+ graph->where = idxmalloc(graph->nvtxs+graph->nrecv, "PartSort: graph->where");
+ firstvtx = vtxdist[mype];
+ for (i=0; i<nvtxs; i++) {
+ ASSERTP(ctrl, elmnts[i].key>=0 && elmnts[i].key<npes, (ctrl, "%d %d\n", i, elmnts[i].key));
+ ASSERTP(ctrl, elmnts[i].val>=vtxdist[mype] && elmnts[i].val<vtxdist[mype+1], (ctrl, "%d %d %d %d\n", i, vtxdist[mype], vtxdist[mype+1], elmnts[i].val));
+ graph->where[elmnts[i].val-firstvtx] = elmnts[i].key;
+ }
+
+
+ GKfree((void **)&mypicks, (void **)&allpicks, (void **)&perm, LTERM);
+ if (wspace->nlarge < nrecv)
+ free(relmnts);
+
+}
+