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.
424 lines
16 KiB
424 lines
16 KiB
/*
|
|
* Copyright(C) 1999-2020, 2022, 2022, 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" // for FALSE, TRUE
|
|
#include "params.h" // for MAXSETS
|
|
#include "smalloc.h" // for sfree, smalloc_ret
|
|
#include "structs.h"
|
|
#include <math.h> // for sqrt
|
|
#include <stdio.h> // for NULL, printf, fprintf, etc
|
|
|
|
extern void reflect_input(int nvtxs, /* number of vertices in graph */
|
|
int nedges, /* number of edges in graph */
|
|
int igeom, /* geometric dimension for inertial method */
|
|
char *graphname, /* name of graph input file */
|
|
char *geomname, /* name of geometry input file */
|
|
char *inassignname, /* name of assignment input file */
|
|
char *outassignname, /* name of assignment output file */
|
|
char *outfilename, /* name of information output file */
|
|
int architecture, /* 0=> hypercube, d=> d-dimensional mesh */
|
|
int ndims_tot, /* total number of cuts to make */
|
|
int mesh_dims[3], /* size of mesh */
|
|
int global_method, /* global partitioning algorithm */
|
|
int local_method, /* local partitioning algorithm */
|
|
int rqi_flag, /* use RQI/Symmlq eigensolver? */
|
|
int vmax, /* smallest acceptable coarsened nvtxs */
|
|
int ndims, /* partitioning level */
|
|
double eigtol, /* tolerance on eigenvectors */
|
|
long seed, /* random number seed */
|
|
FILE *outfile); /* file to write output to */
|
|
|
|
double *SQRTS; /* precomputed square roots for efficiency */
|
|
|
|
double DOUBLE_EPSILON; /* machine precision */
|
|
double DOUBLE_MAX; /* largest double precision value */
|
|
|
|
char *Graph_File_Name = NULL; /* Input graph file name */
|
|
char *Geometry_File_Name = NULL; /* Input coordinate file name */
|
|
char *Assign_In_File_Name = NULL; /* Input assignment file name */
|
|
|
|
FILE *Output_File = NULL; /* Pointer to output file or NULL */
|
|
|
|
int EXPERT = 0; /* user mode */
|
|
|
|
int submain(struct vtx_data **graph, /* data structure for graph */
|
|
int nvtxs, /* number of vertices in full graph */
|
|
int nedges, /* number of edges in graph */
|
|
int using_vwgts, /* are vertex weights being used? */
|
|
int using_ewgts, /* are edge weights being used? */
|
|
int igeom, /* geometry dimension if using inertial method */
|
|
float **coords, /* coordinates of vertices if used */
|
|
char *outassignname, /* name of assignment output file */
|
|
char *outfilename, /* in which to print output metrics */
|
|
int *assignment, /* set number of each vtx (length n) */
|
|
double *goal, /* desired sizes for each set */
|
|
int architecture, /* 0=> hypercube, d=> d-dimensional mesh */
|
|
int ndims_tot, /* total number hypercube dimensions */
|
|
int mesh_dims[3], /* extent of mesh in 3 directions */
|
|
int global_method, /* global partitioning algorithm */
|
|
int local_method, /* local partitioning algorithm */
|
|
int rqi_flag, /* use RQI/Symmlq eigensolver? */
|
|
int vmax, /* if so, how many vtxs to coarsen down to */
|
|
int ndims, /* number of eigenvectors (2^d sets) */
|
|
double eigtol, /* tolerance on eigenvectors */
|
|
long seed /* for random graph mutations */
|
|
)
|
|
{
|
|
extern int ECHO; /* controls output to file or screen */
|
|
extern int CHECK_INPUT; /* should I check input for correctness? */
|
|
extern int SEQUENCE; /* just generate spectal ordering? */
|
|
extern int OUTPUT_ASSIGN; /* print assignment to a file? */
|
|
extern int OUTPUT_METRICS; /* controls formatting of output */
|
|
extern int PERTURB; /* perturb matrix if quad/octasection? */
|
|
extern int NSQRTS; /* number of square roots to precompute */
|
|
extern int KL_METRIC; /* KL interset cost: 1=>cuts, 2=>hops */
|
|
extern int LANCZOS_TYPE; /* type of Lanczos to use */
|
|
extern int REFINE_MAP; /* use greedy strategy to improve mapping? */
|
|
extern int REFINE_PARTITION; /* number of calls to pairwise_refine to make */
|
|
extern int VERTEX_COVER; /* use matching to reduce vertex separator? */
|
|
extern int CONNECTED_DOMAINS; /* force subdomain connectivity at end? */
|
|
extern int INTERNAL_VERTICES; /* greedily increase internal vtxs? */
|
|
extern int DEBUG_INTERNAL; /* debug code about force_internal? */
|
|
extern int DEBUG_REFINE_PART; /* debug code about refine_part? */
|
|
extern int DEBUG_REFINE_MAP; /* debug code about refine_map? */
|
|
extern int DEBUG_MACH_PARAMS; /* print out computed machine params? */
|
|
extern int DEBUG_TRACE; /* trace main execution path */
|
|
extern int PRINT_HEADERS; /* print section headings for output? */
|
|
extern int TIME_KERNELS; /* benchmark some numerical kernels? */
|
|
extern double start_time; /* time code was entered */
|
|
extern double total_time; /* (almost) total time spent in code */
|
|
extern double check_input_time; /* time spent checking input */
|
|
extern double partition_time; /* time spent partitioning graph */
|
|
extern double kernel_time; /* time spent benchmarking kernels */
|
|
extern double count_time; /* time spent evaluating the answer */
|
|
extern double print_assign_time; /* time spent writing output file */
|
|
FILE *outfile; /* output file */
|
|
struct vtx_data **graph2; /* data structure for graph */
|
|
int hop_mtx[MAXSETS][MAXSETS]; /* between-set hop cost for KL */
|
|
double *vwsqrt; /* sqrt of vertex weights (length nvtxs+1) */
|
|
double time, time1; /* timing variables */
|
|
char *graphname, *geomname; /* names of input files */
|
|
char *inassignname; /* name of assignment input file */
|
|
int old_nsqrts; /* old value of NSQRTS */
|
|
int append; /* append output to existing file? */
|
|
int nsets; /* number of sets created by each divide */
|
|
int nsets_tot; /* total number of sets */
|
|
int bits; /* used in computing hops */
|
|
int flag; /* return code from check_input */
|
|
int old_perturb = 0; /* saves original perturbation flag */
|
|
int i, j, k; /* loop counters */
|
|
|
|
if (DEBUG_TRACE > 0) {
|
|
printf("<Entering submain>\n");
|
|
}
|
|
|
|
/* First check all the input for consistency. */
|
|
|
|
if (architecture == 1) {
|
|
mesh_dims[1] = mesh_dims[2] = 1;
|
|
}
|
|
else if (architecture == 2) {
|
|
mesh_dims[2] = 1;
|
|
}
|
|
|
|
/* Check for simple special case of 1 processor. */
|
|
k = 0;
|
|
if (architecture == 0) {
|
|
k = 1 << ndims_tot;
|
|
}
|
|
else if (architecture > 0) {
|
|
k = mesh_dims[0] * mesh_dims[1] * mesh_dims[2];
|
|
}
|
|
|
|
if (k == 1) {
|
|
for (i = 1; i <= nvtxs; i++) {
|
|
assignment[i] = 0;
|
|
}
|
|
|
|
if (OUTPUT_ASSIGN > 0 && outassignname != NULL) {
|
|
time1 = seconds();
|
|
assign_out(nvtxs, assignment, k, outassignname);
|
|
print_assign_time += seconds() - time1;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
graphname = Graph_File_Name;
|
|
geomname = Geometry_File_Name;
|
|
inassignname = Assign_In_File_Name;
|
|
|
|
/* Turn of perturbation if using bisection */
|
|
if (ndims == 1) {
|
|
old_perturb = PERTURB;
|
|
PERTURB = FALSE;
|
|
}
|
|
|
|
if (ECHO < 0 && outfilename != NULL) { /* Open output file */
|
|
outfile = fopen(outfilename, "r");
|
|
if (outfile != NULL) {
|
|
append = TRUE;
|
|
fclose(outfile);
|
|
}
|
|
else {
|
|
append = FALSE;
|
|
}
|
|
outfile = fopen(outfilename, "a");
|
|
if (append) {
|
|
fprintf(outfile, "\n------------------------------------------------\n\n");
|
|
}
|
|
}
|
|
else {
|
|
outfile = NULL;
|
|
}
|
|
|
|
Output_File = outfile;
|
|
|
|
if (outfile != NULL && PRINT_HEADERS) {
|
|
fprintf(outfile, "\n Chaco 2.0\n");
|
|
fprintf(outfile, " Sandia National Laboratories\n\n");
|
|
}
|
|
|
|
if (CHECK_INPUT) { /* Check the input for inconsistencies. */
|
|
time1 = seconds();
|
|
|
|
flag = check_input(graph, nvtxs, nedges, igeom, coords, graphname, assignment, goal,
|
|
architecture, ndims_tot, mesh_dims, global_method, local_method, rqi_flag,
|
|
&vmax, ndims, eigtol);
|
|
|
|
check_input_time += seconds() - time1;
|
|
|
|
if (flag) {
|
|
strout("ERROR IN INPUT.\n");
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
if (ECHO != 0) {
|
|
reflect_input(nvtxs, nedges, igeom, graphname, geomname, inassignname, outassignname,
|
|
outfilename, architecture, ndims_tot, mesh_dims, global_method, local_method,
|
|
rqi_flag, vmax, ndims, eigtol, seed, outfile);
|
|
}
|
|
|
|
if (PRINT_HEADERS) {
|
|
printf("\n\nStarting to partition ...\n\n");
|
|
if (Output_File != NULL) {
|
|
fprintf(Output_File,
|
|
"\n\nStarting to partition ... (residual, warning and error messages only)\n\n");
|
|
}
|
|
}
|
|
|
|
time = seconds();
|
|
|
|
/* Perform some one-time initializations. */
|
|
setrandom(seed);
|
|
machine_params(&DOUBLE_EPSILON, &DOUBLE_MAX);
|
|
|
|
if (DEBUG_MACH_PARAMS > 0) {
|
|
printf("Machine parameters:\n");
|
|
printf(" DOUBLE_EPSILON = %e\n", DOUBLE_EPSILON);
|
|
printf(" DOUBLE_MAX = %e\n", DOUBLE_MAX);
|
|
}
|
|
|
|
nsets = (1 << ndims);
|
|
|
|
old_nsqrts = NSQRTS;
|
|
if (nvtxs < NSQRTS && !using_vwgts) {
|
|
NSQRTS = nvtxs;
|
|
}
|
|
SQRTS = smalloc_ret((NSQRTS + 1) * sizeof(double));
|
|
if (SQRTS == NULL) {
|
|
strout("ERROR: No space to allocate sqrts\n");
|
|
return (1);
|
|
}
|
|
for (i = 1; i <= NSQRTS; i++) {
|
|
SQRTS[i] = sqrt((double)i);
|
|
}
|
|
|
|
if (using_vwgts && (global_method == 1 || global_method == 2)) {
|
|
vwsqrt = smalloc_ret((nvtxs + 1) * sizeof(double));
|
|
if (vwsqrt == NULL) {
|
|
strout("ERROR: No space to allocate vwsqrt\n");
|
|
sfree(SQRTS);
|
|
NSQRTS = old_nsqrts;
|
|
return (1);
|
|
}
|
|
makevwsqrt(vwsqrt, graph, nvtxs);
|
|
}
|
|
else {
|
|
vwsqrt = NULL;
|
|
}
|
|
|
|
if (TIME_KERNELS) {
|
|
time1 = seconds();
|
|
time_kernels(graph, nvtxs, vwsqrt);
|
|
kernel_time += seconds() - time1;
|
|
}
|
|
|
|
if (SEQUENCE) {
|
|
sequence(graph, nvtxs, nedges, using_ewgts, vwsqrt, LANCZOS_TYPE, rqi_flag, vmax, eigtol);
|
|
goto End_Label;
|
|
}
|
|
|
|
/* Initialize cost function for KL-spiff */
|
|
if (global_method == 1 || local_method == 1) {
|
|
for (i = 0; i < nsets; i++) {
|
|
hop_mtx[i][i] = 0;
|
|
for (j = 0; j < i; j++) {
|
|
hop_mtx[i][j] = 0;
|
|
if (KL_METRIC == 2) { /* Count hypercube hops */
|
|
bits = i ^ j;
|
|
while (bits) {
|
|
if (bits & 1) {
|
|
++hop_mtx[i][j];
|
|
}
|
|
bits >>= 1;
|
|
}
|
|
}
|
|
else if (KL_METRIC == 1) { /* Count cut edges */
|
|
hop_mtx[i][j] = 1;
|
|
}
|
|
hop_mtx[j][i] = hop_mtx[i][j];
|
|
}
|
|
}
|
|
}
|
|
|
|
graph2 = graph;
|
|
if (global_method == 3 && local_method != 1 && !VERTEX_COVER && !using_vwgts) {
|
|
graph2 = NULL;
|
|
}
|
|
|
|
if (!(global_method == 7 && local_method == 2)) {
|
|
balance(graph2, nvtxs, nedges, using_vwgts, using_ewgts, vwsqrt, igeom, coords, assignment,
|
|
goal, architecture, ndims_tot, mesh_dims, global_method, local_method, rqi_flag, vmax,
|
|
ndims, eigtol, hop_mtx);
|
|
}
|
|
|
|
partition_time += seconds() - time - kernel_time;
|
|
|
|
nsets_tot = 0;
|
|
if (architecture == 0) {
|
|
nsets_tot = 1 << ndims_tot;
|
|
}
|
|
else if (architecture > 0) {
|
|
nsets_tot = mesh_dims[0] * mesh_dims[1] * mesh_dims[2];
|
|
}
|
|
|
|
if (graph != NULL) {
|
|
j = TRUE;
|
|
for (i = 1; i <= REFINE_PARTITION && j; i++) { /* Reduce cuts w/ KL? */
|
|
if (DEBUG_REFINE_PART > 0) {
|
|
printf("\n\nBefore pass %d to refine partition:\n", i);
|
|
if (outfile != NULL) {
|
|
fprintf(outfile, "\n\nBefore pass %d to refine partition:\n", i);
|
|
}
|
|
countup(graph, nvtxs, assignment, ndims, architecture, ndims_tot, mesh_dims, OUTPUT_METRICS,
|
|
outfile, using_ewgts);
|
|
}
|
|
j = refine_part(graph, nvtxs, using_ewgts, assignment, architecture, ndims_tot, mesh_dims,
|
|
goal);
|
|
}
|
|
}
|
|
|
|
if (graph != NULL) {
|
|
if (INTERNAL_VERTICES) {
|
|
if (DEBUG_INTERNAL > 0) {
|
|
printf("\n\nBefore increasing internal vertices:\n");
|
|
if (outfile != NULL) {
|
|
fprintf(outfile, "\n\nBefore increasing internal vertices:\n");
|
|
}
|
|
countup(graph, nvtxs, assignment, ndims, architecture, ndims_tot, mesh_dims, OUTPUT_METRICS,
|
|
outfile, using_ewgts);
|
|
}
|
|
force_internal(graph, nvtxs, using_ewgts, assignment, goal, nsets_tot, INTERNAL_VERTICES);
|
|
}
|
|
}
|
|
|
|
if (graph != NULL) {
|
|
if (CONNECTED_DOMAINS > 0) { /* Force subdomains to be connected */
|
|
connect_enforce(graph, nvtxs, using_ewgts, assignment, goal, nsets_tot, &i, &j);
|
|
printf("\nConnectivity enforcement moved %d vertices total\n", i);
|
|
printf(" largest moved subset = %d\n\n", j);
|
|
}
|
|
}
|
|
|
|
if (graph != NULL) {
|
|
if (REFINE_MAP) { /* Improve the mapping to processors? */
|
|
if (DEBUG_REFINE_MAP > 0) {
|
|
printf("\n\nBefore refining mapping to processors:\n");
|
|
if (outfile != NULL) {
|
|
fprintf(outfile, "\n\nBefore refining mapping to processors:\n");
|
|
}
|
|
countup(graph, nvtxs, assignment, ndims, architecture, ndims_tot, mesh_dims, OUTPUT_METRICS,
|
|
outfile, using_ewgts);
|
|
}
|
|
refine_map(graph, nvtxs, using_ewgts, assignment, architecture, ndims_tot, mesh_dims);
|
|
}
|
|
}
|
|
|
|
if (OUTPUT_ASSIGN > 0 && outassignname != NULL) {
|
|
time1 = seconds();
|
|
if (architecture == 0) {
|
|
k = 1 << ndims_tot;
|
|
}
|
|
else if (architecture > 0) {
|
|
k = mesh_dims[0] * mesh_dims[1] * mesh_dims[2];
|
|
}
|
|
assign_out(nvtxs, assignment, k, outassignname);
|
|
print_assign_time += seconds() - time1;
|
|
}
|
|
|
|
if (OUTPUT_METRICS != 0) { /* Compute graph metrics of partition. */
|
|
time1 = seconds();
|
|
if (graph != NULL) {
|
|
if (PRINT_HEADERS) {
|
|
printf("\n\n Partitioning Results\n");
|
|
if (outfile != NULL) {
|
|
fprintf(outfile, "\n\n Partitioning Results\n");
|
|
}
|
|
}
|
|
|
|
countup(graph, nvtxs, assignment, ndims, architecture, ndims_tot, mesh_dims, OUTPUT_METRICS,
|
|
outfile, using_ewgts);
|
|
}
|
|
count_time += seconds() - time1;
|
|
}
|
|
|
|
/* Invoke communication simulator? */
|
|
/*
|
|
if (graph != NULL) {
|
|
if (SIMULATOR > 0) {
|
|
simulate(graph, nvtxs, ndims, architecture, ndims_tot,
|
|
mesh_dims, assignment, using_ewgts, outfile);
|
|
}
|
|
}
|
|
*/
|
|
|
|
End_Label:
|
|
|
|
if (vwsqrt != NULL) {
|
|
sfree(vwsqrt);
|
|
}
|
|
if (SQRTS != NULL) {
|
|
sfree(SQRTS);
|
|
}
|
|
|
|
/* Turn perturbation back on for next invocation. */
|
|
if (ndims == 1) {
|
|
PERTURB = old_perturb;
|
|
}
|
|
NSQRTS = old_nsqrts;
|
|
|
|
total_time += seconds() - start_time;
|
|
if (outfile != NULL) {
|
|
time_out(outfile);
|
|
fclose(outfile);
|
|
}
|
|
Output_File = NULL;
|
|
|
|
return (0);
|
|
}
|
|
|