You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
12 KiB
303 lines
12 KiB
/*
|
|
* Copyright(C) 1999-2021, 2023 National Technology & Engineering Solutions
|
|
* of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
|
|
* NTESS, the U.S. Government retains certain rights in this software.
|
|
*
|
|
* See packages/seacas/LICENSE for details
|
|
*/
|
|
|
|
#include "defs.h"
|
|
#include "params.h"
|
|
#include "smalloc.h"
|
|
#include "structs.h"
|
|
#include <stdio.h>
|
|
|
|
void chaco_divide(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 */
|
|
int *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 propagation */
|
|
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 */
|
|
int (*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 */
|
|
int *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 */
|
|
maxdeg = 0;
|
|
|
|
if (DEBUG_TRACE > 0) {
|
|
printf("<Entering divide, nvtxs = %d, nedges = %d>\n", nvtxs, nedges);
|
|
}
|
|
|
|
if (nvtxs <= 0) {
|
|
return;
|
|
}
|
|
if (nedges == 0 && global_method != 3) {
|
|
global_method = 4;
|
|
local_method = 2;
|
|
}
|
|
|
|
for (i = 0; i < MAXSETS; i++) {
|
|
weights[i] = 0.0;
|
|
}
|
|
|
|
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 = smalloc(nvtxs * sizeof(int));
|
|
for (i = 1; i <= ndims; i++) {
|
|
yvecs[i] = smalloc((nvtxs + 1) * sizeof(double));
|
|
}
|
|
|
|
if (mkconnected) {
|
|
/* If doing multi-level KL, this happens on coarse graph. */
|
|
mark = (int *)&(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(yvecs[i]);
|
|
}
|
|
|
|
if (mkconnected) {
|
|
make_unconnected(graph, &nedges, &cdata, using_ewgts);
|
|
}
|
|
|
|
sfree(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(bndy_list);
|
|
}
|
|
}
|
|
|