/* This software was developed by Bruce Hendrickson and Robert Leland * * at Sandia National Laboratories under US Department of Energy * * contract DE-AC04-76DP00789 and is copyrighted by Sandia Corporation. */ #include #include "params.h" #include "defs.h" #include "structs.h" void divide(graph, nvtxs, nedges, using_vwgts, using_ewgts, vwsqrt, igeom, coords, assignment, goal, architecture, term_wgts, global_method, local_method, rqi_flag, vmax, ndims, eigtol, hop_mtx, nsets, striping) struct vtx_data **graph; /* graph data structure */ int nvtxs; /* number of vertices in graph */ int nedges; /* number of edges in graph */ int using_vwgts; /* are vertex weights being used? */ int using_ewgts; /* are edge weights being used? */ double *vwsqrt; /* sqrt of vertex weights (length nvtxs+1) */ int igeom; /* geometry dimension for inertial method */ float **coords; /* coordinates for inertial method */ short *assignment; /* set number of each vtx (length n) */ double *goal; /* desired set sizes */ int architecture; /* 0 => hypercube, d => d-dimensional mesh */ float *term_wgts[]; /* weights for terminal propogation */ int global_method; /* global partitioning algorithm */ int local_method; /* local partitioning algorithm */ int rqi_flag; /* should I use multilevel eigensolver? */ int vmax; /* if so, # vertices to coarsen down to */ int ndims; /* number of eigenvectors */ double eigtol; /* tolerance on eigenvectors */ short (*hop_mtx)[MAXSETS]; /* between-set hop costs for KL */ int nsets; /* number of sets to partition into */ int striping; /* partition by striping into pieces? */ { extern int DEBUG_TRACE; /* trace main execution path? */ extern int DEBUG_CONNECTED; /* debug flag for connected components */ extern int DEBUG_KL; /* debug flag for KL variants */ extern int COARSE_NLEVEL_KL;/* how often to invoke KL while uncoarsening */ extern int MAPPING_TYPE; /* how to map from eigenvectors to partition */ extern int LANCZOS_TYPE; /* which Lanczos variant to use */ extern int MAKE_CONNECTED; /* force connectivity in spectral method? */ extern double KL_IMBALANCE; /* fractional imbalance allowed in KL */ extern int VERTEX_SEPARATOR;/* vertex instead of edge separator? */ extern int VERTEX_COVER; /* form/improve vtx separator via matching? */ extern int COARSE_BPM; /* apply matching/flow while uncoarsening? */ struct connect_data *cdata; /* data for enforcing connectivity */ double *yvecs[MAXDIMS + 1]; /* space for pointing to eigenvectors */ double evals[MAXDIMS + 1]; /* corresponding eigenvalues */ double weights[MAXSETS]; /* vertex weight in each set */ double maxdeg; /* maximum weighted degree of a vertex */ double total_weight; /* weight of all vertices */ double temp_goal[2]; /* goal to simulate bisection while striping */ double *fake_goal; /* either goal or temp_goal */ int *active; /* keeping track of vtxs in BFS (length nvtxs) */ int *bndy_list; /* list of boundary vtxs */ int *null_ptr; /* argument to klspiff */ short *mark; /* for marking vtxs in BFS (length nvtxs+1) */ int vwgt_max; /* largest vertex weight */ int max_dev; /* largest allowed deviation from balance */ int mediantype; /* how to map from eigenvectors to partition */ int solver_flag; /* which Lanczos variant to use */ int mkconnected; /* enforce connectivity in spectral method? */ int i; /* loop counters */ int simple_type; /* which type of simple partitioning to use */ double *smalloc(); int sfree(), find_bndy(), find_side_bndy(); void make_connected(), print_connected(), coarsen_kl(), eigensolve(); void coarsen_klv(), klvspiff(); void assign(), make_unconnected(), inertial(), klspiff(), simple_part(); void count_weights(), bpm_improve(), countup_vtx_sep(); double find_maxdeg(); if (DEBUG_TRACE > 0) { printf("\n", nvtxs, nedges); } if (nvtxs <= 0) return; if (nedges == 0 && global_method != 3) { global_method = 4; local_method = 2; } bndy_list = NULL; if (striping) { ndims = 1; mediantype = 4; temp_goal[0] = temp_goal[1] = 0; for (i = 0; 2 * i + 1 < nsets; i++) { temp_goal[0] += goal[i]; temp_goal[1] += goal[nsets - 1 - i]; } i = nsets / 2; if (2 * i != nsets) { temp_goal[0] += .5 * goal[i]; temp_goal[1] += .5 * goal[i]; } fake_goal = temp_goal; } else { mediantype = MAPPING_TYPE; fake_goal = goal; } if (using_vwgts) { vwgt_max = 0; for (i = 1; i <= nvtxs; i++) { if (graph[i]->vwgt > vwgt_max) vwgt_max = graph[i]->vwgt; } } else vwgt_max = 1; /* Perform one of the global partitionings on this sub-graph. */ if (global_method == 1) { /* Multilevel method. */ mkconnected = MAKE_CONNECTED; solver_flag = LANCZOS_TYPE; if (VERTEX_SEPARATOR) { coarsen_klv(graph, nvtxs, nedges, using_vwgts, using_ewgts, term_wgts, igeom, coords, vwgt_max, assignment, goal, architecture, hop_mtx, solver_flag, ndims, nsets, vmax, mediantype, mkconnected, eigtol, COARSE_NLEVEL_KL, 0, &bndy_list, weights, FALSE); if (VERTEX_COVER && !COARSE_BPM) { max_dev = vwgt_max; total_weight = 0; for (i = 0; i < nsets; i++) { total_weight += goal[i]; } total_weight *= KL_IMBALANCE / nsets; if (total_weight > max_dev) { max_dev = total_weight; } bpm_improve(graph, assignment, goal, max_dev, &bndy_list, weights, using_vwgts); } } else { coarsen_kl(graph, nvtxs, nedges, using_vwgts, using_ewgts, term_wgts, igeom, coords, vwgt_max, assignment, goal, architecture, hop_mtx, solver_flag, ndims, nsets, vmax, mediantype, mkconnected, eigtol, COARSE_NLEVEL_KL, 0, &bndy_list, weights, FALSE); if (VERTEX_COVER) { max_dev = vwgt_max; total_weight = 0; for (i = 0; i < nsets; i++) { total_weight += goal[i]; } total_weight *= KL_IMBALANCE / nsets; if (total_weight > max_dev) { max_dev = total_weight; } if (goal[0] - weights[0] <= goal[1] - weights[1]) i = 0; else i = 1; find_side_bndy(graph, nvtxs, assignment, i, 2, &bndy_list); count_weights(graph, nvtxs, assignment, nsets + 1, weights, using_vwgts); if (DEBUG_KL > 0) { printf("After KL, before bpm_improve\n"); countup_vtx_sep(graph, nvtxs, assignment); } bpm_improve(graph, assignment, goal, max_dev, &bndy_list, weights, using_vwgts); } } } else if (global_method == 2) { /* Spectral method. */ mkconnected = MAKE_CONNECTED; solver_flag = LANCZOS_TYPE; active = (int *) smalloc((unsigned) nvtxs * sizeof(int)); for (i = 1; i <= ndims; i++) { yvecs[i] = (double *) smalloc((unsigned) (nvtxs + 1) * sizeof(double)); } if (mkconnected) { /* If doing multi-level KL, this happens on coarse graph. */ mark = (short *) &(yvecs[1][0]); make_connected(graph, nvtxs, &nedges, mark, active, &cdata, using_ewgts); if (DEBUG_CONNECTED > 0) { printf("Enforcing connectivity\n"); print_connected(cdata); } } else if (DEBUG_CONNECTED > 0) { printf("Not enforcing connectivity\n"); } maxdeg = find_maxdeg(graph, nvtxs, using_ewgts, (float *) NULL); eigensolve(graph, nvtxs, nedges, maxdeg, vwgt_max, vwsqrt, using_vwgts, using_ewgts, term_wgts, igeom, coords, yvecs, evals, architecture, assignment, fake_goal, solver_flag, rqi_flag, vmax, ndims, mediantype, eigtol); assign(graph, yvecs, nvtxs, ndims, architecture, nsets, vwsqrt, assignment, active, mediantype, goal, vwgt_max); for (i = 1; i <= ndims; i++) sfree((char *) yvecs[i]); if (mkconnected) { make_unconnected(graph, &nedges, &cdata, using_ewgts); } sfree((char *) active); } else if (global_method == 3) { /* Inertial method. */ inertial(graph, nvtxs, architecture, nsets, igeom, coords, assignment, goal, using_vwgts); } else if (global_method == 4) { /* Linear ordering. */ simple_type = 3; simple_part(graph, nvtxs, assignment, nsets, simple_type, goal); } else if (global_method == 5) { /* Random partitioning. */ simple_type = 2; simple_part(graph, nvtxs, assignment, nsets, simple_type, goal); } else if (global_method == 6) { /* Scattered partitioning. */ simple_type = 1; simple_part(graph, nvtxs, assignment, nsets, simple_type, goal); } /* Perform a local refinement, if specified, on the global partitioning. */ if (local_method == 1 && global_method != 1) { /* If global_method == 1, already did KL as part of multilevel-KL. */ null_ptr = NULL; max_dev = vwgt_max; total_weight = 0; for (i = 0; i < nsets; i++) { total_weight += goal[i]; } total_weight *= KL_IMBALANCE / nsets; if (total_weight > max_dev) { max_dev = total_weight; } if (VERTEX_SEPARATOR) { find_bndy(graph, nvtxs, assignment, 2, &bndy_list); count_weights(graph, nvtxs, assignment, nsets + 1, weights, (vwgt_max != 1)); klvspiff(graph, nvtxs, assignment, goal, max_dev, &bndy_list, weights); if (VERTEX_COVER) { bpm_improve(graph, assignment, goal, max_dev, &bndy_list, weights, using_vwgts); } } else { if (global_method != 2) { maxdeg = find_maxdeg(graph, nvtxs, using_ewgts, (float *) NULL); } count_weights(graph, nvtxs, assignment, nsets, weights, (vwgt_max != 1)); klspiff(graph, nvtxs, assignment, nsets, hop_mtx, goal, term_wgts, max_dev, maxdeg, using_ewgts, &null_ptr, weights); if (VERTEX_COVER) { if (goal[0] - weights[0] <= goal[1] - weights[1]) i = 0; else i = 1; find_side_bndy(graph, nvtxs, assignment, i, 2, &bndy_list); count_weights(graph, nvtxs, assignment, nsets + 1, weights, (vwgt_max != 1)); if (DEBUG_KL > 0) { printf("After KL, before bpm_improve\n"); countup_vtx_sep(graph, nvtxs, assignment); } bpm_improve(graph, assignment, goal, max_dev, &bndy_list, weights, using_vwgts); } } } else if (global_method != 1 && VERTEX_COVER) { find_bndy(graph, nvtxs, assignment, 2, &bndy_list); count_weights(graph, nvtxs, assignment, nsets + 1, weights, (vwgt_max != 1)); if (DEBUG_KL > 0) { printf("Before bpm_improve\n"); countup_vtx_sep(graph, nvtxs, assignment); } max_dev = vwgt_max; total_weight = 0; for (i = 0; i < nsets; i++) { total_weight += goal[i]; } total_weight *= KL_IMBALANCE / nsets; if (total_weight > max_dev) { max_dev = total_weight; } bpm_improve(graph, assignment, goal, max_dev, &bndy_list, weights, using_vwgts); } if (bndy_list != NULL) { sfree((char *) bndy_list); } }