diff --git a/src/branch_and_cut.c b/src/branch-and-cut.c similarity index 97% rename from src/branch_and_cut.c rename to src/branch-and-cut.c index 29465a5..bbe9bc3 100644 --- a/src/branch_and_cut.c +++ b/src/branch-and-cut.c @@ -2,7 +2,7 @@ #include #include #include "lp.h" -#include "branch_and_cut.h" +#include "branch-and-cut.h" #include "util.h" #include "gtsp.h" @@ -58,8 +58,11 @@ int BNC_init_lp(struct BNC *bnc) rval = bnc->problem_init_lp(bnc->lp, bnc->problem_data); abort_if(rval, "problem_init_lp failed"); - rval = LP_write(bnc->lp, "subtour.lp"); - abort_if(rval, "LP_write failed"); + if(strlen(LP_FILENAME) > 0) + { + rval = LP_write(bnc->lp, LP_FILENAME); + abort_if(rval, "LP_write failed"); + } CLEANUP: return rval; diff --git a/src/branch_and_cut.h b/src/branch-and-cut.h similarity index 100% rename from src/branch_and_cut.h rename to src/branch-and-cut.h diff --git a/src/graph.c b/src/graph.c index 019b091..0563942 100644 --- a/src/graph.c +++ b/src/graph.c @@ -78,8 +78,6 @@ int graph_build( int b = edges[2 * i + 1]; n = &graph->nodes[a]; - n->adj[n->degree].neighbor_index = b; - n->adj[n->degree].edge_index = i; n->adj[n->degree].neighbor = &graph->nodes[b]; n->adj[n->degree].edge = &graph->edges[i]; n->degree++; @@ -87,8 +85,6 @@ int graph_build( if (!is_directed) { n = &graph->nodes[b]; - n->adj[n->degree].neighbor_index = a; - n->adj[n->degree].edge_index = i; n->adj[n->degree].neighbor = &graph->nodes[a]; n->adj[n->degree].edge = &graph->edges[i]; n->degree++; diff --git a/src/graph.h b/src/graph.h index 0b8f8b8..8a446a3 100644 --- a/src/graph.h +++ b/src/graph.h @@ -5,9 +5,6 @@ struct Adjacency { - int edge_index; - int neighbor_index; - struct Edge *edge; struct Node *neighbor; }; diff --git a/src/gtsp-comb.c b/src/gtsp-comb.c index de96883..39437af 100644 --- a/src/gtsp-comb.c +++ b/src/gtsp-comb.c @@ -67,7 +67,7 @@ static int add_comb_cut( nz++; } -#if LOG_LEVEL >= LOG_LEVEL_DEBUG +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE log_verbose("Generated cut:\n"); if (OPTIMAL_X) { @@ -341,49 +341,6 @@ static int shrink_clusters( return rval; } -static int write_shrunken_graph( - double *shrunken_x, - struct Graph *shrunken_graph, - int const cluster_count) -{ - int rval = 0; - - FILE *file = 0; - - file = fopen("gtsp-shrunken.in", "w"); - abort_if(!file, "could not open file"); - - fprintf(file, "%d %d\n", (*shrunken_graph).node_count, cluster_count); - for (int i = 0; i < (*shrunken_graph).node_count; i++) - fprintf(file, "%.2lf %.2lf %d\n", (*shrunken_graph).x_coordinates[i], - (*shrunken_graph).y_coordinates[i], i); - - fclose(file); - - file = fopen("gtsp-shrunken.out", "w"); - abort_if(!file, "could not open file"); - - int positive_edge_count = 0; - for (int i = 0; i < (*shrunken_graph).edge_count; i++) - if (shrunken_x[i] > EPSILON) - positive_edge_count++; - - fprintf(file, "%d %d\n", (*shrunken_graph).node_count, - (*shrunken_graph).edge_count); - - fprintf(file, "%d\n", positive_edge_count); - - for (int i = 0; i < (*shrunken_graph).edge_count; i++) - if (shrunken_x[i] > EPSILON) - fprintf(file, "%d %d %.4lf\n", - (*shrunken_graph).edges[i].from->index, - (*shrunken_graph).edges[i].to->index, shrunken_x[i]); - fclose(file); - - CLEANUP: - return rval; -} - int GTSP_find_comb_cuts(struct LP *lp, struct GTSP *data) { int rval = 0; @@ -415,13 +372,6 @@ int GTSP_find_comb_cuts(struct LP *lp, struct GTSP *data) rval = shrink_clusters(data, x, &shrunken_graph, shrunken_x); abort_if(rval, "shrink_clusters failed"); -#if LOG_LEVEL >= LOG_LEVEL_DEBUG - rval = write_shrunken_graph(shrunken_x, &shrunken_graph, cluster_count); - abort_if(rval, "write_shrunken_graph failed"); -#else - UNUSED(write_shrunken_graph); -#endif - teeth = (int *) malloc(cluster_count * sizeof(int)); components = (int *) malloc(cluster_count * sizeof(int)); component_sizes = (int *) malloc(cluster_count * sizeof(int)); diff --git a/src/gtsp-subtour.c b/src/gtsp-subtour.c index 1ae2aa6..0df812c 100644 --- a/src/gtsp-subtour.c +++ b/src/gtsp-subtour.c @@ -187,8 +187,11 @@ int GTSP_find_exact_subtour_cuts(struct LP *lp, struct GTSP *data) abort_if(rval, "LP_get_x failed"); #if LOG_LEVEL >= LOG_LEVEL_DEBUG - rval = GTSP_write_solution(data, "gtsp-frac.out", x); - abort_if(rval, "GTSP_write_solution failed"); + if(strlen(FRAC_SOLUTION_FILENAME) > 0) + { + rval = GTSP_write_solution(data, FRAC_SOLUTION_FILENAME, x); + abort_if(rval, "GTSP_write_solution failed"); + } #endif struct Graph digraph; diff --git a/src/gtsp.c b/src/gtsp.c index ae5b390..fb722ad 100644 --- a/src/gtsp.c +++ b/src/gtsp.c @@ -8,9 +8,7 @@ #include "gtsp-comb.h" int large_neighborhood_search( - struct Tour *tour, - struct GTSP *data, - int *tour_cost); + struct Tour *tour, struct GTSP *data, int *tour_cost); int build_edge_map(struct GTSP *gtsp, int *edge_map); @@ -274,7 +272,8 @@ int GTSP_write_problem(struct GTSP *data, char *filename) const struct Graph *graph = data->graph; - fprintf(file, "%d %d\n", graph->node_count, data->cluster_count); + fprintf(file, "%d %d %d\n", graph->node_count, data->cluster_count, + graph->edge_count); for (int i = 0; i < graph->node_count; i++) { @@ -287,15 +286,28 @@ int GTSP_write_problem(struct GTSP *data, char *filename) return rval; } +int GTSP_print_solution(struct GTSP *data, double *x) +{ + struct Edge *edges = data->graph->edges; + int edge_count = data->graph->edge_count; + + for (int i = 0; i < edge_count; i++) + if (x[i] > EPSILON) + log_info(" %-3d %-3d %8.4lf\n", edges[i].from->index, + edges[i].to->index, x[i]); + + return 0; +} + int GTSP_write_solution(struct GTSP *data, char *filename, double *x) { int rval = 0; struct Edge *edges = data->graph->edges; - int node_count = data->graph->node_count; int edge_count = data->graph->edge_count; FILE *file; + file = fopen(filename, "w"); abort_if(!file, "could not open file"); @@ -304,8 +316,6 @@ int GTSP_write_solution(struct GTSP *data, char *filename, double *x) if (x[i] > EPSILON) positive_edge_count++; - fprintf(file, "%d %d\n", node_count, edge_count); - fprintf(file, "%d\n", positive_edge_count); for (int i = 0; i < edge_count; i++) @@ -478,18 +488,17 @@ int GTSP_solution_found(struct BNC *bnc, struct GTSP *data, double *x) int rval = 0; int tour_cost; - char filename[100]; double *best_val = &bnc->best_obj_val; struct Tour *tour; tour = (struct Tour *) malloc(data->cluster_count * sizeof(struct Tour)); - sprintf(filename, "tmp/gtsp-m%d-n%d-s%d.out", data->cluster_count, - data->graph->node_count, SEED); - - log_info("Writting solution to file %s\n", filename); - rval = GTSP_write_solution(data, filename, x); - abort_if(rval, "GTSP_write_solution failed"); + if (strlen(SOLUTION_FILENAME) > 0) + { + log_info("Writing solution to file %s\n", SOLUTION_FILENAME); + rval = GTSP_write_solution(data, SOLUTION_FILENAME, x); + abort_if(rval, "GTSP_write_solution failed"); + } rval = build_tour_from_x(data, tour, x); abort_if(rval, "build_tour_from_x failed"); @@ -747,9 +756,7 @@ int two_opt(struct Tour *tour, struct GTSP *data) } int large_neighborhood_search( - struct Tour *tour, - struct GTSP *data, - int *tour_cost) + struct Tour *tour, struct GTSP *data, int *tour_cost) { int rval = 0; diff --git a/src/gtsp.h b/src/gtsp.h index ec79110..d2bfe13 100644 --- a/src/gtsp.h +++ b/src/gtsp.h @@ -3,7 +3,7 @@ #include "lp.h" #include "graph.h" -#include "branch_and_cut.h" +#include "branch-and-cut.h" struct Tour { @@ -60,6 +60,10 @@ int list_length(struct Tour * tour, struct GTSP* data); void print_list(struct Tour * tour, struct GTSP* data); +int GTSP_print_solution(struct GTSP *data, double *x); + + + int build_tour_from_x(struct GTSP *data, struct Tour *tour, double *x); int GTSP_solution_found(struct BNC *bnc, struct GTSP *data, double *x); diff --git a/src/lp.c b/src/lp.c index 906694a..8846305 100644 --- a/src/lp.c +++ b/src/lp.c @@ -384,11 +384,16 @@ int LP_get_num_cols(struct LP *lp) int LP_write(struct LP *lp, const char *fname) { int rval = 0; - char nambuf[MAX_NAME_LENGTH]; + + FILE *f = fopen(fname, "w"); + abort_iff(!f, "could not open file %s", fname); + fclose(f); + strncpy(nambuf, fname, MAX_NAME_LENGTH); nambuf[MAX_NAME_LENGTH - 1] = '\0'; + log_info("Writing LP to file %s...\n", fname); rval = CPXwriteprob(lp->cplex_env, lp->cplex_lp, nambuf, "RLP"); abort_if(rval, "CPXwriteprob failed"); diff --git a/src/main.c b/src/main.c index 6653f85..baa1fcd 100644 --- a/src/main.c +++ b/src/main.c @@ -30,6 +30,12 @@ double INITIAL_TIME = 0; int BNC_NODE_COUNT = 0; +char LP_FILENAME[100] = {0}; +char SOLUTION_FILENAME[100] = {0}; +char FRAC_SOLUTION_FILENAME[100] = {0}; +char WRITE_GRAPH_FILENAME[100] = {0}; +char STATS_FILENAME[100] = {0}; + static int input_node_count = -1; static int input_cluster_count = -1; static int grid_size = 100; @@ -39,24 +45,36 @@ static const struct option options_tab[] = {{"help", no_argument, 0, 'h'}, {"clusters", required_argument, 0, 'm'}, {"grid-size", required_argument, 0, 'g'}, {"optimal", required_argument, 0, 'x'}, - {"seed", required_argument, 0, 's'}, + {"seed", required_argument, 0, 's'}, {"out", required_argument, 0, 'o'}, + {"stats", required_argument, 0, 't'}, {"lp", required_argument, 0, 'l'}, + {"write-graph", required_argument, 0, 'w'}, {(char *) 0, (int) 0, (int *) 0, (int) 0}}; static char input_x_filename[1000] = {0}; -static void print_usage(int argc, char **argv) +static void print_usage(char **argv) { printf("Usage: %s [OPTION]...\n", argv[0]); printf("Solves the Generalized Traveling Salesman problem for the input graph.\n\n"); printf("Parameters:\n"); - printf("%4s %-13s %s\n", "-n", "--nodes", "number of nodes"); - printf("%4s %-13s %s\n", "-m", "--clusters", "number of clusters"); - printf("%4s %-13s %s\n", "-s", "--seed", "random seed"); - printf("%4s %-13s %s\n", "-g", "--grid-size", + printf("%4s %-20s %s\n", "-n", "--nodes=NUM", "number of nodes"); + printf("%4s %-20s %s\n", "-m", "--clusters=NUM", "number of clusters"); + printf("%4s %-20s %s\n", "-s", "--seed=NUM", "random seed"); + printf("%4s %-20s %s\n", "-g", "--grid-size=NUM", "size of the box used for generating random points"); - printf("%4s %-13s %s\n", "-x", "--optimal", - "file containg valid solution (used to assert validity of cuts)"); + printf("%4s %-20s %s\n", "-x", "--optimal=FILE", + "file containg optimal solution (used to assert validity of cuts)"); + printf("%4s %-20s %s\n", "-o", "--out=FILE", + "write optimal solution to this file"); + printf("%4s %-20s %s\n", "-f", "--frac=FILE", + "write current fractional solution to this file"); + printf("%4s %-20s %s\n", "-l", "--lp=FILE", + "write initial LP to this file"); + printf("%4s %-20s %s\n", "-w", "--write-graph=FILE", + "write the randomly generated input graph to this file"); + printf("%4s %-20s %s\n", "-t", "--stats=FILE", + "write statistics to this file (append if file exists)"); } static int parse_args(int argc, char **argv) @@ -69,7 +87,8 @@ static int parse_args(int argc, char **argv) { int c = 0; int option_index = 0; - c = getopt_long(argc, argv, "n:m:g:x:s:h:", options_tab, &option_index); + c = getopt_long(argc, argv, "n:m:g:x:s:h:o:t:l:w:", options_tab, + &option_index); if (c < 0) break; @@ -91,12 +110,28 @@ static int parse_args(int argc, char **argv) strcpy(input_x_filename, optarg); break; + case 'o': + strcpy(SOLUTION_FILENAME, optarg); + break; + case 's': SEED = (unsigned) atoi(optarg); break; + case 't': + strcpy(STATS_FILENAME, optarg); + break; + + case 'l': + strcpy(LP_FILENAME, optarg); + break; + + case 'w': + strcpy(WRITE_GRAPH_FILENAME, optarg); + break; + case 'h': - print_usage(argc, argv); + print_usage(argv); exit(0); case ':': @@ -175,16 +210,12 @@ int main(int argc, char **argv) grid_size, &data); abort_if(rval, "GTSP_create_random_problem failed"); - char filename[100]; - sprintf(filename, "input/%s.in", instance_name); - log_info("Writing random instance to file %s\n", filename); - rval = GTSP_write_problem(&data, filename); - abort_if(rval, "GTSP_write_problem failed"); - -#if LOG_LEVEL >= LOG_LEVEL_DEBUG - log_info("Writing random instance to file gtsp.in\n"); - rval = GTSP_write_problem(&data, "gtsp.in"); -#endif + if (strlen(WRITE_GRAPH_FILENAME) > 0) + { + log_info("Writing random instance to file %s\n", WRITE_GRAPH_FILENAME); + rval = GTSP_write_problem(&data, WRITE_GRAPH_FILENAME); + abort_if(rval, "GTSP_write_problem failed"); + } int init_val = 0; @@ -212,7 +243,6 @@ int main(int argc, char **argv) if (strlen(input_x_filename) == 0) { sprintf(input_x_filename, "optimal/%s.out", instance_name); - FILE *file = fopen(input_x_filename, "r"); if (!file) @@ -241,19 +271,12 @@ int main(int argc, char **argv) rval = BNC_init_lp(&bnc); abort_if(rval, "BNC_init_lp failed"); -// log_info("Writing LP to file gtsp.lp...\n"); -// rval = LP_write(bnc.lp, "gtsp.lp"); -// abort_if(rval, "LP_write failed"); - log_info("Starting branch-and-cut solver...\n"); rval = BNC_solve(&bnc); abort_if(rval, "BNC_solve_node failed"); abort_if(!bnc.best_x, "problem has no feasible solution"); - log_info("Optimal integral solution:\n"); - log_info(" obj value = %.2lf **\n", bnc.best_obj_val); - if (OPTIMAL_X) { abort_iff(bnc.best_obj_val - EPSILON > opt_val, @@ -263,60 +286,69 @@ int main(int argc, char **argv) TOTAL_TIME = get_user_time() - initial_time; - log_info("Branch-and-bound nodes: %d\n", BNC_NODE_COUNT); - log_info("LP optimize calls: %d\n", LP_SOLVE_COUNT); - log_info("LP solving time: %.2lf\n", LP_SOLVE_TIME); - log_info("LP cut pool management time: %.2lf\n", CUT_POOL_TIME); - - // Write statistics to a file - FILE *file = fopen("stats.tab", "a"); - abort_if(!file, "could not open stats.tab"); + if (strlen(STATS_FILENAME) > 0) + { + log_info("Writing statistics to file %s...\n", STATS_FILENAME); + FILE *file = fopen(STATS_FILENAME, "a"); + abort_if(!file, "could not open stats.tab"); - struct stat st; - stat("stats.tab", &st); + struct stat st; + stat(STATS_FILENAME, &st); - if (st.st_size == 0) - { - fprintf(file, "%-20s ", "instance"); - fprintf(file, "%-8s ", "time"); - fprintf(file, "%-8s ", "subt-t"); - fprintf(file, "%-8s ", "combs-t"); - fprintf(file, "%-8s ", "pool-t"); - fprintf(file, "%-8s ", "pool-m"); - fprintf(file, "%-8s ", "lp-count"); - fprintf(file, "%-8s ", "lp-time"); - fprintf(file, "%-8s ", "lp-rows"); - fprintf(file, "%-8s ", "lp-cols"); - fprintf(file, "%-8s ", "init-v"); - fprintf(file, "%-8s ", "opt-v"); - fprintf(file, "%-8s ", "root-v"); - fprintf(file, "%-8s ", "nodes"); - fprintf(file, "%-8s ", "subt-cc"); - fprintf(file, "%-8s ", "subt-nc"); - fprintf(file, "%-8s ", "subt-nn"); - fprintf(file, "%-8s ", "combs"); + if (st.st_size == 0) + { + fprintf(file, "%-20s ", "instance"); + fprintf(file, "%-8s ", "time"); + fprintf(file, "%-8s ", "subt-t"); + fprintf(file, "%-8s ", "combs-t"); + fprintf(file, "%-8s ", "pool-t"); + fprintf(file, "%-8s ", "pool-m"); + fprintf(file, "%-8s ", "lp-count"); + fprintf(file, "%-8s ", "lp-time"); + fprintf(file, "%-8s ", "lp-rows"); + fprintf(file, "%-8s ", "lp-cols"); + fprintf(file, "%-8s ", "init-v"); + fprintf(file, "%-8s ", "opt-v"); + fprintf(file, "%-8s ", "root-v"); + fprintf(file, "%-8s ", "nodes"); + fprintf(file, "%-8s ", "subt-cc"); + fprintf(file, "%-8s ", "subt-nc"); + fprintf(file, "%-8s ", "subt-nn"); + fprintf(file, "%-8s ", "combs"); + + fprintf(file, "\n"); + } + fprintf(file, "%-20s ", instance_name); + fprintf(file, "%-8.2lf ", TOTAL_TIME); + fprintf(file, "%-8.2lf ", SUBTOUR_TIME); + fprintf(file, "%-8.2lf ", COMBS_TIME); + fprintf(file, "%-8.2lf ", CUT_POOL_TIME); + fprintf(file, "%-8ld ", CUT_POOL_MAX_MEMORY / 1024 / 1024); + fprintf(file, "%-8d ", LP_SOLVE_COUNT); + fprintf(file, "%-8.2lf ", LP_SOLVE_TIME); + fprintf(file, "%-8d ", LP_MAX_ROWS); + fprintf(file, "%-8d ", LP_MAX_COLS); + fprintf(file, "%-8d ", init_val); + fprintf(file, "%-8.0lf ", bnc.best_obj_val); + fprintf(file, "%-8.0lf ", ROOT_VALUE); + fprintf(file, "%-8d ", BNC_NODE_COUNT); + fprintf(file, "%-8d ", SUBTOUR_COUNT); + fprintf(file, "%-8d ", COMBS_COUNT); fprintf(file, "\n"); + fclose(file); + } + + if(strlen(SOLUTION_FILENAME) == 0) + { + log_info("Optimal solution:\n"); + rval = GTSP_print_solution(&data, bnc.best_x); + abort_if(rval, "GTSP_print_solution failed"); } - fprintf(file, "%-20s ", instance_name); - fprintf(file, "%-8.2lf ", TOTAL_TIME); - fprintf(file, "%-8.2lf ", SUBTOUR_TIME); - fprintf(file, "%-8.2lf ", COMBS_TIME); - fprintf(file, "%-8.2lf ", CUT_POOL_TIME); - fprintf(file, "%-8ld ", CUT_POOL_MAX_MEMORY / 1024 / 1024); - fprintf(file, "%-8d ", LP_SOLVE_COUNT); - fprintf(file, "%-8.2lf ", LP_SOLVE_TIME); - fprintf(file, "%-8d ", LP_MAX_ROWS); - fprintf(file, "%-8d ", LP_MAX_COLS); - fprintf(file, "%-8d ", init_val); - fprintf(file, "%-8.0lf ", bnc.best_obj_val); - fprintf(file, "%-8.0lf ", ROOT_VALUE); - fprintf(file, "%-8d ", BNC_NODE_COUNT); - fprintf(file, "%-8d ", SUBTOUR_COUNT); - fprintf(file, "%-8d ", COMBS_COUNT); - fprintf(file, "\n"); - fclose(file); + log_info("Optimal solution value:\n"); + log_info(" %.4lf\n", bnc.best_obj_val); + CLEANUP: if (OPTIMAL_X) free(OPTIMAL_X); diff --git a/src/main.h b/src/main.h index 091191e..85ebf8d 100644 --- a/src/main.h +++ b/src/main.h @@ -24,4 +24,8 @@ extern double ROOT_VALUE; extern int SUBTOUR_COUNT; extern int COMBS_COUNT; +extern char LP_FILENAME[100]; +extern char SOLUTION_FILENAME[100]; +extern char FRAC_SOLUTION_FILENAME[100]; + #endif \ No newline at end of file diff --git a/src/util.h b/src/util.h index ba79aa8..fd32b33 100644 --- a/src/util.h +++ b/src/util.h @@ -41,11 +41,11 @@ #endif #define abort_if(cond, msg) if(cond) { \ - fprintf(stderr, "%28s:%d " msg "\n", __FILE__, __LINE__); \ + fprintf(stderr, msg " (%s:%d)\n", __FILE__, __LINE__); \ rval = 1; goto CLEANUP; } #define abort_iff(cond, msg, ...) if(cond) { \ - fprintf(stderr, "%28s:%d " msg "\n", __FILE__, __LINE__, __VA_ARGS__); \ + fprintf(stderr, msg " (%s:%d)\n", __VA_ARGS__, __FILE__, __LINE__); \ rval = 1; goto CLEANUP; } #define UNUSED(x) (void)(x)