From 6891c0d0be2db38a4d8b7834cbe15712ea9408e7 Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Thu, 19 Mar 2015 05:55:40 -0400 Subject: [PATCH] First version of the GTSP branch-and-bound solver --- src/gtsp.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/gtsp.h | 43 +++++++++++++ src/main.c | 102 +++++++++++++++++++++++------ 3 files changed, 308 insertions(+), 20 deletions(-) create mode 100644 src/gtsp.c create mode 100644 src/gtsp.h diff --git a/src/gtsp.c b/src/gtsp.c new file mode 100644 index 0000000..89e2b4b --- /dev/null +++ b/src/gtsp.c @@ -0,0 +1,183 @@ +#include +#include +#include "gtsp.h" +#include "geometry.h" +#include "util.h" + +int GTSP_init_data(struct GTSP *data) +{ + data->node_count = 0; + data->edge_count = 0; + data->edges = 0; + data->clusters = 0; + data->cluster_count = 0; + data->x_coordinates = 0; + data->y_coordinates = 0; + return 0; +} + +void GTSP_free(struct GTSP *data) +{ + if (!data) return; + if (data->edges) free(data->edges); + if (data->clusters) free(data->clusters); + if (data->x_coordinates) free(data->x_coordinates); + if (data->y_coordinates) free(data->y_coordinates); +} + +int GTSP_create_random_problem( + int node_count, int cluster_count, int grid_size, struct GTSP *data) +{ + int rval = 0; + + struct Edge *edges = 0; + int *clusters = 0; + + double *x_coords = 0; + double *y_coords = 0; + + int edge_count = (node_count * (node_count - 1)) / 2; + + edges = (struct Edge *) malloc(edge_count * sizeof(struct Edge)); + clusters = (int *) malloc(node_count * sizeof(int)); + ABORT_IF (!edges, "could not allocate data->edges\n"); + ABORT_IF (!clusters, "could not allocate clusters\n"); + + x_coords = (double *) malloc(node_count * sizeof(double)); + y_coords = (double *) malloc(node_count * sizeof(double)); + ABORT_IF (!x_coords, "could not allocate x_coords\n"); + ABORT_IF (!y_coords, "could not allocate y_coords\n"); + + rval = generate_random_clusters_2d(node_count, cluster_count, grid_size, + x_coords, y_coords, clusters); + ABORT_IF(rval, "generate_random_clusters_2d failed"); + + int current_edge = 0; + for (int i = 0; i < edge_count; i++) + for (int j = i + 1; j < node_count; j++) + { + edges[current_edge].from = i; + edges[current_edge].to = j; + edges[current_edge].weight = + get_euclidean_distance(x_coords, y_coords, i, j); + + current_edge++; + } + + data->node_count = node_count; + data->edge_count = edge_count; + data->edges = edges; + data->clusters = clusters; + data->cluster_count = cluster_count; + data->x_coordinates = x_coords; + data->y_coordinates = y_coords; + + CLEANUP: + if (rval) + { + if (edges) free(edges); + if (clusters) free(clusters); + } + return rval; +} + +int GTSP_init_lp(struct LP *lp, struct GTSP *data) +{ + int rval = 0; + + int node_count = data->node_count; + int edge_count = data->edge_count; + int cluster_count = data->cluster_count; + int *clusters = data->clusters; + struct Edge *edges = data->edges; + + for (int i = 0; i < node_count; i++) + { + rval = LP_new_row(lp, 'E', 0.0); + ABORT_IF(rval, "LP_new_row failed"); + } + + for (int i = 0; i < cluster_count; i++) + { + rval = LP_new_row(lp, 'E', 1.0); + ABORT_IF(rval, "LP_new_row failed"); + } + + double lb = 0.0; + double ub = 1.0; + int cmatbeg = 0; + + for (int i = 0; i < node_count; i++) + { + double obj = 0.0; + double cmatval[] = {-2.0, 1.0}; + int cmatind[] = {i, node_count + clusters[i]}; + + rval = LP_add_cols(lp, 1, 2, &obj, &cmatbeg, cmatind, cmatval, &lb, + &ub); + ABORT_IF(rval, "LP_add_cols failed"); + } + + for (int i = 0; i < edge_count; i++) + { + double obj = (double) edges[i].weight; + double cmatval[] = {1.0, 1.0}; + int cmatind[] = {edges[i].from, edges[i].to}; + + rval = LP_add_cols(lp, 1, 2, &obj, &cmatbeg, cmatind, cmatval, &lb, + &ub); + ABORT_IF(rval, "LP_add_cols failed"); + } + + CLEANUP: + return rval; +} + +int GTSP_write_data(struct GTSP *data, char *filename) +{ + int rval = 0; + + FILE *file; + + file = fopen(filename, "w"); + ABORT_IF(!file, "could not open file"); + + fprintf(file, "%d %d\n", data->node_count, data->cluster_count); + + for (int i = 0; i < data->node_count; i++) + { + fprintf(file, "%.2lf %.2lf %d\n", data->x_coordinates[i], + data->y_coordinates[i], data->clusters[i]); + } + + CLEANUP: + if (file) fclose(file); + return rval; +} + +int GTSP_write_solution(struct GTSP *data, char *filename, double *x) +{ + int rval = 0; + + struct Edge *edges = data->edges; + int node_count = data->node_count; + + FILE *file; + file = fopen(filename, "w"); + ABORT_IF(!file, "could not open file"); + + int positive_edge_count = 0; + for (int i = 0; i < data->edge_count; i++) + if (x[i + node_count] > 0.5) + positive_edge_count++; + + fprintf(file, "%d\n", positive_edge_count); + + for (int i = 0; i < data->edge_count; i++) + if (x[i + node_count] > 0.5) + fprintf(file, "%d %d\n", edges[i].from, edges[i].to); + + CLEANUP: + if (file) fclose(file); + return rval; +} \ No newline at end of file diff --git a/src/gtsp.h b/src/gtsp.h new file mode 100644 index 0000000..b4ed5f3 --- /dev/null +++ b/src/gtsp.h @@ -0,0 +1,43 @@ +// +// Created by isoron on 18/03/15. +// + +#ifndef _PROJECT_GTSP_H_ +#define _PROJECT_GTSP_H_ + +#include "lp.h" + +struct Edge +{ + int from; + int to; + int weight; +}; + +struct GTSP +{ + int node_count; + int edge_count; + struct Edge *edges; + + int *clusters; + int cluster_count; + + double *x_coordinates; + double *y_coordinates; +}; + +int GTSP_create_random_problem( + int node_count, int cluster_count, int grid_size, struct GTSP *data); + +void GTSP_free(struct GTSP *data); + +int GTSP_init_data(struct GTSP *data); + +int GTSP_init_lp(struct LP *lp, struct GTSP *data); + +int GTSP_write_data(struct GTSP *data, char *filename); + +int GTSP_write_solution(struct GTSP *data, char *filename, double *x); + +#endif //_PROJECT_GTSP_H_ diff --git a/src/main.c b/src/main.c index c92ad17..7442f03 100644 --- a/src/main.c +++ b/src/main.c @@ -1,11 +1,13 @@ #include #include #include +#include #include "lp.h" #include "util.h" #include "main.h" #include "tsp.h" #include "branch_and_cut.h" +#include "gtsp.h" char *INPUT_FILENAME = 0; unsigned int SEED = 0; @@ -13,34 +15,35 @@ int GEOMETRIC_DATA = 0; int NODE_COUNT_RAND = 0; int GRID_SIZE_RAND = 100; -static int parse_arguments(int ac, char **av); +static int parse_arguments_tsp(int ac, char **av); -static void print_usage(char *f); +static void print_usage_tsp(char *f); -int main(int ac, char **av) +int main_tsp(int ac, char **av) { int rval = 0; - SEED = (unsigned int) get_current_time(); + SEED = (unsigned int) get_real_time(); + + struct BNC bnc; + struct TSPData data; - rval = parse_arguments(ac, av); + rval = TSP_init_data(&data); + ABORT_IF(rval, "TSP_init_data failed"); + + rval = BNC_init(&bnc); + ABORT_IF(rval, "BNC_init failed"); + + rval = parse_arguments_tsp(ac, av); ABORT_IF(rval, "Failed to parse arguments.\n"); printf("Seed = %d\n", SEED); srand(SEED); - struct BNC bnc; - struct TSPData data; - - TSP_init_data(&data); - rval = TSP_read_problem(INPUT_FILENAME, &data); ABORT_IF(rval, "TSP_read_problem failed\n"); - rval = BNC_init(&bnc); - ABORT_IF(rval, "BNC_init failed"); - - bnc.best_val = TSP_find_initial_solution(&data); + bnc.best_obj_val = TSP_find_initial_solution(&data); bnc.problem_data = (void *) &data; bnc.problem_init_lp = (int (*)(struct LP *, void *)) TSP_init_lp; bnc.problem_add_cutting_planes = @@ -53,7 +56,7 @@ int main(int ac, char **av) ABORT_IF(rval, "BNC_solve_node failed\n"); time_printf("Optimal integral solution:\n"); - time_printf(" obj value = %.2lf **\n", bnc.best_val); + time_printf(" obj value = %.2lf **\n", bnc.best_obj_val); CLEANUP: BNC_free(&bnc); @@ -61,7 +64,60 @@ int main(int ac, char **av) return rval; } -static int parse_arguments(int ac, char **av) +int main_gtsp(int ac, char **av) +{ + int rval = 0; + + SEED = (unsigned int) get_real_time(); + srand(SEED); + + int node_count = 50; + int cluster_count = node_count / 5; + int grid_size = 100; + + struct BNC bnc; + struct GTSP data; + + rval = GTSP_init_data(&data); + ABORT_IF(rval, "GTSP_init_data failed"); + + rval = GTSP_create_random_problem(node_count, cluster_count, grid_size, + &data); + ABORT_IF(rval, "GTSP_create_random_problem failed"); + + rval = GTSP_write_data(&data, "gtsp.in"); + ABORT_IF(rval, "GTSP_write_problem failed\n"); + + rval = BNC_init(&bnc); + ABORT_IF(rval, "BNC_init failed\n"); + + printf("Seed = %d\n", SEED); + srand(SEED); + + bnc.best_obj_val = DBL_MAX; + bnc.problem_data = (void *) &data; + bnc.problem_init_lp = (int (*)(struct LP *, void *)) GTSP_init_lp; + + rval = BNC_init_lp(&bnc); + ABORT_IF(rval, "BNC_init_lp failed\n"); + + rval = BNC_solve(&bnc); + ABORT_IF(rval, "BNC_solve_node failed\n"); + + time_printf("Optimal integral solution:\n"); + time_printf(" obj value = %.2lf **\n", bnc.best_obj_val); + + rval = GTSP_write_solution(&data, "gtsp.out", bnc.best_x); + ABORT_IF(rval, "GTSP_write_solution failed"); + + CLEANUP: + GTSP_free(&data); + BNC_free(&bnc); + return rval; + +} + +static int parse_arguments_tsp(int ac, char **av) { int rval = 0; @@ -69,7 +125,7 @@ static int parse_arguments(int ac, char **av) if (ac == 1) { - print_usage(av[0]); + print_usage_tsp(av[0]); return 1; } @@ -93,7 +149,7 @@ static int parse_arguments(int ac, char **av) break; case '?': default: - print_usage(av[0]); + print_usage_tsp(av[0]); return 1; } } @@ -102,7 +158,7 @@ static int parse_arguments(int ac, char **av) if (optind != ac) { - print_usage(av[0]); + print_usage_tsp(av[0]); return 1; } @@ -113,7 +169,13 @@ static int parse_arguments(int ac, char **av) return rval; } -static void print_usage(char *f) +int main(int ac, char **av) +{ + return main_gtsp(ac, av); +// return main_tsp(ac, av); +} + +static void print_usage_tsp(char *f) { fprintf(stderr, "Usage: %s [-see below-] [prob_file]\n" " -a add all subtours cuts at once\n"