/* Combine goals of collections of processors for next division. */ public static void merge_goals(double[] goal, /* desired set sizes */ double[] merged_goal, /* sizes of sets at this partition level */ set_info *set_info, /* information about all sets */ int[] subsets, /* set numbers of processors to merge */ int nsets, /* number of sets created by this division */ int ndims_tot, /* total number of dimensions in the hypercube */ bool cube_or_mesh, /* 0=> hypercube, d=> d-dimensional mesh */ int[] mesh_dims /*[3]*/, /* shape of mesh */ double vwgt_sum /* actual sum of vertex weights */ ) { set_info *set; /* set of processors still clumped together */ double total_goal; /* total of desired goals */ int index; /* x, y or z location of a processor */ int i, x, y, z; /* loop counters */ total_goal = 0; for (i = 0; i < nsets; i++) { set = &(set_info[subsets[i]]); merged_goal[i] = 0; if (cube_or_mesh) { /* Mesh architecture. */ for (x = set->low[0]; x < set->low[0] + set->span[0]; x++) { for (y = set->low[1]; y < set->low[1] + set->span[1]; y++) { for (z = set->low[2]; z < set->low[2] + set->span[2]; z++) { index = z * mesh_dims[0] * mesh_dims[1] + y * mesh_dims[0] + x; merged_goal[i] += goal[index]; } } } } else if (!cube_or_mesh) { /* Hypercube architecture. */ x = 1 << (ndims_tot - set->ndims); y = 1 << ndims_tot; for (z = set->setnum; z < y; z += x) { merged_goal[i] += goal[z]; } } total_goal += merged_goal[i]; } /* Now scale goals to reflect actual weight of vertices available. */ for (i = 0; i < nsets; i++) { merged_goal[i] = (merged_goal[i] / total_goal) * vwgt_sum; } }
/* Compute the average distance between two subsets of mesh processors. */ private static double avg_dist_mesh(set_info *set1, /* data about all first set */ set_info *set2, /* data about all second set */ int architecture /* dimension of mesh */ ) { double val; /* distance returned */ int i; /* loop counter */ val = 0; for (i = 0; i < architecture; i++) { val += avg_dist_interval(set1->low[i], set1->span[i], set2->low[i], set2->span[i]); } return(val); }
static void avg_dists_mesh(int architecture, /* dimensions of mesh */ set_info *set_info, /* data about all the sets */ int nsets, /* number of subsets being created */ int set_max, /* largest set created so far */ int [] subsets, /* subsets being created */ float *[] dists /*[MAXSETS]*/ /* distances from my subsets to other sets */ ) { float *dist0; /* first of dists vectors */ float *dist; /* one of dists vectors */ double val; /* distance from subset to set */ double sep; /* distance between two subsets */ int set; /* loops through all other sets */ int i; /* loop counter */ /* First compute distances for subset 0. */ dist0 = dists[0]; for (set = 0; set < set_max; set++) { if (set_info[set].span[0] >= 0) { val = avg_dist_mesh(&set_info[subsets[0]], &set_info[set], architecture); dist0[set] = (float)val; } } /* Now compute all distances relative to subset 0. */ for (i = 1; i < nsets; i++) { dist = dists[i]; sep = avg_dist_mesh(&set_info[subsets[i]], &set_info[subsets[0]], architecture); for (set = 0; set < set_max; set++) { if (set_info[set].span[0] >= 0) { val = avg_dist_mesh(&set_info[subsets[i]], &set_info[set], architecture); /* Note: this is net preference for set over 0. */ dist[set] = (float)((dist0[set] - val) / sep); } } } }
private static bool define_subcubes(int nsets_real, /* actual number of sets being created */ int ndims_tot, /* total hypercube dimensions */ int ndims, /* # dimension in this cut */ set_info *set, /* data for set being divided */ set_info *set_info, /* data for all sets */ int [] subsets, /* subsets to be created */ bool inert, /* using inertial method? */ int *pstriping, /* cut in single direction? */ int[][] hop_mtx_special /*[MAXSETS][MAXSETS]*/ /* nonstandard hop values */ ) { bool hop_flag; /* use special hop matrix? */ int nsets; /* number of sets being created */ int setnum; /* global number of subset */ int bits; /* number of bits in which two sets differ */ int i, j, k; /* loop counters */ nsets = 1 << ndims; hop_flag = false; for (k = nsets - 1; k >= 0; k--) /* Backwards to not overwrite current set. */ { setnum = set->setnum | (k << (ndims_tot - set->ndims)); set_info[setnum].ndims = set->ndims - ndims; subsets[k] = setnum; } *pstriping = (inert && nsets_real > 2) ? 1 : 0; if (*pstriping != 0) /* Gray code for better mapping. */ { for (k = 0; k < nsets; k++) { subsets[k] = gray(subsets[k]); } if (KL_METRIC == KernighanLinMetric.Hops) { hop_flag = true; for (i = 0; i < nsets; i++) { hop_mtx_special[i][i] = 0; for (j = 0; j < i; j++) { hop_mtx_special[i][j] = 0; bits = (subsets[i]) ^ (subsets[j]); while (bits != 0) { if ((bits & 1) != 0) { ++hop_mtx_special[i][j]; } bits >>= 1; } hop_mtx_special[j][i] = hop_mtx_special[i][j]; } } } } return(hop_flag); }
public static bool divide_procs(int architecture, /* 0 => hypercube, d => d-dimensional mesh */ int ndims, /* normal dimension of each cut */ int ndims_tot, /* total number of hypercube dimensions */ set_info *info_set, /* data for all sets */ set_info *divide_set, /* data for set being divided */ int[] subsets, /* subsets to be created */ bool inert, /* using inertial method? */ int *pndims_real, /* actual ndims for this cut */ int *pnsets_real, /* # sets created by this cut */ int *pstriping, /* cut in single direction? */ int [] cut_dirs, /* direction of each cut if mesh */ int [] mesh_dims, /* size of full mesh */ int[][] hops_special /*[][MAXSETS]*/ /* hop matrix for nonstandard cases */ ) { int nsets_real = -1; /* number of sets to divide into */ int ndims_real = -1; /* number of eigenvectors to use */ int striping = -1; /* cut in single direction? */ bool flag = true; /* unusual partition => use special hops */ int ndim_poss; /* largest dimensionality possible */ int idims; /* true dimensionality of subgrid */ int i; /* loop counter */ if (architecture > 0) /* Mesh, complicated case. */ { nsets_real = divide_set->span[0] * divide_set->span[1] * divide_set->span[2]; nsets_real = Math.Min(1 << ndims, nsets_real); ndims_real = ndims; while (1 << ndims_real > nsets_real) { --ndims_real; } ndim_poss = 0; idims = 0; for (i = 0; i < 3; i++) { if (divide_set->span[i] >= 2) { ndim_poss++; idims++; } if (divide_set->span[i] >= 4) { ndim_poss++; } if (divide_set->span[i] >= 8) { ndim_poss++; } } ndims_real = Math.Min(ndim_poss, ndims_real); if (idims > 1) { nsets_real = 1 << ndims_real; } flag = define_submeshes(nsets_real, architecture, mesh_dims, divide_set, info_set, subsets, inert, &striping, cut_dirs, hops_special); if (striping != 0) { ndims_real = 1; } } else if (architecture == 0) /* Hypercube, easy case. */ { ndims_real = Math.Min(ndims, divide_set->ndims); nsets_real = 1 << ndims_real; flag = define_subcubes(nsets_real, ndims_tot, ndims_real, divide_set, info_set, subsets, inert, &striping, hops_special); if (striping != 0) { ndims_real = 1; } } *pndims_real = ndims_real; *pnsets_real = nsets_real; *pstriping = striping; return(flag); }
/* Figure out how to divide mesh into pieces. Return true if nonstandard. */ private static bool define_submeshes(int nsets, /* number of subsets in this partition */ int cube_or_mesh, /* 0=> hypercube, d=> d-dimensional mesh */ int [] mesh_dims, /* shape of mesh */ set_info *set, /* set data for set I'm partitioning */ set_info *set_info, /* set data for all sets */ int [] subsets, /* subsets being created by partition */ bool inert, /* using inertial method? */ int *striping, /* should I partition with parallel cuts? */ int [] dir, /* directions of each cut */ int[][] hop_mtx_special /*[MAXSETS][MAXSETS]*/ /* hops values if unusual */ ) { int ndims; /* dimension of cut */ int[] dims = new int[3]; /* local copy of mesh_dims to modify */ int maxdim; /* longest dimension of the mesh */ int mindim; /* intest dimension of mesh */ int[] start = new int[3]; /* start in each index of submesh */ int[] width = new int[3]; /* length in each index of submesh */ int[] nbits = new int[3]; /* values for computing hops */ int[] coords = new int[3]; /* location of set in logical grid */ int[] mask = new int[3]; /* values for computing hops */ int setnum; /* number of created set */ bool flag; /* return condition */ bool snaking; /* is single stripe snaking through grid? */ bool reverse; /* should I reverse direction for embedding? */ int i, j, k; /* loop counters */ dims[0] = set->span[0]; dims[1] = set->span[1]; dims[2] = set->span[2]; ndims = 1; while ((2 << ndims) <= nsets) { ndims++; } /* Find the intest and longest directions in mesh. */ maxdim = -1; mindim = dims[0]; dir[1] = dir[2] = 0; for (i = 0; i < cube_or_mesh; i++) { if (dims[i] > maxdim) { maxdim = dims[i]; dir[0] = i; } if (dims[i] < mindim) { mindim = dims[i]; } } /* Decide whether or not to force striping. */ i = 0; for (j = 0; j < cube_or_mesh; j++) { if (set->span[j] > 1) { i++; } } *striping = (i <= 1 || nsets == 3 || (maxdim > nsets && (maxdim > .6 * nsets * mindim || (inert && nsets > 2)))) ? 1 : 0; snaking = !(*striping != 0) && inert && nsets > 2; if (!(*striping != 0)) { if (nsets >= 4) /* Find direction of second & third cuts. */ { dims[dir[0]] /= 2; maxdim = -1; for (i = 0; i < cube_or_mesh; i++) { if (dims[i] > maxdim) { maxdim = dims[i]; dir[1] = i; } } } if (nsets == 8) /* Find a third direction. */ { dims[dir[1]] /= 2; maxdim = -1; for (i = 0; i < cube_or_mesh; i++) { if (dims[i] > maxdim) { maxdim = dims[i]; dir[2] = i; } } } nbits[0] = nbits[1] = nbits[2] = 0; for (i = 0; i < ndims; i++) { ++nbits[dir[i]]; } for (i = 0; i < 3; i++) { mask[i] = (1 << nbits[i]) - 1; } mask[1] <<= nbits[0]; mask[2] <<= nbits[0] + nbits[1]; } for (k = nsets - 1; k >= 0; k--) /* Backwards to not overwrite current set. */ { for (i = 0; i < 3; i++) { start[i] = 0; width[i] = dims[i] = set->span[i]; } if ((*striping) != 0) /* Use longest direction for all cuts. */ { start[dir[0]] = (k * dims[dir[0]] + nsets - 1) / nsets; width[dir[0]] = ((k + 1) * dims[dir[0]] + nsets - 1) / nsets - start[dir[0]]; } else /* Figure out partition based on cut directions. */ { coords[0] = k & mask[0]; coords[1] = (k & mask[1]) >> nbits[0]; coords[2] = (k & mask[2]) >> (nbits[0] + nbits[1]); if (snaking) { reverse = (coords[1] & 1) != 0; if (reverse) { coords[0] = mask[0] - coords[0]; } reverse = (coords[2] & 1) != 0; if (reverse) { coords[1] = (mask[1] >> nbits[0]) - coords[1]; } } for (j = 0; j < ndims; j++) { --nbits[dir[j]]; if ((coords[dir[j]] & (1 << nbits[dir[j]])) != 0) { /* Right side of partition. */ start[dir[j]] += (width[dir[j]] + 1) / 2; width[dir[j]] /= 2; } else /* Left side of partition */ { width[dir[j]] = (width[dir[j]] + 1) / 2; } } /* Now restore nbits values. */ nbits[0] = nbits[1] = nbits[2] = 0; for (i = 0; i < ndims; i++) { ++nbits[dir[i]]; } } for (i = 0; i < 3; i++) { start[i] += set->low[i]; } setnum = (start[2] * mesh_dims[1] + start[1]) * mesh_dims[0] + start[0]; for (i = 0; i < 3; i++) { set_info[setnum].low[i] = start[i]; set_info[setnum].span[i] = width[i]; } subsets[k] = setnum; } /* Check to see if hop_mtx is nonstandard. */ flag = false; if (KL_METRIC == KernighanLinMetric.Hops) { if ((*striping) != 0) { flag = true; for (i = 0; i < nsets; i++) { for (j = 0; j < nsets; j++) { hop_mtx_special[i][j] = Math.Abs(i - j); } } } else if (nsets == 4) { if (dir[0] == dir[1] || snaking) { flag = true; for (i = 0; i < nsets; i++) { start[0] = i & mask[0]; start[1] = (i & mask[1]) >> nbits[0]; if (snaking) { reverse = (start[1] & 1) != 0; if (reverse) { start[0] = mask[0] - start[0]; } } for (j = i; j < nsets; j++) { coords[0] = j & mask[0]; coords[1] = (j & mask[1]) >> nbits[0]; if (snaking) { reverse = (coords[1] & 1) != 0; if (reverse) { coords[0] = mask[0] - coords[0]; } } hop_mtx_special[i][j] = hop_mtx_special[j][i] = Math.Abs(start[0] - coords[0]) + Math.Abs(start[1] - coords[1]); } } } } else if (nsets == 8) { if (dir[0] == dir[1] || dir[0] == dir[2] || dir[1] == dir[2] || snaking) { flag = true; for (i = 0; i < nsets; i++) { start[0] = i & mask[0]; start[1] = (i & mask[1]) >> nbits[0]; start[2] = (i & mask[2]) >> (nbits[0] + nbits[1]); if (snaking) { reverse = (start[1] & 1) != 0; if (reverse) { start[0] = mask[0] - start[0]; } reverse = (start[2] & 1) != 0; if (reverse) { start[1] = (mask[1] >> nbits[0]) - start[1]; } } for (j = i; j < nsets; j++) { coords[0] = j & mask[0]; coords[1] = (j & mask[1]) >> nbits[0]; coords[2] = (j & mask[2]) >> (nbits[0] + nbits[1]); if (snaking) { reverse = (coords[1] & 1) != 0; if (reverse) { coords[0] = mask[0] - coords[0]; } reverse = (coords[2] & 1) != 0; if (reverse) { coords[1] = (mask[1] >> nbits[0]) - coords[1]; } } hop_mtx_special[i][j] = hop_mtx_special[j][i] = Math.Abs(start[0] - coords[0]) + Math.Abs(start[1] - coords[1]) + Math.Abs(start[2] - coords[2]); } } } } } *striping = ((*striping != 0) && snaking) ? 1 : 0; return(flag); }
static void avg_dists_cube(int ndims_tot, /* total number of hypercube dimensions */ int ndims, /* number of dimensions created this step */ set_info *set_info, /* data about all the sets */ int nsets, /* number of subsets being created */ int set_max, /* largest set created so far */ int [] subsets, /* subsets being created */ float *[] dists /*[MAXSETS]*/ /* distances from my subsets to other sets */ ) { float *dist0; /* first of dists vectors */ float *dist; /* one of dists vectors */ int ndims_old; /* hypercube dimensions not relevant */ int ndims_left; /* hypercube dimensions left to do */ int myset; /* subset being analyzed */ int start; /* bit difference between two sets */ int val; /* number of differing bits */ int set; /* loops through all other sets */ int i; /* loop counter */ /* First compute distances for subset 0. */ myset = subsets[0]; dist0 = dists[0]; ndims_left = set_info[myset].ndims; ndims_old = ndims_tot - ndims_left - ndims; for (set = 0; set < set_max; set++) { if (set_info[set].ndims >= 0) { val = 0; if (ndims_left == set_info[set].ndims) { start = (myset ^ set) >> ndims_old; while (start != 0) { if ((start & 1) != 0) { val++; } start >>= 1; } } dist0[set] = val; } } /* Now compute all distances relative to subset 0. */ for (i = 1; i < nsets; i++) { myset = subsets[i]; dist = dists[i]; for (set = 0; set < set_max; set++) { if (set_info[set].ndims >= 0) { val = 0; if (ndims_left == set_info[set].ndims) { start = (myset ^ set) >> ndims_old; while (start != 0) { if ((start & 1) != 0) { val++; } start >>= 1; } } /* Note: this is net preference for set over set 0. */ dist[set] = dist0[set] - val; } } } }
/* Compute the terminal constraints for next partition. */ public static void make_term_props(vtx_data **graph, /* data structure for graph */ int sub_nvtxs, /* number of vtxs in subgraph */ int *loc2glob, /* mapping from subgraph to graph */ int *assignment, /* set for each vertex */ int architecture, /* 0 => hypercube, 1 => mesh */ int ndims_tot, /* total hypercube dimensions */ int ndims, /* number of dimensions at this step */ set_info *set_info, /* data about all the sets */ int setnum, /* number of set being divided */ int nsets, /* number of subsets being created */ int set_max, /* largest set created so far */ int [] subsets, /* subsets being created */ float *[] term_wgts, /* set of terminal weights for each vertex */ bool useEdgeWeights /* are edge weights being used? */ ) { double[] term_wgt = new double[MAXSETS]; /* terminal weights */ float * twptr; /* one of the term_wgts vectors */ float *[] dists = new float *[MAXSETS]; /* distances from my subsets to other sets */ float * dist; /* one of the dists arrays */ float edge_wgt; /* weight of an edge */ int vtx; /* vertex number */ int neighbor; /* neighboring vertex number */ int neighbor_setnum; /* set neighboring vertex is in */ int i, j, k; /* loop counters */ /* First compute average distance between my subsets and all other sets. */ dist = (float *)Marshal.AllocHGlobal(nsets * (set_max + 1) * sizeof(float)); for (i = 0; i < nsets; i++) { dists[i] = dist; dist += set_max + 1; } for (k = 0; k < MAXSETS; k++) { term_wgt[k] = 0; } if (architecture == 0) { avg_dists_cube(ndims_tot, ndims, set_info, nsets, set_max, subsets, dists); } else if (architecture > 0) { avg_dists_mesh(architecture, set_info, nsets, set_max, subsets, dists); } edge_wgt = 1; for (i = 1; i <= sub_nvtxs; i++) { for (k = 1; k < nsets; k++) { term_wgt[k] = 0; } vtx = loc2glob[i]; for (j = 1; j < graph[vtx]->nedges; j++) { neighbor = graph[vtx]->edges[j]; neighbor_setnum = assignment[neighbor]; if (neighbor_setnum != setnum) { if (useEdgeWeights) { edge_wgt = graph[vtx]->ewgts[j]; } for (k = 1; k < nsets; k++) { dist = dists[k]; term_wgt[k] += edge_wgt * dist[neighbor_setnum]; } } } for (k = 1; k < nsets; k++) { twptr = term_wgts[k]; twptr[i] = (float)term_wgt[k]; } } Marshal.FreeHGlobal((IntPtr)dists[0]); }