/* 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 <stdio.h>
#include <string.h>
#include <math.h>
#include "defs.h"
#include "params.h"
#include "structs.h"
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(graph, nvtxs, nedges, using_vwgts, using_ewgts, igeom, coords,
outassignname, outfilename,
assignment, goal,
architecture, ndims_tot, mesh_dims,
global_method, local_method, rqi_flag, vmax, ndims,
eigtol, seed)
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 */
short *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_METRICS; /* whether to tally and display cost metrics */
extern int OUTPUT_ASSIGN; /* print assignment to a file? */
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 RAND_MAXIMUM; /* largest value returnable by rand() */
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 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 */
short 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; /* saves original pertubation flag */
int i, j, k; /* loop counters */
double seconds();
void setrandom();
double *smalloc_ret();
int check_input(), sfree(), refine_part();
void setrandom(), makevwsqrt(), balance(), countup();
void force_internal(), sequence(), reflect_input();
void machine_params(), assign_out(), refine_map();
void time_out(), time_kernels(), strout();
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;
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;
else append = FALSE;
fclose(outfile);
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, &RAND_MAXIMUM);
if (DEBUG_MACH_PARAMS > 0) {
printf("Machine parameters:\n");
printf(" DOUBLE_EPSILON = %e\n", DOUBLE_EPSILON);
printf(" DOUBLE_MAX = %e\n", DOUBLE_MAX);
printf(" RAND_MAXIMUM = %d\n\n", RAND_MAXIMUM);
}
nsets = (1 << ndims);
old_nsqrts = NSQRTS;
if (nvtxs < NSQRTS && !using_vwgts) {
NSQRTS = nvtxs;
}
SQRTS = (double *) smalloc_ret((unsigned) (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 = (double *) smalloc_ret((unsigned) (nvtxs + 1) * sizeof(double));
if (vwsqrt == NULL) {
strout("ERROR: No space to allocate vwsqrt\n");
sfree((char *) 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++) {
if (KL_METRIC == 2) { /* Count hypercube hops */
hop_mtx[i][j] = 0;
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;
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 (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((char *) vwsqrt);
if (SQRTS != NULL)
sfree((char *) SQRTS);
/* Turn perturbation back on for next invocation. */
if (ndims == 1) {
PERTURB = old_perturb;
}
NSQRTS = old_nsqrts;
total_time += seconds() - start_time;
time_out(outfile);
if (outfile != NULL) fclose(outfile);
Output_File = NULL;
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1