First version of the GTSP branch-and-bound solver
This commit is contained in:
183
src/gtsp.c
Normal file
183
src/gtsp.c
Normal file
@@ -0,0 +1,183 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
||||
43
src/gtsp.h
Normal file
43
src/gtsp.h
Normal file
@@ -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_
|
||||
102
src/main.c
102
src/main.c
@@ -1,11 +1,13 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <float.h>
|
||||
#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();
|
||||
|
||||
rval = parse_arguments(ac, av);
|
||||
struct BNC bnc;
|
||||
struct TSPData data;
|
||||
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user