void median ( struct vtx_data **graph, /* data structure with vertex weights */ double *vals, /* values of which to find median */ int nvtxs, /* number of values I own */ int *active, /* space for list of nvtxs ints */ double *goal, /* desired sizes for sets */ int using_vwgts, /* are vertex weights being used? */ int *sets /* set each vertex gets assigned to */ ) { double *vptr; /* loops through vals array */ double val; /* value in vals array */ double maxval; /* largest active value */ double minval; /* smallest active value */ double guess; /* approximate median value */ double nearup; /* lowest guy above guess */ double neardown; /* highest guy below guess */ double whigh; /* total weight of values above maxval */ double wlow; /* total weight of values below minval */ double wabove; /* total weight of active values above guess */ double wbelow; /* total weight of active values below guess */ double wexact; /* weight of vertices exactly at guess */ double lweight; /* desired weight of lower values in set */ double uweight; /* desired weight of upper values in set */ double frac; /* fraction of values I want less than guess */ int *aptr; /* loops through active array */ int *aptr2; /* helps update active array */ int myactive; /* number of active values I own */ double wfree; /* weight of vtxs not yet divided */ int removed; /* number of my values eliminated */ /*int npass = 0;*/ /* counts passes required to find median */ int done; /* check for termination criteria */ int vtx; /* vertex being considered */ int i; /* loop counters */ /* Initialize. */ /* Determine the desired weight sums for the two different sets. */ lweight = goal[0]; uweight = goal[1]; myactive = nvtxs; whigh = wlow = 0; /* Find largest and smallest values in vector, and construct active list. */ vptr = vals; aptr = active; minval = maxval = *(++vptr); *aptr++ = 1; for (i = 2; i <= nvtxs; i++) { *aptr++ = i; val = *(++vptr); if (val > maxval) maxval = val; if (val < minval) minval = val; } /* Loop until all sets are partitioned correctly. */ done = FALSE; while (!done) { /*npass++;*/ /* Select a potential dividing value. */ /* Currently, this assumes a linear distribution. */ wfree = lweight + uweight - (wlow + whigh); frac = (lweight - wlow) / wfree; /* Overshoot a bit to try to cut into largest set. */ frac = .5 * (frac + .5); guess = minval + frac * (maxval - minval); /* Now count the guys above and below this guess. */ /* Also find nearest values on either side of guess. */ wabove = wbelow = wexact = 0; nearup = maxval; neardown = minval; aptr = active; for (i = 0; i < myactive; i++) { vtx = *aptr++; val = vals[vtx]; if (val > guess) { if (using_vwgts) wabove += graph[vtx]->vwgt; else wabove++; if (val < nearup) nearup = val; } else if (val < guess) { if (using_vwgts) wbelow += graph[vtx]->vwgt; else wbelow++; if (val > neardown) neardown = val; } else { if (using_vwgts) wexact += graph[vtx]->vwgt; else wexact++; } } /* Select a half to discard. */ /* And remove discarded vertices from active list. */ removed = 0; if (wlow + wbelow - lweight > whigh + wabove - uweight && whigh + wabove + wexact < uweight ) { /* Discard upper set. */ whigh += wabove + wexact; maxval = neardown; done = FALSE; aptr = aptr2 = active; for (i = 0; i < myactive; i++) { if (vals[*aptr] >= guess) { ++removed; } else *aptr2++ = *aptr; aptr++; } myactive -= removed; if (myactive == 0) done = TRUE; } else if ( whigh + wabove - uweight > wlow + wbelow - lweight && wlow + wbelow + wexact < lweight ) { /* Discard lower set. */ wlow += wbelow + wexact; minval = nearup; done = FALSE; aptr = aptr2 = active; for (i = 0; i < myactive; i++) { if (vals[*aptr] <= guess) { ++removed; } else *aptr2++ = *aptr; aptr++; } myactive -= removed; if (myactive == 0) done = TRUE; } else { /* Perfect partition! */ wlow += wbelow; whigh += wabove; done = TRUE; } /* Check for alternate termination criteria. */ if (!done && maxval == minval) { guess = maxval; done = TRUE; } } median_assign(graph, vals, nvtxs, goal, using_vwgts, sets, wlow, whigh, guess); }
void mapper ( struct vtx_data **graph, /* data structure with vertex weights */ double **xvecs, /* continuous indicator vectors */ int nvtxs, /* number of vtxs in graph */ int *active, /* space for nmyvals ints */ int *sets, /* returned processor assignment for my vtxs */ int ndims, /* number of dimensions being divided into */ int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int nsets, /* number of sets to divide into */ int mediantype, /* type of eigenvector partitioning to use */ double *goal, /* desired set sizes */ int vwgt_max /* largest vertex weight */ ) { double temp_goal[2]; /* combined set goals if using option 1. */ double wbelow; /* weight of vertices with negative values */ double wabove; /* weight of vertices with positive values */ int *temp_sets; /* sets vertices get assigned to */ int vweight; /* weight of a vertex */ int using_vwgts; /* are vertex weights being used? */ int bits; /* bits for assigning set numbers */ int i, j; /* loop counters */ void median(), rec_median_k(), rec_median_1(), median_assign(); void map2d(), map3d(); /* NOTE: THIS EXPECTS XVECS, NOT YVECS! */ using_vwgts = (vwgt_max != 1); if (ndims == 1 && mediantype == 1) mediantype = 3; /* simpler call than normal option 1. */ if (mediantype == 0) { /* Divide at zero instead of median. */ bits = 1; temp_sets = smalloc((nvtxs + 1) * sizeof(int)); for (j = 1; j <= nvtxs; j++) sets[j] = 0; for (i = 1; i <= ndims; i++) { temp_goal[0] = temp_goal[1] = 0; for (j = 0; j < (1 << ndims); j++) { if (bits & j) temp_goal[1] += goal[j]; else temp_goal[0] += goal[j]; } bits <<= 1; wbelow = wabove = 0; vweight = 1; for (j = 1; j <= nvtxs; j++) { if (using_vwgts) vweight = graph[j]->vwgt; if (xvecs[i][j] < 0) wbelow += vweight; else if (xvecs[i][j] > 0) wabove += vweight; } median_assign(graph, xvecs[i], nvtxs, temp_goal, using_vwgts, temp_sets, wbelow, wabove, (double) 0.0); for (j = 1; j <= nvtxs; j++) sets[j] = (sets[j] << 1) + temp_sets[j]; } } else if (mediantype == 1) { /* Divide using min-cost assignment. */ if (ndims == 2) map2d(graph, xvecs, nvtxs, sets, goal, vwgt_max); else if (ndims == 3) map3d(graph, xvecs, nvtxs, sets, goal, vwgt_max); } else if (mediantype == 2) { /* Divide recursively using medians. */ rec_median_k(graph, xvecs, nvtxs, active, ndims, cube_or_mesh, goal, using_vwgts, sets); } else if (mediantype == 3) { /* Cut with independent medians => unbalanced. */ bits = 1; temp_sets = smalloc((nvtxs + 1) * sizeof(int)); for (j = 1; j <= nvtxs; j++) sets[j] = 0; for (i = 1; i <= ndims; i++) { temp_goal[0] = temp_goal[1] = 0; for (j = 0; j < (1 << ndims); j++) { if (bits & j) temp_goal[1] += goal[j]; else temp_goal[0] += goal[j]; } bits <<= 1; median(graph, xvecs[i], nvtxs, active, temp_goal, using_vwgts, temp_sets); for (j = 1; j <= nvtxs; j++) sets[j] = (sets[j] << 1) + temp_sets[j]; } sfree(temp_sets); } if (mediantype == 4) { /* Stripe the domain. */ rec_median_1(graph, xvecs[1], nvtxs, active, cube_or_mesh, nsets, goal, using_vwgts, sets, TRUE); } }