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.
846 lines
26 KiB
846 lines
26 KiB
2 years ago
|
/*!
|
||
|
\file
|
||
|
\brief A simple program to try out some graph routines
|
||
|
|
||
|
\date 6/12/2008
|
||
|
\author George
|
||
|
\version \verbatim $Id: gkgraph.c 17700 2014-09-27 18:10:02Z karypis $ \endverbatim
|
||
|
*/
|
||
|
|
||
|
#include <GKlib.h>
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! Data structures for the code */
|
||
|
/*************************************************************************/
|
||
|
typedef struct {
|
||
|
int lnbits;
|
||
|
int cnbits;
|
||
|
int type;
|
||
|
int niter;
|
||
|
float eps;
|
||
|
float lamda;
|
||
|
int nosort;
|
||
|
int write;
|
||
|
|
||
|
char *infile;
|
||
|
char *outfile;
|
||
|
} params_t;
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! Constants */
|
||
|
/*************************************************************************/
|
||
|
#define CMD_NITER 1
|
||
|
#define CMD_EPS 2
|
||
|
#define CMD_LAMDA 3
|
||
|
#define CMD_TYPE 4
|
||
|
#define CMD_NOSORT 5
|
||
|
#define CMD_WRITE 6
|
||
|
#define CMD_LNBITS 7
|
||
|
#define CMD_CNBITS 8
|
||
|
#define CMD_HELP 10
|
||
|
|
||
|
#define CLINE32 16
|
||
|
#define CLINE64 8
|
||
|
#define MAXRCLOCKSPAN (1<<20)
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! Local variables */
|
||
|
/*************************************************************************/
|
||
|
static struct gk_option long_options[] = {
|
||
|
{"lnbits", 1, 0, CMD_LNBITS},
|
||
|
{"cnbits", 1, 0, CMD_CNBITS},
|
||
|
{"type", 1, 0, CMD_TYPE},
|
||
|
{"niter", 1, 0, CMD_NITER},
|
||
|
{"lamda", 1, 0, CMD_LAMDA},
|
||
|
{"eps", 1, 0, CMD_EPS},
|
||
|
{"nosort", 0, 0, CMD_NOSORT},
|
||
|
{"write", 0, 0, CMD_WRITE},
|
||
|
{"help", 0, 0, CMD_HELP},
|
||
|
{0, 0, 0, 0}
|
||
|
};
|
||
|
|
||
|
|
||
|
/*-------------------------------------------------------------------*/
|
||
|
/* Mini help */
|
||
|
/*-------------------------------------------------------------------*/
|
||
|
static char helpstr[][100] = {
|
||
|
" ",
|
||
|
"Usage: gkgraph [options] <graph-file> [<out-file>]",
|
||
|
" ",
|
||
|
" Required parameters",
|
||
|
" graph-file",
|
||
|
" The name of the file storing the graph. The file is in ",
|
||
|
" Metis' graph format.",
|
||
|
" ",
|
||
|
" Optional parameters",
|
||
|
" -niter=int",
|
||
|
" Specifies the maximum number of iterations. [default: 100]",
|
||
|
" ",
|
||
|
" -lnbits=int",
|
||
|
" Specifies the number of address bits indexing the cacheline. [default: 6]",
|
||
|
" ",
|
||
|
" -cnbits=int",
|
||
|
" Specifies the number of address bits indexing the cache. [default: 13]",
|
||
|
" ",
|
||
|
" -lamda=float",
|
||
|
" Specifies the follow-the-adjacent-links probability. [default: 0.80]",
|
||
|
" ",
|
||
|
" -eps=float",
|
||
|
" Specifies the error tollerance. [default: 1e-10]",
|
||
|
" ",
|
||
|
" -nosort",
|
||
|
" Does not sort the adjacency lists.",
|
||
|
" ",
|
||
|
" -write",
|
||
|
" Output the reordered graphs.",
|
||
|
" ",
|
||
|
" -help",
|
||
|
" Prints this message.",
|
||
|
""
|
||
|
};
|
||
|
|
||
|
static char shorthelpstr[][100] = {
|
||
|
" ",
|
||
|
" Usage: gkgraph [options] <graph-file> [<out-file>]",
|
||
|
" use 'gkgraph -help' for a summary of the options.",
|
||
|
""
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! Function prototypes */
|
||
|
/*************************************************************************/
|
||
|
void test_spmv(params_t *params);
|
||
|
void test_tc(params_t *params);
|
||
|
void sort_adjacencies(params_t *params, gk_graph_t *graph);
|
||
|
double compute_spmvstats(params_t *params, gk_graph_t *graph);
|
||
|
double compute_tcstats(params_t *params, gk_graph_t *graph, int32_t *iperm);
|
||
|
int32_t *reorder_degrees(params_t *params, gk_graph_t *graph);
|
||
|
int32_t *reorder_freqlpn(params_t *params, gk_graph_t *graph);
|
||
|
int32_t *reorder_freqlpn_db(params_t *params, gk_graph_t *graph);
|
||
|
int32_t *reorder_minlpn(params_t *params, gk_graph_t *graph);
|
||
|
int32_t *reorder_minlpn_db(params_t *params, gk_graph_t *graph);
|
||
|
void print_init_info(params_t *params, gk_graph_t *graph);
|
||
|
void print_final_info(params_t *params);
|
||
|
params_t *parse_cmdline(int argc, char *argv[]);
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! the entry point */
|
||
|
/**************************************************************************/
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
params_t *params;
|
||
|
|
||
|
/* get command-line options */
|
||
|
params = parse_cmdline(argc, argv);
|
||
|
|
||
|
test_tc(params);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! various spmv-related tests */
|
||
|
/**************************************************************************/
|
||
|
void test_spmv(params_t *params)
|
||
|
{
|
||
|
ssize_t i, j, v;
|
||
|
gk_graph_t *graph, *pgraph;
|
||
|
int32_t *perm;
|
||
|
|
||
|
/* read the data */
|
||
|
graph = gk_graph_Read(params->infile, GK_GRAPH_FMT_METIS, -1, -1, 0, 0, 0);
|
||
|
|
||
|
/* display some basic stats */
|
||
|
print_init_info(params, graph);
|
||
|
|
||
|
sort_adjacencies(params, graph);
|
||
|
if (params->write) gk_graph_Write(graph, "original.ijv", GK_GRAPH_FMT_IJV, 1);
|
||
|
printf("Input SPMV HitRate: %.4lf\n", compute_spmvstats(params, graph));
|
||
|
|
||
|
|
||
|
v = RandomInRange(graph->nvtxs);
|
||
|
gk_graph_ComputeBFSOrdering(graph, v, &perm, NULL);
|
||
|
pgraph = gk_graph_Reorder(graph, perm, NULL);
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
if (params->write) gk_graph_Write(pgraph, "bfs.ijv", GK_GRAPH_FMT_IJV, 1);
|
||
|
printf("BFS SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph));
|
||
|
gk_graph_Free(&pgraph);
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
|
||
|
|
||
|
perm = reorder_degrees(params, graph);
|
||
|
pgraph = gk_graph_Reorder(graph, perm, NULL);
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
if (params->write) gk_graph_Write(pgraph, "degrees.ijv", GK_GRAPH_FMT_IJV, 1);
|
||
|
printf("Degrees SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph));
|
||
|
gk_graph_Free(&pgraph);
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
|
||
|
|
||
|
perm = reorder_freqlpn(params, graph);
|
||
|
pgraph = gk_graph_Reorder(graph, perm, NULL);
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
if (params->write) gk_graph_Write(pgraph, "freqlpn.ijv", GK_GRAPH_FMT_IJV, 1);
|
||
|
printf("FreqLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph));
|
||
|
gk_graph_Free(&pgraph);
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
|
||
|
perm = reorder_freqlpn_db(params, graph);
|
||
|
pgraph = gk_graph_Reorder(graph, perm, NULL);
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
if (params->write) gk_graph_Write(pgraph, "freqlpn-db.ijv", GK_GRAPH_FMT_IJV, 1);
|
||
|
printf("DBFreqLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph));
|
||
|
gk_graph_Free(&pgraph);
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
|
||
|
perm = reorder_minlpn(params, graph);
|
||
|
pgraph = gk_graph_Reorder(graph, perm, NULL);
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
if (params->write) gk_graph_Write(pgraph, "minlpn.ijv", GK_GRAPH_FMT_IJV, 1);
|
||
|
printf("MinLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph));
|
||
|
gk_graph_Free(&pgraph);
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
|
||
|
perm = reorder_minlpn_db(params, graph);
|
||
|
pgraph = gk_graph_Reorder(graph, perm, NULL);
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
if (params->write) gk_graph_Write(pgraph, "minlpn-db.ijv", GK_GRAPH_FMT_IJV, 1);
|
||
|
printf("DBMinLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph));
|
||
|
gk_graph_Free(&pgraph);
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
|
||
|
gk_graph_Free(&graph);
|
||
|
|
||
|
print_final_info(params);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! various tc-related tests */
|
||
|
/**************************************************************************/
|
||
|
void test_tc(params_t *params)
|
||
|
{
|
||
|
ssize_t i, j, v;
|
||
|
gk_graph_t *graph, *pgraph;
|
||
|
int32_t *perm, *iperm;
|
||
|
|
||
|
/* read the data */
|
||
|
graph = gk_graph_Read(params->infile, GK_GRAPH_FMT_METIS, -1, -1, 0, 0, 0);
|
||
|
|
||
|
/* display some basic stats */
|
||
|
print_init_info(params, graph);
|
||
|
|
||
|
perm = reorder_degrees(params, graph);
|
||
|
pgraph = gk_graph_Reorder(graph, perm, NULL);
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
iperm = gk_i32incset(graph->nvtxs, 0, gk_i32malloc(graph->nvtxs, "iperm"));
|
||
|
printf("Degrees TC HitRate: %.4lf\n", compute_tcstats(params, pgraph, iperm));
|
||
|
|
||
|
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
v = RandomInRange(pgraph->nvtxs);
|
||
|
gk_graph_ComputeBFSOrdering(pgraph, v, &perm, NULL);
|
||
|
for (i=0; i<graph->nvtxs; i++) iperm[perm[i]] = i;
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
printf("BFS TC HitRate: %.4lf\n", compute_tcstats(params, pgraph, iperm));
|
||
|
|
||
|
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
perm = reorder_freqlpn(params, pgraph);
|
||
|
for (i=0; i<graph->nvtxs; i++) iperm[perm[i]] = i;
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
printf("FreqLabelPropN TC HitRate: %.4lf\n", compute_tcstats(params, pgraph, iperm));
|
||
|
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
perm = reorder_freqlpn_db(params, pgraph);
|
||
|
for (i=0; i<graph->nvtxs; i++) iperm[perm[i]] = i;
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
printf("DBFreqLabelPropN TC HitRate: %.4lf\n", compute_tcstats(params, pgraph, iperm));
|
||
|
|
||
|
|
||
|
#ifdef XXX
|
||
|
perm = reorder_minlpn(params, graph);
|
||
|
pgraph = gk_graph_Reorder(graph, perm, NULL);
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
if (params->write) gk_graph_Write(pgraph, "minlpn.ijv", GK_GRAPH_FMT_IJV, 1);
|
||
|
printf("MinLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph));
|
||
|
gk_graph_Free(&pgraph);
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
|
||
|
perm = reorder_minlpn_db(params, graph);
|
||
|
pgraph = gk_graph_Reorder(graph, perm, NULL);
|
||
|
sort_adjacencies(params, pgraph);
|
||
|
if (params->write) gk_graph_Write(pgraph, "minlpn-db.ijv", GK_GRAPH_FMT_IJV, 1);
|
||
|
printf("DBMinLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph));
|
||
|
gk_graph_Free(&pgraph);
|
||
|
gk_free((void **)&perm, LTERM);
|
||
|
#endif
|
||
|
|
||
|
gk_free((void **)&iperm, LTERM);
|
||
|
gk_graph_Free(&graph);
|
||
|
|
||
|
print_final_info(params);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This function sorts the adjacency lists of the vertices in increasing
|
||
|
order.
|
||
|
*/
|
||
|
/*************************************************************************/
|
||
|
void sort_adjacencies(params_t *params, gk_graph_t *graph)
|
||
|
{
|
||
|
uint64_t i, nvtxs;
|
||
|
ssize_t *xadj;
|
||
|
int32_t *adjncy;
|
||
|
|
||
|
if (params->nosort)
|
||
|
return;
|
||
|
|
||
|
nvtxs = graph->nvtxs;
|
||
|
xadj = graph->xadj;
|
||
|
adjncy = graph->adjncy;
|
||
|
|
||
|
for (i=0; i<nvtxs; i++)
|
||
|
gk_i32sorti(xadj[i+1]-xadj[i], adjncy+xadj[i]);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This function analyzes the cache locality of an SPMV operation using
|
||
|
GKlib's cache simulator and returns the cache's hit rate.
|
||
|
*/
|
||
|
/*************************************************************************/
|
||
|
double compute_spmvstats(params_t *params, gk_graph_t *graph)
|
||
|
{
|
||
|
uint64_t i, nvtxs;
|
||
|
ssize_t *xadj;
|
||
|
int32_t *adjncy, *vec;
|
||
|
|
||
|
gk_cache_t *cache = gk_cacheCreate(16, params->lnbits, params->cnbits); /* 8MB total; i7 spec */
|
||
|
|
||
|
nvtxs = graph->nvtxs;
|
||
|
xadj = graph->xadj;
|
||
|
adjncy = graph->adjncy;
|
||
|
|
||
|
vec = gk_i32malloc(nvtxs, "vec");
|
||
|
for (i=0; i<xadj[nvtxs]; i++) {
|
||
|
gk_cacheLoad(cache, (size_t)(&adjncy[i]));
|
||
|
gk_cacheLoad(cache, (size_t)(&vec[adjncy[i]]));
|
||
|
}
|
||
|
|
||
|
gk_free((void **)&vec, LTERM);
|
||
|
|
||
|
double hitrate = gk_cacheGetHitRate(cache);
|
||
|
gk_cacheDestroy(&cache);
|
||
|
|
||
|
return hitrate;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! The hash-map-based triangle-counting routine that uses the JIK
|
||
|
triangle enumeration scheme.
|
||
|
|
||
|
This version implements the following:
|
||
|
- It does not store location information in L
|
||
|
- Reverts the order within U's adjancency lists to allow ++ traversal
|
||
|
*/
|
||
|
/*************************************************************************/
|
||
|
double compute_tcstats(params_t *params, gk_graph_t *graph, int32_t *iperm)
|
||
|
{
|
||
|
int32_t vi, vj, vjj, vk, vl, nvtxs;
|
||
|
ssize_t ei, eiend, eistart, ej, ejend, ejstart;
|
||
|
int64_t ntriangles;
|
||
|
ssize_t *xadj, *uxadj;
|
||
|
int32_t *adjncy;
|
||
|
int32_t l, hmsize, *hmap;
|
||
|
|
||
|
gk_cache_t *cache = gk_cacheCreate(16, params->lnbits, params->cnbits);
|
||
|
|
||
|
nvtxs = graph->nvtxs;
|
||
|
xadj = graph->xadj;
|
||
|
adjncy = graph->adjncy;
|
||
|
|
||
|
/* determine the starting location of the upper trianglular part */
|
||
|
uxadj = gk_zmalloc(nvtxs, "uxadj");
|
||
|
for (vi=0; vi<nvtxs; vi++) {
|
||
|
for (ei=xadj[vi], eiend=xadj[vi+1]; ei<eiend && adjncy[ei]<vi; ei++);
|
||
|
uxadj[vi] = ei;
|
||
|
/* flip the order of Adj(vi)'s upper triangular adjacency list */
|
||
|
for (ej=xadj[vi+1]-1; ei<ej; ei++, ej--) {
|
||
|
vj = adjncy[ei];
|
||
|
adjncy[ei] = adjncy[ej];
|
||
|
adjncy[ej] = vj;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* determine the size of the hash-map and convert it into a format
|
||
|
that is compatible with a bitwise AND operation */
|
||
|
for (hmsize=0, vi=0; vi<nvtxs; vi++)
|
||
|
hmsize = gk_max(hmsize, (int32_t)(xadj[vi+1]-uxadj[vi]));
|
||
|
for (l=1; hmsize>(1<<l); l++);
|
||
|
hmsize = (1<<(l+4))-1;
|
||
|
hmap = gk_i32smalloc(hmsize+1, 0, "hmap");
|
||
|
|
||
|
for (ntriangles=0, vjj=0; vjj<nvtxs; vjj++) {
|
||
|
vj = iperm[vjj];
|
||
|
|
||
|
gk_cacheLoad(cache, (size_t)(&xadj[vj]));
|
||
|
gk_cacheLoad(cache, (size_t)(&xadj[vj+1]));
|
||
|
gk_cacheLoad(cache, (size_t)(&uxadj[vj]));
|
||
|
|
||
|
if (xadj[vj+1]-uxadj[vj] == 0 || uxadj[vj] == xadj[vj])
|
||
|
continue;
|
||
|
|
||
|
/* hash Adj(vj) */
|
||
|
gk_cacheLoad(cache, (size_t)(&uxadj[vj]));
|
||
|
gk_cacheLoad(cache, (size_t)(&xadj[vj+1]));
|
||
|
for (ej=uxadj[vj], ejend=xadj[vj+1]; ej<ejend; ej++) {
|
||
|
gk_cacheLoad(cache, (size_t)(&adjncy[ej]));
|
||
|
vk = adjncy[ej];
|
||
|
for (l=(vk&hmsize);
|
||
|
gk_cacheLoad(cache, (size_t)(&hmap[l])) && hmap[l]!=0;
|
||
|
l=((l+1)&hmsize));
|
||
|
hmap[l] = vk;
|
||
|
}
|
||
|
|
||
|
/* find intersections */
|
||
|
gk_cacheLoad(cache, (size_t)(&xadj[vj]));
|
||
|
gk_cacheLoad(cache, (size_t)(&uxadj[vj]));
|
||
|
for (ej=xadj[vj], ejend=uxadj[vj]; ej<ejend; ej++) {
|
||
|
gk_cacheLoad(cache, (size_t)(&adjncy[ej]));
|
||
|
gk_cacheLoad(cache, (size_t)(&uxadj[vi]));
|
||
|
vi = adjncy[ej];
|
||
|
for (ei=uxadj[vi]; gk_cacheLoad(cache, (size_t)(&adjncy[ei])) && adjncy[ei]>vj; ei++) {
|
||
|
vk = adjncy[ei];
|
||
|
for (l=vk&hmsize;
|
||
|
gk_cacheLoad(cache, (size_t)(&hmap[l])) && hmap[l]!=0 && hmap[l]!=vk;
|
||
|
l=((l+1)&hmsize));
|
||
|
gk_cacheLoad(cache, (size_t)(&hmap[l]));
|
||
|
if (hmap[l] == vk)
|
||
|
ntriangles++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* reset hash */
|
||
|
gk_cacheLoad(cache, (size_t)(&uxadj[vj]));
|
||
|
gk_cacheLoad(cache, (size_t)(&xadj[vj+1]));
|
||
|
for (ej=uxadj[vj], ejend=xadj[vj+1]; ej<ejend; ej++) {
|
||
|
gk_cacheLoad(cache, (size_t)(&adjncy[ej]));
|
||
|
vk = adjncy[ej];
|
||
|
for (l=(vk&hmsize);
|
||
|
gk_cacheLoad(cache, (size_t)(&hmap[l])) && hmap[l]!=vk;
|
||
|
l=((l+1)&hmsize));
|
||
|
hmap[l] = 0;
|
||
|
}
|
||
|
}
|
||
|
printf("& compatible hmsize: %"PRId32" #triangles: %"PRIu64"\n", hmsize, ntriangles);
|
||
|
|
||
|
gk_free((void **)&uxadj, &hmap, LTERM);
|
||
|
|
||
|
//printf("%zd %zd\n", (ssize_t)cache->nhits, (ssize_t)cache->clock);
|
||
|
|
||
|
double hitrate = gk_cacheGetHitRate(cache);
|
||
|
gk_cacheDestroy(&cache);
|
||
|
|
||
|
return hitrate;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This function computes an increasing degree ordering
|
||
|
*/
|
||
|
/*************************************************************************/
|
||
|
int32_t *reorder_degrees(params_t *params, gk_graph_t *graph)
|
||
|
{
|
||
|
int i, v, u, nvtxs, range;
|
||
|
ssize_t j, *xadj;
|
||
|
int32_t *counts, *perm;
|
||
|
|
||
|
nvtxs = graph->nvtxs;
|
||
|
xadj = graph->xadj;
|
||
|
|
||
|
for (range=0, i=0; i<nvtxs; i++)
|
||
|
range = gk_max(range, xadj[i+1]-xadj[i]);
|
||
|
range++;
|
||
|
|
||
|
counts = gk_i32smalloc(range+1, 0, "counts");
|
||
|
for (i=0; i<nvtxs; i++)
|
||
|
counts[xadj[i+1]-xadj[i]]++;
|
||
|
MAKECSR(i, range, counts);
|
||
|
|
||
|
perm = gk_i32malloc(nvtxs, "perm");
|
||
|
for (i=0; i<nvtxs; i++)
|
||
|
perm[i] = counts[xadj[i+1]-xadj[i]]++;
|
||
|
|
||
|
gk_free((void **)&counts, LTERM);
|
||
|
|
||
|
return perm;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This function re-orders the graph by:
|
||
|
- performing a fixed number of most-popular label propagation iterations
|
||
|
- locally renumbers the vertices with the same label
|
||
|
*/
|
||
|
/*************************************************************************/
|
||
|
int32_t *reorder_freqlpn(params_t *params, gk_graph_t *graph)
|
||
|
{
|
||
|
int32_t i, ii, k, nvtxs, maxlbl;
|
||
|
ssize_t j, *xadj;
|
||
|
int32_t *adjncy, *labels, *freq, *perm;
|
||
|
gk_i32kv_t *cand;
|
||
|
|
||
|
nvtxs = graph->nvtxs;
|
||
|
xadj = graph->xadj;
|
||
|
adjncy = graph->adjncy;
|
||
|
|
||
|
labels = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "labels"));
|
||
|
freq = gk_i32smalloc(nvtxs, 0, "freq");
|
||
|
perm = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "perm"));
|
||
|
|
||
|
for (k=0; k<params->niter; k++) {
|
||
|
gk_i32randArrayPermuteFine(nvtxs, perm, 0);
|
||
|
for (ii=0; ii<nvtxs; ii++) {
|
||
|
i = perm[ii];
|
||
|
maxlbl = labels[adjncy[xadj[i]]];
|
||
|
freq[maxlbl] = 1;
|
||
|
for (j=xadj[i]+1; j<xadj[i+1]; j++) {
|
||
|
freq[labels[adjncy[j]]]++;
|
||
|
if (freq[maxlbl] < freq[labels[adjncy[j]]])
|
||
|
maxlbl = labels[adjncy[j]];
|
||
|
else if (freq[maxlbl] == freq[labels[adjncy[j]]]) {
|
||
|
if (RandomInRange(2))
|
||
|
maxlbl = labels[adjncy[j]];
|
||
|
}
|
||
|
}
|
||
|
for (j=xadj[i]; j<xadj[i+1]; j++)
|
||
|
freq[labels[adjncy[j]]] = 0;
|
||
|
labels[i] = maxlbl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cand = gk_i32kvmalloc(nvtxs, "cand");
|
||
|
for (i=0; i<nvtxs; i++) {
|
||
|
cand[i].key = labels[i];
|
||
|
cand[i].val = i;
|
||
|
}
|
||
|
gk_i32kvsorti(nvtxs, cand);
|
||
|
|
||
|
for (i=0; i<nvtxs; i++)
|
||
|
perm[cand[i].val] = i;
|
||
|
|
||
|
gk_free((void **)&labels, &freq, &cand, LTERM);
|
||
|
|
||
|
return perm;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This function re-orders the graph by:
|
||
|
- performing a fixed number of most-popular label propagation iterations
|
||
|
- restricts that propagation to take place within similar degree buckets
|
||
|
of vertices
|
||
|
- locally renumbers the vertices with the same label
|
||
|
*/
|
||
|
/*************************************************************************/
|
||
|
int32_t *reorder_freqlpn_db(params_t *params, gk_graph_t *graph)
|
||
|
{
|
||
|
int32_t i, ii, k, nvtxs, maxlbl;
|
||
|
ssize_t j, *xadj;
|
||
|
int32_t *adjncy, *labels, *freq, *perm, *dbucket;
|
||
|
gk_i32kv_t *cand;
|
||
|
|
||
|
nvtxs = graph->nvtxs;
|
||
|
xadj = graph->xadj;
|
||
|
adjncy = graph->adjncy;
|
||
|
|
||
|
labels = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "labels"));
|
||
|
freq = gk_i32smalloc(nvtxs, 0, "freq");
|
||
|
perm = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "perm"));
|
||
|
dbucket = gk_i32malloc(nvtxs, "dbucket");
|
||
|
|
||
|
for (i=0; i<nvtxs; i++)
|
||
|
dbucket[i] = ((xadj[i+1]-xadj[i])>>3);
|
||
|
|
||
|
for (k=0; k<params->niter; k++) {
|
||
|
gk_i32randArrayPermuteFine(nvtxs, perm, 0);
|
||
|
for (ii=0; ii<nvtxs; ii++) {
|
||
|
i = perm[ii];
|
||
|
maxlbl = labels[i];
|
||
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
||
|
if (dbucket[i] != dbucket[adjncy[j]])
|
||
|
continue;
|
||
|
|
||
|
freq[labels[adjncy[j]]]++;
|
||
|
if (freq[maxlbl] < freq[labels[adjncy[j]]])
|
||
|
maxlbl = labels[adjncy[j]];
|
||
|
else if (freq[maxlbl] == freq[labels[adjncy[j]]]) {
|
||
|
if (RandomInRange(2))
|
||
|
maxlbl = labels[adjncy[j]];
|
||
|
}
|
||
|
}
|
||
|
for (j=xadj[i]; j<xadj[i+1]; j++)
|
||
|
freq[labels[adjncy[j]]] = 0;
|
||
|
labels[i] = maxlbl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cand = gk_i32kvmalloc(nvtxs, "cand");
|
||
|
for (i=0; i<nvtxs; i++) {
|
||
|
cand[i].key = labels[i];
|
||
|
cand[i].val = i;
|
||
|
}
|
||
|
gk_i32kvsorti(nvtxs, cand);
|
||
|
|
||
|
for (i=0; i<nvtxs; i++)
|
||
|
perm[cand[i].val] = i;
|
||
|
|
||
|
gk_free((void **)&labels, &freq, &dbucket, &cand, LTERM);
|
||
|
|
||
|
return perm;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This function re-orders the graph by:
|
||
|
- performing a fixed number of min-label propagation iterations
|
||
|
- locally renumbers the vertices with the same label
|
||
|
*/
|
||
|
/*************************************************************************/
|
||
|
int32_t *reorder_minlpn(params_t *params, gk_graph_t *graph)
|
||
|
{
|
||
|
int32_t i, ii, k, nvtxs, minlbl;
|
||
|
ssize_t j, *xadj;
|
||
|
int32_t *adjncy, *labels, *perm;
|
||
|
gk_i32kv_t *cand;
|
||
|
|
||
|
nvtxs = graph->nvtxs;
|
||
|
xadj = graph->xadj;
|
||
|
adjncy = graph->adjncy;
|
||
|
|
||
|
labels = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "labels"));
|
||
|
perm = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "perm"));
|
||
|
|
||
|
for (k=0; k<params->niter; k++) {
|
||
|
for (i=0; i<nvtxs; i++) {
|
||
|
minlbl = labels[i];
|
||
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
||
|
if (minlbl > labels[adjncy[j]])
|
||
|
minlbl = labels[adjncy[j]];
|
||
|
}
|
||
|
labels[i] = minlbl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cand = gk_i32kvmalloc(nvtxs, "cand");
|
||
|
for (i=0; i<nvtxs; i++) {
|
||
|
cand[i].key = labels[i];
|
||
|
cand[i].val = i;
|
||
|
}
|
||
|
gk_i32kvsorti(nvtxs, cand);
|
||
|
|
||
|
for (i=0; i<nvtxs; i++) {
|
||
|
perm[cand[i].val] = i;
|
||
|
//if (i>0 && cand[i].key != cand[i-1].key)
|
||
|
// printf("%10d %10d\n", i-1, cand[i-1].key);
|
||
|
}
|
||
|
//printf("%10d %10d\n", i-1, cand[i-1].key);
|
||
|
|
||
|
gk_free((void **)&labels, &cand, LTERM);
|
||
|
|
||
|
return perm;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This function re-orders the graph by:
|
||
|
- performing a fixed number of min-label propagation iterations
|
||
|
- restricts that propagation to take place within similar degree buckets
|
||
|
of vertices
|
||
|
- locally renumbers the vertices with the same label
|
||
|
*/
|
||
|
/*************************************************************************/
|
||
|
int32_t *reorder_minlpn_db(params_t *params, gk_graph_t *graph)
|
||
|
{
|
||
|
int32_t i, ii, k, nvtxs, minlbl;
|
||
|
ssize_t j, *xadj;
|
||
|
int32_t *adjncy, *labels, *perm, *dbucket;
|
||
|
gk_i32kv_t *cand;
|
||
|
|
||
|
nvtxs = graph->nvtxs;
|
||
|
xadj = graph->xadj;
|
||
|
adjncy = graph->adjncy;
|
||
|
|
||
|
labels = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "labels"));
|
||
|
perm = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "perm"));
|
||
|
dbucket = gk_i32malloc(nvtxs, "dbucket");
|
||
|
|
||
|
for (i=0; i<nvtxs; i++)
|
||
|
dbucket[i] = ((xadj[i+1]-xadj[i])>>3);
|
||
|
|
||
|
for (k=0; k<params->niter; k++) {
|
||
|
for (i=0; i<nvtxs; i++) {
|
||
|
minlbl = labels[i];
|
||
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
||
|
if (dbucket[i] != dbucket[adjncy[j]])
|
||
|
continue;
|
||
|
|
||
|
if (minlbl > labels[adjncy[j]])
|
||
|
minlbl = labels[adjncy[j]];
|
||
|
}
|
||
|
labels[i] = minlbl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cand = gk_i32kvmalloc(nvtxs, "cand");
|
||
|
for (i=0; i<nvtxs; i++) {
|
||
|
cand[i].key = labels[i];
|
||
|
cand[i].val = i;
|
||
|
}
|
||
|
gk_i32kvsorti(nvtxs, cand);
|
||
|
|
||
|
for (i=0; i<nvtxs; i++) {
|
||
|
perm[cand[i].val] = i;
|
||
|
//if (i>0 && cand[i].key != cand[i-1].key)
|
||
|
// printf("%10d %10d\n", i-1, cand[i-1].key);
|
||
|
}
|
||
|
//printf("%10d %10d\n", i-1, cand[i-1].key);
|
||
|
|
||
|
gk_free((void **)&labels, &dbucket, &cand, LTERM);
|
||
|
|
||
|
return perm;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This function prints run parameters */
|
||
|
/*************************************************************************/
|
||
|
void print_init_info(params_t *params, gk_graph_t *graph)
|
||
|
{
|
||
|
printf("*******************************************************************************\n");
|
||
|
printf(" gkgraph\n\n");
|
||
|
printf("Graph Information ----------------------------------------------------------\n");
|
||
|
printf(" input file=%s, [%d, %zd]\n",
|
||
|
params->infile, graph->nvtxs, graph->xadj[graph->nvtxs]);
|
||
|
|
||
|
printf("\n");
|
||
|
printf("Options --------------------------------------------------------------------\n");
|
||
|
printf(" lnbits=%d, cnbits=%d, type=%d, niter=%d, lamda=%f, eps=%e\n",
|
||
|
params->lnbits, params->cnbits, params->type, params->niter,
|
||
|
params->lamda, params->eps);
|
||
|
|
||
|
printf("\n");
|
||
|
printf("Working... -----------------------------------------------------------------\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This function prints final statistics */
|
||
|
/*************************************************************************/
|
||
|
void print_final_info(params_t *params)
|
||
|
{
|
||
|
printf("\n");
|
||
|
printf("Memory Usage Information -----------------------------------------------------\n");
|
||
|
printf(" Maximum memory used: %10zd bytes\n", (ssize_t) gk_GetMaxMemoryUsed());
|
||
|
printf(" Current memory used: %10zd bytes\n", (ssize_t) gk_GetCurMemoryUsed());
|
||
|
printf("********************************************************************************\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/*! This is the entry point of the command-line argument parser */
|
||
|
/*************************************************************************/
|
||
|
params_t *parse_cmdline(int argc, char *argv[])
|
||
|
{
|
||
|
int i;
|
||
|
int c, option_index;
|
||
|
params_t *params;
|
||
|
|
||
|
params = (params_t *)gk_malloc(sizeof(params_t), "parse_cmdline: params");
|
||
|
|
||
|
/* initialize the params data structure */
|
||
|
params->lnbits = 6;
|
||
|
params->cnbits = 13;
|
||
|
params->type = 1;
|
||
|
params->niter = 1;
|
||
|
params->eps = 1e-10;
|
||
|
params->lamda = 0.20;
|
||
|
params->nosort = 0;
|
||
|
params->write = 0;
|
||
|
params->infile = NULL;
|
||
|
|
||
|
|
||
|
/* Parse the command line arguments */
|
||
|
while ((c = gk_getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) {
|
||
|
switch (c) {
|
||
|
case CMD_LNBITS:
|
||
|
if (gk_optarg) params->lnbits = atoi(gk_optarg);
|
||
|
break;
|
||
|
case CMD_CNBITS:
|
||
|
if (gk_optarg) params->cnbits = atoi(gk_optarg);
|
||
|
break;
|
||
|
case CMD_TYPE:
|
||
|
if (gk_optarg) params->type = atoi(gk_optarg);
|
||
|
break;
|
||
|
case CMD_NITER:
|
||
|
if (gk_optarg) params->niter = atoi(gk_optarg);
|
||
|
break;
|
||
|
case CMD_EPS:
|
||
|
if (gk_optarg) params->eps = atof(gk_optarg);
|
||
|
break;
|
||
|
case CMD_LAMDA:
|
||
|
if (gk_optarg) params->lamda = atof(gk_optarg);
|
||
|
break;
|
||
|
case CMD_NOSORT:
|
||
|
params->nosort = 1;
|
||
|
break;
|
||
|
case CMD_WRITE:
|
||
|
params->write = 1;
|
||
|
break;
|
||
|
|
||
|
case CMD_HELP:
|
||
|
for (i=0; strlen(helpstr[i]) > 0; i++)
|
||
|
printf("%s\n", helpstr[i]);
|
||
|
exit(0);
|
||
|
break;
|
||
|
case '?':
|
||
|
default:
|
||
|
printf("Illegal command-line option(s)\nUse %s -help for a summary of the options.\n", argv[0]);
|
||
|
exit(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (argc-gk_optind != 1) {
|
||
|
printf("Unrecognized parameters.");
|
||
|
for (i=0; strlen(shorthelpstr[i]) > 0; i++)
|
||
|
printf("%s\n", shorthelpstr[i]);
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
params->infile = gk_strdup(argv[gk_optind++]);
|
||
|
|
||
|
if (argc-gk_optind > 0)
|
||
|
params->outfile = gk_strdup(argv[gk_optind++]);
|
||
|
else
|
||
|
params->outfile = gk_strdup("gkgraph.out");
|
||
|
|
||
|
if (!gk_fexists(params->infile))
|
||
|
errexit("input file %s does not exist.\n", params->infile);
|
||
|
|
||
|
return params;
|
||
|
}
|
||
|
|