#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <bliss/defs.hh>
#include <bliss/graph.hh>
#include <bliss/timer.hh>
#include <bliss/utils.hh>
static const char* infilename = 0;
static bool opt_directed = false;
static bool opt_canonize = false;
static const char* opt_output_can_file = 0;
static const char* opt_splitting_heuristics = "fsm";
static bool opt_use_failure_recording = true;
static bool opt_use_component_recursion = true;
static unsigned int verbose_level = 1;
static FILE* verbstr = stdout;
#if !defined(BLISS_COMPILED_DATE)
#define BLISS_COMPILED_DATE "compiled " __DATE__
#endif
static void
version(FILE* const fp)
{
fprintf(fp,
"bliss version %s (" BLISS_COMPILED_DATE ")\n"
"Copyright (C) 2003-2015 Tommi Junttila.\n"
"\n"
"License LGPLv3+: GNU LGPL version 3 or later, <http://gnu.org/licenses/lgpl.html>.\n"
"This program comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
"and you are welcome to redistribute it under certain conditions;\n"
"see COPYING and COPYING.LESSER for details.\n"
, bliss::version
);
}
static void
usage(FILE* const fp, const char* argv0)
{
const char* program_name;
program_name = rindex(argv0, '/');
if(program_name) program_name++;
else program_name = argv0;
if(!program_name or *program_name == 0) program_name = "bliss";
fprintf(fp,
"Usage: %s [options] [<graphfile>]\n"
" Run bliss on <graphfile>.\n"
"Options:\n"
" -directed the input graph is directed\n"
" -can compute canonical form\n"
" -ocan=f compute canonical form and output it in file f\n"
" -v=N set verbose level to N [N >= 0, default: 1]\n"
" -sh=X select splitting heuristics, where X is\n"
" f first non-singleton cell\n"
" fl first largest non-singleton cell\n"
" fs first smallest non-singleton cell\n"
" fm first maximally non-trivially connected\n"
" non-singleton cell\n"
" flm first largest maximally non-trivially connected\n"
" non-singleton cell\n"
" fsm first smallest maximally non-trivially connected\n"
" non-singleton cell [default]\n"
" -fr=X use failure recording? [X=y/n, default: y]\n"
" -cr=X use component recursion? [X=y/n, default: y]\n"
" -version print the version number and exit\n"
" -help print this help and exit\n"
"\n"
,program_name
);
}
static void
parse_options(const int argc, const char** argv)
{
unsigned int tmp;
for(int i = 1; i < argc; i++)
{
if(strcmp(argv[i], "-can") == 0)
opt_canonize = true;
else if((strncmp(argv[i], "-ocan=", 6) == 0) and (strlen(argv[i]) > 6))
{
opt_canonize = true;
opt_output_can_file = argv[i]+6;
}
else if(sscanf(argv[i], "-v=%u", &tmp) == 1)
verbose_level = tmp;
else if(strcmp(argv[i], "-directed") == 0)
opt_directed = true;
else if(strcmp(argv[i], "-fr=n") == 0)
opt_use_failure_recording = false;
else if(strcmp(argv[i], "-fr=y") == 0)
opt_use_failure_recording = true;
else if(strcmp(argv[i], "-cr=n") == 0)
opt_use_component_recursion = false;
else if(strcmp(argv[i], "-cr=y") == 0)
opt_use_component_recursion = true;
else if((strncmp(argv[i], "-sh=", 4) == 0) and (strlen(argv[i]) > 4))
{
opt_splitting_heuristics = argv[i]+4;
}
else if(strcmp(argv[i], "-version") == 0)
{
version(stdout);
exit(0);
}
else if(strcmp(argv[i], "-help") == 0)
{
usage(stdout, argv[0]);
exit(0);
}
else if(argv[i][0] == '-')
{
fprintf(stderr, "Unknown command line argument `%s'\n", argv[i]);
usage(stderr, argv[0]);
exit(1);
}
else
{
if(infilename)
{
fprintf(stderr, "Too many file arguments\n");
usage(stderr, argv[0]);
exit(1);
}
else
{
infilename = argv[i];
}
}
}
}
static void
report_aut(void* param, const unsigned int n, const unsigned int* aut)
{
assert(param);
fprintf((FILE*)param, "Generator: ");
fprintf((FILE*)param, "\n");
}
static void
_fatal(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap); fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
int
main(const int argc, const char** argv)
{
bliss::Timer timer;
parse_options(argc, argv);
if(opt_directed)
{
if(strcmp(opt_splitting_heuristics, "f") == 0)
else if(strcmp(opt_splitting_heuristics, "fs") == 0)
else if(strcmp(opt_splitting_heuristics, "fl") == 0)
else if(strcmp(opt_splitting_heuristics, "fm") == 0)
else if(strcmp(opt_splitting_heuristics, "fsm") == 0)
else if(strcmp(opt_splitting_heuristics, "flm") == 0)
else
_fatal("Illegal option -sh=%s, aborting", opt_splitting_heuristics);
}
else
{
if(strcmp(opt_splitting_heuristics, "f") == 0)
else if(strcmp(opt_splitting_heuristics, "fs") == 0)
else if(strcmp(opt_splitting_heuristics, "fl") == 0)
else if(strcmp(opt_splitting_heuristics, "fm") == 0)
else if(strcmp(opt_splitting_heuristics, "fsm") == 0)
else if(strcmp(opt_splitting_heuristics, "flm") == 0)
else
_fatal("Illegal option -sh=%s, aborting", opt_splitting_heuristics);
}
FILE* infile = stdin;
if(infilename)
{
infile = fopen(infilename, "r");
if(!infile)
_fatal("Cannot not open `%s' for input, aborting", infilename);
}
if(opt_directed)
{
}
else
{
}
if(infile != stdin)
fclose(infile);
if(!g)
_fatal("Failed to read the graph, aborting");
if(verbose_level >= 2)
{
fprintf(verbstr, "Graph read in %.2f seconds\n", timer.get_duration());
fflush(verbstr);
}
if(opt_directed)
else
((
bliss::Graph*)g)->set_splitting_heuristic(shs_undirected);
if(opt_canonize == false)
{
}
else
{
const unsigned int* cl = g->
canonical_form(stats, &report_aut, stdout);
fprintf(stdout, "Canonical labeling: ");
fprintf(stdout, "\n");
if(opt_output_can_file)
{
FILE* const fp = fopen(opt_output_can_file, "w");
if(!fp)
_fatal("Cannot open '%s' for outputting the canonical form, aborting", opt_output_can_file);
fclose(fp);
delete cf;
}
}
if(verbose_level > 0 and verbstr)
if(verbose_level > 0)
{
fprintf(verbstr, "Total time:\t%.2f seconds\n", timer.get_duration());
fflush(verbstr);
}
delete g; g = 0;
return 0;
}