From 67ca00a0e00c8f10937bd8b2f65a5d92b3d96760 Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Wed, 18 Mar 2015 07:15:35 -0400 Subject: [PATCH] Refactoring --- CMakeLists.txt | 1 - src/branch_and_cut.c | 211 +++++++++++++++++++++++++------------------ src/branch_and_cut.h | 24 +++-- src/graph.c | 11 ++- src/graph.h | 44 +++++++-- src/lp.c | 55 +++++++---- src/lp.h | 47 +++++++--- src/main.c | 112 +++++++++++------------ src/main.h | 45 ++------- src/tsp.c | 118 +++++++++++++++--------- src/tsp.h | 53 ++++++----- src/util.c | 116 +++++++++++++----------- src/util.h | 15 +-- 13 files changed, 487 insertions(+), 365 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d1f915..046384c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,6 @@ set(CMAKE_SOURCE_DIR src) set(CMAKE_C_FLAGS "-O3 -g -Wall -pedantic -g --std=c11 -Winline") - set(SOURCE_FILES src/lp.c src/lp.h diff --git a/src/branch_and_cut.c b/src/branch_and_cut.c index 02d14fb..0be9977 100644 --- a/src/branch_and_cut.c +++ b/src/branch_and_cut.c @@ -3,25 +3,81 @@ #include #include "lp.h" #include "branch_and_cut.h" -#include "tsp.h" #include "util.h" -int bnc_is_integral(double *x, int length); +static int BNC_solve_node(struct BNC *bnc, int depth); -int bnc_find_best_branch_var(double *x, int length); +static int BNC_branch_node(struct BNC *bnc, double *x, int depth); -int bnc_solve_node( - struct LP *lp, double *best_val, int ncount, int ecount, int *elist, - int depth) +static int BNC_is_integral(double *x, int num_cols); + +static int BNC_find_best_branching_var(double *x, int num_cols); + +int BNC_init(struct BNC *bnc) +{ + int rval = 0; + + bnc->lp = 0; + bnc->problem_data = 0; + bnc->problem_init_lp = 0; + bnc->problem_add_cutting_planes = 0; + + bnc->lp = (struct LP *) malloc(sizeof(struct LP)); + ABORT_IF(!bnc->lp, "could not allocate bnc->lp\n"); + + CLEANUP: + return rval; +} + +void BNC_free(struct BNC *bnc) +{ + if (!bnc) return; + if (bnc->lp) + { + LP_free(bnc->lp); + free(bnc->lp); + } +} + +int BNC_init_lp(struct BNC *bnc) { + int rval = 0; + time_printf("Initializing LP...\n"); + + rval = LP_open(bnc->lp); + ABORT_IF(rval, "LP_open failed\n"); + + rval = LP_create(bnc->lp, "subtour"); + ABORT_IF(rval, "LP_create failed\n"); + + rval = bnc->problem_init_lp(bnc->lp, bnc->problem_data); + ABORT_IF(rval, "problem_init_lp failed\n"); + + rval = LP_write(bnc->lp, "subtour.lp"); + ABORT_IF(rval, "LP_write failed\n"); + + CLEANUP: + return rval; +} + +int BNC_solve(struct BNC *bnc) +{ + return BNC_solve_node(bnc, 1); +} + +static int BNC_solve_node(struct BNC *bnc, int depth) +{ + struct LP *lp = bnc->lp; + double *best_val = &bnc->best_val; + int rval = 0; double *x = (double *) NULL; time_printf("Optimizing...\n"); int is_infeasible; - rval = lp_optimize(lp, &is_infeasible); - ABORT_IF (rval, "lp_optimize failed\n"); + rval = LP_optimize(lp, &is_infeasible); + ABORT_IF (rval, "LP_optimize failed\n"); if (is_infeasible) { @@ -30,8 +86,8 @@ int bnc_solve_node( } double objval; - rval = lp_get_obj_val(lp, &objval); - ABORT_IF (rval, "lp_get_obj_val failed\n"); + rval = LP_get_obj_val(lp, &objval); + ABORT_IF (rval, "LP_get_obj_val failed\n"); time_printf(" objective value = %.2f\n", objval); @@ -43,25 +99,30 @@ int bnc_solve_node( goto CLEANUP; } - x = (double *) malloc(ecount * sizeof(double)); + int num_cols = LP_get_num_cols(lp); + + x = (double *) malloc(num_cols * sizeof(double)); ABORT_IF(!x, "could not allocate x\n"); - rval = lp_get_x(lp, x); - ABORT_IF(rval, "lp_get_x failed\n"); + rval = LP_get_x(lp, x); + ABORT_IF(rval, "LP_get_x failed\n"); - rval = TSP_add_cutting_planes(ncount, ecount, elist, lp); - ABORT_IF(rval, "TSP_add_cutting_planes failed\n"); + if (bnc->problem_add_cutting_planes) + { + rval = bnc->problem_add_cutting_planes(lp, bnc->problem_data); + ABORT_IF(rval, "TSP_add_cutting_planes failed\n"); + } - rval = lp_optimize(lp, &is_infeasible); - ABORT_IF (rval, "lp_optimize failed\n"); + rval = LP_optimize(lp, &is_infeasible); + ABORT_IF (rval, "LP_optimize failed\n"); - rval = lp_get_obj_val(lp, &objval); - ABORT_IF(rval, "lp_get_obj_val failed\n"); + rval = LP_get_obj_val(lp, &objval); + ABORT_IF(rval, "LP_get_obj_val failed\n"); - rval = lp_get_x(lp, x); - ABORT_IF(rval, "lp_get_x failed\n"); + rval = LP_get_x(lp, x); + ABORT_IF(rval, "LP_get_x failed\n"); - if (bnc_is_integral(x, ecount)) + if (BNC_is_integral(x, num_cols)) { time_printf(" solution is integral\n"); @@ -71,11 +132,12 @@ int bnc_solve_node( time_printf("Found a better integral solution:\n"); time_printf(" objval = %.2lf **\n", objval); } - } else + } + else { time_printf(" solution is fractional\n"); - rval = bnc_branch_node(lp, x, ncount, ecount, depth, best_val, elist); - ABORT_IF(rval, "bnc_branch_node failed\n"); + rval = BNC_branch_node(bnc, x, depth); + ABORT_IF(rval, "BNC_branch_node failed\n"); } CLEANUP: @@ -83,95 +145,66 @@ int bnc_solve_node( return rval; } -int bnc_branch_node( - struct LP *lp, double *x, int ncount, int ecount, int depth, - double *best_val, int *elist) +static int BNC_branch_node(struct BNC *bnc, double *x, int depth) { int rval = 0; - int best_index = bnc_find_best_branch_var(x, ecount); + struct LP *lp = bnc->lp; - time_printf("Branching on variable x%d = %.6lf (depth %d)...\n", best_index, - x[best_index], depth); + int num_cols = LP_get_num_cols(lp); + int best_branch_var = BNC_find_best_branching_var(x, num_cols); - time_printf("Fixing variable x%d to one...\n", best_index); - rval = lp_change_bound(lp, best_index, 'L', 1.0); - ABORT_IF(rval, "lp_change_bound failed\n"); + time_printf("Branching on variable x%d = %.6lf (depth %d)...\n", + best_branch_var, x[best_branch_var], depth); - rval = bnc_solve_node(lp, best_val, ncount, ecount, elist, depth + 1); - ABORT_IF(rval, "bnc_solve_node failed\n"); + time_printf("Fixing variable x%d to one...\n", best_branch_var); + rval = LP_change_bound(lp, best_branch_var, 'L', 1.0); + ABORT_IF(rval, "LP_change_bound failed\n"); - rval = lp_change_bound(lp, best_index, 'L', 0.0); - ABORT_IF(rval, "lp_change_bound failed\n"); + rval = BNC_solve_node(bnc, depth + 1); + ABORT_IF(rval, "BNC_solve_node failed\n"); - time_printf("Fixing variable x%d to zero...\n", best_index); - rval = lp_change_bound(lp, best_index, 'U', 0.0); - ABORT_IF(rval, "lp_change_bound failed\n"); + rval = LP_change_bound(lp, best_branch_var, 'L', 0.0); + ABORT_IF(rval, "LP_change_bound failed\n"); - rval = bnc_solve_node(lp, best_val, ncount, ecount, elist, depth + 1); - ABORT_IF(rval, "bnc_solve_node failed\n"); + time_printf("Fixing variable x%d to zero...\n", best_branch_var); + rval = LP_change_bound(lp, best_branch_var, 'U', 0.0); + ABORT_IF(rval, "LP_change_bound failed\n"); - rval = lp_change_bound(lp, best_index, 'U', 1.0); - ABORT_IF(rval, "lp_change_bound failed\n"); + rval = BNC_solve_node(bnc, depth + 1); + ABORT_IF(rval, "BNC_solve_node failed\n"); - time_printf("Finished branching on variable %d\n", best_index); + rval = LP_change_bound(lp, best_branch_var, 'U', 1.0); + ABORT_IF(rval, "LP_change_bound failed\n"); + + time_printf("Finished branching on variable %d\n", best_branch_var); CLEANUP: return rval; } -int bnc_find_best_branch_var(double *x, int length) +static int BNC_is_integral(double *x, int num_cols) { - int best_index = 0; - double best_index_frac = 1.0; + for (int i = 0; i < num_cols; i++) + if (x[i] > LP_EPSILON && x[i] < 1.0 - LP_EPSILON) + return 0; - for (int j = 0; j < length; j++) - { - if (fabs(x[j] - 0.5) < best_index_frac) - { - best_index = j; - best_index_frac = fabs(x[j] - 0.5); - } - } - - return best_index; + return 1; } -int bnc_is_integral(double *x, int length) +static int BNC_find_best_branching_var(double *x, int num_cols) { - int all_integral = 1; + int best_index = 0; + double best_index_frac = 1.0; - for (int j = 0; j < length; j++) + for (int i = 0; i < num_cols; i++) { - if (x[j] > LP_EPSILON && x[j] < 1.0 - LP_EPSILON) + if (fabs(x[i] - 0.5) < best_index_frac) { - all_integral = 0; - break; + best_index = i; + best_index_frac = fabs(x[i] - 0.5); } } - return all_integral; + return best_index; } - -int bnc_init_lp( - struct LP *lp, int node_count, int edge_count, int *edge_list, - int *edge_weights) -{ - int rval = 0; - time_printf("Initializing LP...\n"); - - rval = lp_open(lp); - ABORT_IF(rval, "lp_open failed\n"); - - rval = lp_create(lp, "subtour"); - ABORT_IF(rval, "lp_create failed\n"); - - rval = TSP_init_lp(node_count, lp, edge_count, edge_weights, edge_list); - ABORT_IF(rval, "TSP_init_lp failed\n"); - - rval = lp_write(lp, "subtour.lp"); - ABORT_IF(rval, "lp_write failed\n"); - - CLEANUP: - return rval; -} \ No newline at end of file diff --git a/src/branch_and_cut.h b/src/branch_and_cut.h index 52ff26a..d6e4858 100644 --- a/src/branch_and_cut.h +++ b/src/branch_and_cut.h @@ -3,15 +3,23 @@ #include "lp.h" -int bnc_solve_node( - struct LP *lp, double *best_val, int ncount, int ecount, int *elist, - int depth); +struct BNC +{ + struct LP *lp; + double best_val; + int *problem_data; -int bnc_branch_node( - struct LP *lp, double *x, int ncount, int ecount, int depth, - double *current_val, int *elist); + int (*problem_init_lp)(struct LP *, void *); -int bnc_init_lp( - struct LP *lp, int node_count, int edge_count, int *edge_list, int *edge_weights); + int (*problem_add_cutting_planes)(struct LP *, void *); +}; + +int BNC_init(struct BNC *bnc); + +int BNC_solve(struct BNC *bnc); + +int BNC_init_lp(struct BNC *bnc); + +void BNC_free(struct BNC *bnc); #endif //_PROJECT_BRANCH_AND_CUT_H_ diff --git a/src/graph.c b/src/graph.c index 62f8b36..72979f5 100644 --- a/src/graph.c +++ b/src/graph.c @@ -55,7 +55,7 @@ int graph_build(int node_count, int edge_count, int *edge_list, struct Graph *G) (struct AdjObj *) malloc(2 * edge_count * sizeof(struct AdjObj)); ABORT_IF(!G->node_list, "could not allocate G->node_list\n"); - ABORT_IF(!G->adj_space, "out of memory for node_list or adj_space\n"); + ABORT_IF(!G->adj_space, "could not allocate G->adj_space\n"); for (int i = 0; i < node_count; i++) G->node_list[i].deg = 0; @@ -109,8 +109,13 @@ int euclid_edgelen(int i, int j, double *x, double *y) } void get_delta( - int island_node_count, int *island_nodes, int edge_count, int *edges, - int *delta_count, int *delta, int *marks) + int island_node_count, + int *island_nodes, + int edge_count, + int *edges, + int *delta_count, + int *delta, + int *marks) { for (int i = 0; i < island_node_count; i++) marks[island_nodes[i]] = 1; diff --git a/src/graph.h b/src/graph.h index d5f42ef..9587516 100644 --- a/src/graph.h +++ b/src/graph.h @@ -1,8 +1,32 @@ -#ifndef __GRAPH_H_ -#define __GRAPH_H_ +#ifndef _PROJECT_GRAPH_H_ +#define _PROJECT_GRAPH_H_ #include "main.h" +struct AdjObj +{ + /* Index of neighbor node */ + int n; + + /* Index of adj joining neighbor */ + int e; +}; + +struct Node +{ + int deg; + struct AdjObj *adj; + int mark; +}; + +struct Graph +{ + int node_count; + int edge_count; + struct Node *node_list; + struct AdjObj *adj_space; +}; + void graph_dfs( int n, struct Graph *G, double *x, int *icount, int *island); @@ -10,12 +34,18 @@ void graph_init(struct Graph *G); void graph_free(struct Graph *G); -int graph_build(int node_count, int edge_count, int *edge_list, struct Graph *G); +int graph_build + (int node_count, int edge_count, int *edge_list, struct Graph *G); int euclid_edgelen(int i, int j, double *x, double *y); void get_delta( - int nsize, int *nlist, int ecount, int *elist, int *deltacount, - int *delta, int *marks); - -#endif //___GRAPH_H_ + int nsize, + int *nlist, + int ecount, + int *elist, + int *deltacount, + int *delta, + int *marks); + +#endif diff --git a/src/lp.c b/src/lp.c index a5b9bd0..7451735 100644 --- a/src/lp.c +++ b/src/lp.c @@ -7,11 +7,11 @@ #define LP_EPSILON 0.000001 -int lp_open(struct LP *lp) +int LP_open(struct LP *lp) { int rval = 0; - lp->cplex_lp = (CPXLPptr)NULL; + lp->cplex_lp = (CPXLPptr) NULL; lp->cplex_env = CPXopenCPLEX(&rval); if (rval) { @@ -23,7 +23,7 @@ int lp_open(struct LP *lp) return rval; } -void lp_free(struct LP *lp) +void LP_free(struct LP *lp) { if (!lp) return; if (!lp->cplex_env) return; @@ -35,7 +35,7 @@ void lp_free(struct LP *lp) lp->cplex_env = 0; } -int lp_create(struct LP *lp, const char *name) +int LP_create(struct LP *lp, const char *name) { int rval = 0; char nambuf[MAX_NAME_LENGTH]; @@ -52,12 +52,11 @@ int lp_create(struct LP *lp, const char *name) return rval; } -int lp_new_row(struct LP *lp, char sense, double rhs) +int LP_new_row(struct LP *lp, char sense, double rhs) { int rval = 0; - rval = CPXnewrows(lp->cplex_env, lp->cplex_lp, 1, &rhs, &sense, - (double *) NULL, (char **) NULL); + rval = CPXnewrows(lp->cplex_env, lp->cplex_lp, 1, &rhs, &sense, 0, 0); ABORT_IF(rval, "CPXnewrows failed\n"); @@ -65,14 +64,20 @@ int lp_new_row(struct LP *lp, char sense, double rhs) return rval; } -int lp_add_rows( - struct LP *lp, int newrows, int newnz, double *rhs, char *sense, - int *rmatbeg, int *rmatind, double *rmatval) +int LP_add_rows( + struct LP *lp, + int newrows, + int newnz, + double *rhs, + char *sense, + int *rmatbeg, + int *rmatind, + double *rmatval) { int rval = 0; rval = CPXaddrows(lp->cplex_env, lp->cplex_lp, 0, newrows, newnz, rhs, - sense, rmatbeg, rmatind, rmatval, (char **) NULL, (char **) NULL); + sense, rmatbeg, rmatind, rmatval, 0, 0); ABORT_IF(rval, "CPXaddrows failed\n"); @@ -80,9 +85,16 @@ int lp_add_rows( return rval; } -int lp_add_cols( - struct LP *lp, int newcols, int newnz, double *obj, int *cmatbeg, - int *cmatind, double *cmatval, double *lb, double *ub) +int LP_add_cols( + struct LP *lp, + int newcols, + int newnz, + double *obj, + int *cmatbeg, + int *cmatind, + double *cmatval, + double *lb, + double *ub) { int rval = 0; @@ -95,7 +107,7 @@ int lp_add_cols( return rval; } -int lp_change_bound(struct LP *lp, int col, char lower_or_upper, double bnd) +int LP_change_bound(struct LP *lp, int col, char lower_or_upper, double bnd) { int rval = 0; @@ -107,7 +119,7 @@ int lp_change_bound(struct LP *lp, int col, char lower_or_upper, double bnd) return rval; } -int lp_optimize(struct LP *lp, int *infeasible) +int LP_optimize(struct LP *lp, int *infeasible) { int rval = 0, solstat; @@ -134,7 +146,7 @@ int lp_optimize(struct LP *lp, int *infeasible) return rval; } -int lp_get_obj_val(struct LP *lp, double *obj) +int LP_get_obj_val(struct LP *lp, double *obj) { int rval = 0; @@ -145,7 +157,7 @@ int lp_get_obj_val(struct LP *lp, double *obj) return rval; } -int lp_get_x(struct LP *lp, double *x) +int LP_get_x(struct LP *lp, double *x) { int rval = 0; @@ -159,7 +171,12 @@ int lp_get_x(struct LP *lp, double *x) return rval; } -int lp_write(struct LP *lp, const char *fname) +int LP_get_num_cols(struct LP *lp) +{ + return CPXgetnumcols(lp->cplex_env, lp->cplex_lp); +} + +int LP_write(struct LP *lp, const char *fname) { int rval = 0; diff --git a/src/lp.h b/src/lp.h index d181aef..4332926 100644 --- a/src/lp.h +++ b/src/lp.h @@ -1,5 +1,5 @@ -#ifndef __MAIN_ -#define __MAIN_ +#ifndef _PROJECT_LP_H_ +#define _PROJECT_LP_H_ #include @@ -13,28 +13,45 @@ struct LP static const int MAX_NAME_LENGTH = 100; -int lp_open(struct LP *lp); +int LP_open(struct LP *lp); -int lp_create(struct LP *lp, const char *name); +int LP_create(struct LP *lp, const char *name); -int lp_write(struct LP *lp, const char *fname); +int LP_write(struct LP *lp, const char *fname); -void lp_free(struct LP *lp); +void LP_free(struct LP *lp); -int lp_new_row(struct LP *lp, char sense, double rhs); +int LP_new_row(struct LP *lp, char sense, double rhs); -int lp_add_rows(struct LP *lp, int newrows, int newnz, double *rhs, char *sense, - int *rmatbeg, int *rmatind, double *rmatval); +int LP_add_rows( + struct LP *lp, + int newrows, + int newnz, + double *rhs, + char *sense, + int *rmatbeg, + int *rmatind, + double *rmatval); -int lp_add_cols(struct LP *lp, int newcols, int newnz, double *obj, - int *cmatbeg, int *cmatind, double *cmatval, double *lb, double *ub); +int LP_add_cols( + struct LP *lp, + int newcols, + int newnz, + double *obj, + int *cmatbeg, + int *cmatind, + double *cmatval, + double *lb, + double *ub); -int lp_change_bound(struct LP *lp, int col, char lower_or_upper, double bnd); +int LP_change_bound(struct LP *lp, int col, char lower_or_upper, double bnd); -int lp_optimize(struct LP *lp, int *infeasible); +int LP_optimize(struct LP *lp, int *infeasible); -int lp_get_obj_val(struct LP *lp, double *obj); +int LP_get_obj_val(struct LP *lp, double *obj); -int lp_get_x(struct LP *lp, double *x); +int LP_get_x(struct LP *lp, double *x); + +int LP_get_num_cols(struct LP *lp); #endif \ No newline at end of file diff --git a/src/main.c b/src/main.c index dc436cf..c92ad17 100644 --- a/src/main.c +++ b/src/main.c @@ -7,82 +7,69 @@ #include "tsp.h" #include "branch_and_cut.h" -char *fname = (char *) NULL; -int seed = 0; -int geometric_data = 0; -int ncount_rand = 0; -int gridsize_rand = 100; -int use_all_subtours = 0; +char *INPUT_FILENAME = 0; +unsigned int SEED = 0; +int GEOMETRIC_DATA = 0; +int NODE_COUNT_RAND = 0; +int GRID_SIZE_RAND = 100; + +static int parse_arguments(int ac, char **av); + +static void print_usage(char *f); int main(int ac, char **av) { int rval = 0; - int *edge_weights = 0; - int *edge_list = 0; - int *tlist = 0; - seed = (int) util_get_current_time(); + SEED = (unsigned int) get_current_time(); - rval = parseargs(ac, av); + rval = parse_arguments(ac, av); ABORT_IF(rval, "Failed to parse arguments.\n"); - ABORT_IF(!fname && !ncount_rand, "Must specify a problem file or use -k for" - " random prob\n"); - printf("Seed = %d\n", seed); - srand(seed); - - if (fname) - { - printf("Problem name: %s\n", fname); - if (geometric_data) printf("Geometric data\n"); - } - - int node_count = 0, edge_count = 0; - rval = TSP_read_problem(fname, &node_count, &edge_count, &edge_list, - &edge_weights); - ABORT_IF(rval, "TSP_read_problem failed\n"); - ABORT_IF(use_all_subtours && node_count > 20, "Too many nodes to add all" - " subtours\n"); + printf("Seed = %d\n", SEED); + srand(SEED); - tlist = (int *) malloc((node_count) * sizeof(int)); + struct BNC bnc; + struct TSPData data; - ABORT_IF(!tlist, "out of memory for tlist\n"); + TSP_init_data(&data); - double best_val = TSP_find_initial_solution(edge_weights, edge_list, - node_count, edge_count); + rval = TSP_read_problem(INPUT_FILENAME, &data); + ABORT_IF(rval, "TSP_read_problem failed\n"); - initial_time = util_get_current_time(); + rval = BNC_init(&bnc); + ABORT_IF(rval, "BNC_init failed"); - struct LP *lp; - lp = (struct LP *) malloc(sizeof(struct LP *)); + bnc.best_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 = + (int (*)(struct LP *, void *)) TSP_add_cutting_planes; - rval = bnc_init_lp(lp, node_count, edge_count, edge_list, edge_weights); - ABORT_IF(rval, "bnc_init_lp failed\n"); + rval = BNC_init_lp(&bnc); + ABORT_IF(rval, "BNC_init_lp failed"); - rval = bnc_solve_node(lp, &best_val, node_count, edge_count, edge_list, 1); - ABORT_IF(rval, "bnc_solve_node failed\n"); + rval = BNC_solve(&bnc); + ABORT_IF(rval, "BNC_solve_node failed\n"); time_printf("Optimal integral solution:\n"); - time_printf(" objective value = %.2lf **\n", best_val); - - printf("\nRunning Time: %.2f seconds\n", - util_get_current_time() - initial_time); - fflush(stdout); + time_printf(" obj value = %.2lf **\n", bnc.best_val); CLEANUP: - if (tlist) free(tlist); - if (edge_list) free(edge_list); - if (edge_weights) free(edge_weights); + BNC_free(&bnc); + TSP_free_data(&data); return rval; } -int parseargs(int ac, char **av) +static int parse_arguments(int ac, char **av) { + int rval = 0; + int c; if (ac == 1) { - usage(av[0]); + print_usage(av[0]); return 1; } @@ -90,46 +77,49 @@ int parseargs(int ac, char **av) { switch (c) { - case 'a': - use_all_subtours = 1; + case 'a':; break; case 'b': - gridsize_rand = atoi(optarg); + GRID_SIZE_RAND = atoi(optarg); break; case 'g': - geometric_data = 1; + GEOMETRIC_DATA = 1; break; case 'k': - ncount_rand = atoi(optarg); + NODE_COUNT_RAND = atoi(optarg); break; case 's': - seed = atoi(optarg); + SEED = (unsigned) atoi(optarg); break; case '?': default: - usage(av[0]); + print_usage(av[0]); return 1; } } - if (optind < ac) fname = av[optind++]; + if (optind < ac) INPUT_FILENAME = av[optind++]; if (optind != ac) { - usage(av[0]); + print_usage(av[0]); return 1; } - return 0; + ABORT_IF(!INPUT_FILENAME && !NODE_COUNT_RAND, + "Must specify an input file or use -k for random problem\n"); + + CLEANUP: + return rval; } -void usage(char *f) +static void print_usage(char *f) { fprintf(stderr, "Usage: %s [-see below-] [prob_file]\n" " -a add all subtours cuts at once\n" " -b d gridsize d for random problems\n" " -g prob_file has x-y coordinates\n" " -k d generate problem with d cities\n" - " -s d random seed\n", f); + " -s d random SEED\n", f); } diff --git a/src/main.h b/src/main.h index 9b0eb14..5f64e38 100644 --- a/src/main.h +++ b/src/main.h @@ -1,39 +1,10 @@ -#ifndef __MAIN_H_ -#define __MAIN_H_ - -struct AdjObj -{ - int n; - /* index of neighbor node */ - int e; /* index of adj joining neighbor */ -}; - -struct Node -{ - int deg; - struct AdjObj *adj; - int mark; -}; - -struct Graph -{ - int node_count; - int edge_count; - struct Node *node_list; - struct AdjObj *adj_space; -}; - -void usage(char *f); - -int parseargs(int ac, char **av); - -extern char *fname; -extern int seed; -extern int geometric_data; -extern int ncount_rand; -extern int gridsize_rand; -extern int use_all_subtours; - -extern double initial_time; +#ifndef _PROJECT_MAIN_H_ +#define _PROJECT_MAIN_H_ + +extern char *INPUT_FILENAME; +extern unsigned int SEED; +extern int GEOMETRIC_DATA; +extern int NODE_COUNT_RAND; +extern int GRID_SIZE_RAND; #endif \ No newline at end of file diff --git a/src/tsp.c b/src/tsp.c index 43d899f..0f8aadb 100644 --- a/src/tsp.c +++ b/src/tsp.c @@ -4,17 +4,36 @@ #include "tsp.h" #include "util.h" -int TSP_init_lp( - int node_count, struct LP *lp, int edge_count, int *edge_weights, - int *edge_list) +int TSP_init_data(struct TSPData *data) { + data->node_count = 0; + data->edge_count = 0; + data->edge_weights = 0; + data->edge_list = 0; + + return 0; +} + +void TSP_free_data(struct TSPData *data) +{ + if (data->edge_list) free(data->edge_list); + if (data->edge_weights) free(data->edge_weights); +} + +int TSP_init_lp(struct LP *lp, struct TSPData *data) +{ + int node_count = data->node_count; + int edge_count = data->edge_count; + int *edge_list = data->edge_list; + int *edge_weights = data->edge_weights; + int rval = 0; /* Build a row for each degree equation */ for (int i = 0; i < node_count; i++) { - rval = lp_new_row(lp, 'E', 2.0); - ABORT_IF(rval, "lp_new_row failed\n"); + rval = LP_new_row(lp, 'E', 2.0); + ABORT_IF(rval, "LP_new_row failed\n"); } /* Build a column for each edge of the graph */ @@ -27,10 +46,10 @@ int TSP_init_lp( double obj = (double) edge_weights[j]; int cmatind[] = {edge_list[2 * j], edge_list[2 * j + 1]}; - rval = lp_add_cols(lp, 1, 2, &obj, &cmatbeg, cmatind, cmatval, &lb, + rval = LP_add_cols(lp, 1, 2, &obj, &cmatbeg, cmatind, cmatval, &lb, &ub); - ABORT_IF(rval, "lp_add_cols failed\n"); + ABORT_IF(rval, "LP_add_cols failed\n"); } CLEANUP: @@ -38,8 +57,13 @@ int TSP_init_lp( } int TSP_find_violated_subtour_elimination_cut( - int ncount, int edge_count, int *edges, struct LP *lp) + struct LP *lp, + struct TSPData *data) { + int ncount = data->node_count; + int edge_count = data->edge_count; + int *edges = data->edge_list; + int rval = 0; int is_infeasible = 0; @@ -53,8 +77,8 @@ int TSP_find_violated_subtour_elimination_cut( struct Graph G; graph_init(&G); - rval = lp_optimize(lp, &is_infeasible); - ABORT_IF(rval, "lp_optimize failed\n"); + rval = LP_optimize(lp, &is_infeasible); + ABORT_IF(rval, "LP_optimize failed\n"); ABORT_IF(is_infeasible, "LP is infeasible\n"); rval = graph_build(ncount, edge_count, edges, &G); @@ -77,8 +101,8 @@ int TSP_find_violated_subtour_elimination_cut( for (int i = 0; i < ncount; i++) marks[i] = 0; - rval = lp_get_x(lp, x); - ABORT_IF(rval, "lp_get_x failed\n"); + rval = LP_get_x(lp, x); + ABORT_IF(rval, "LP_get_x failed\n"); int round = 0; int delta_count = 0; @@ -87,7 +111,7 @@ int TSP_find_violated_subtour_elimination_cut( while (!TSP_is_graph_connected(&G, x, &island_count, island_sizes, island_start, island_nodes)) { - time_printf("Adding %d bnc_solve_node inequalities...\n", island_count); + time_printf("Adding %d BNC_solve_node inequalities...\n", island_count); for (int i = 0; i < island_count; i++) { get_delta(island_sizes[i], island_nodes + island_start[i], @@ -99,19 +123,19 @@ int TSP_find_violated_subtour_elimination_cut( time_printf("Reoptimizing (round %d)...\n", ++round); ABORT_IF(rval, "TSP_add_subtour_elimination_cut failed"); - rval = lp_optimize(lp, &is_infeasible); - ABORT_IF(rval, "lp_optimize failed\n"); + rval = LP_optimize(lp, &is_infeasible); + ABORT_IF(rval, "LP_optimize failed\n"); ABORT_IF(is_infeasible, "LP is infeasible\n"); double objval = 0; - rval = lp_get_obj_val(lp, &objval); - ABORT_IF(rval, "lp_get_obj_val failed\n"); + rval = LP_get_obj_val(lp, &objval); + ABORT_IF(rval, "LP_get_obj_val failed\n"); - rval = lp_get_x(lp, x); - ABORT_IF(rval, "lp_get_x failed\n"); + rval = LP_get_x(lp, x); + ABORT_IF(rval, "LP_get_x failed\n"); } - time_printf(" graph is TSP_is_graph_connected\n"); + time_printf(" graph is connected\n"); CLEANUP: graph_free(&G); @@ -122,7 +146,7 @@ int TSP_find_violated_subtour_elimination_cut( return rval; } -int TSP_add_subtour_elimination_cut(struct LP *lp, int deltacount, int *delta) +int TSP_add_subtour_elimination_cut(struct LP *lp, int delta_length, int *delta) { int rval = 0; char sense = 'G'; @@ -132,16 +156,16 @@ int TSP_add_subtour_elimination_cut(struct LP *lp, int deltacount, int *delta) double *rmatval; int *rmatind = delta; - rmatval = (double *) malloc(deltacount * sizeof(double)); + rmatval = (double *) malloc(delta_length * sizeof(double)); ABORT_IF(!rmatval, "out of memory for rmatval\n"); - for (int i = 0; i < deltacount; i++) + for (int i = 0; i < delta_length; i++) rmatval[i] = 1.0; - rval = lp_add_rows(lp, 1, deltacount, &rhs, &sense, &rmatbeg, rmatind, + rval = LP_add_rows(lp, 1, delta_length, &rhs, &sense, &rmatbeg, rmatind, rmatval); - ABORT_IF(rval, "lp_add_rows failed"); + ABORT_IF(rval, "LP_add_rows failed"); CLEANUP: if (rmatval) free(rmatval); @@ -149,8 +173,12 @@ int TSP_add_subtour_elimination_cut(struct LP *lp, int deltacount, int *delta) } int TSP_is_graph_connected( - struct Graph *G, double *x, int *island_count, int *island_sizes, - int *island_start, int *island_nodes) + struct Graph *G, + double *x, + int *island_count, + int *island_sizes, + int *island_start, + int *island_nodes) { for (int i = 0; i < G->node_count; i++) { @@ -180,7 +208,11 @@ int TSP_is_graph_connected( } int TSP_find_closest_neighbor_tour( - int start, int node_count, int edge_count, int *edges, int *elen, + int start, + int node_count, + int edge_count, + int *edges, + int *elen, int *path_length) { int rval; @@ -227,10 +259,13 @@ int TSP_find_closest_neighbor_tour( return rval; } -int TSP_read_problem( - char *filename, int *p_ncount, int *p_ecount, int **p_elist, - int **p_elen) +int TSP_read_problem(char *filename, struct TSPData *data) { + int *p_ncount = &data->node_count; + int *p_ecount = &data->edge_count; + int **p_elist = &data->edge_list; + int **p_elen = &data->edge_weights; + struct _IO_FILE *f = (struct _IO_FILE *) NULL; int i, j, end1, end2, w, rval = 0, ncount, ecount; int *elist = (int *) NULL, *elen = (int *) NULL; @@ -246,7 +281,7 @@ int TSP_read_problem( } } - if (filename && geometric_data == 0) + if (filename && GEOMETRIC_DATA == 0) { if (fscanf(f, "%d %d", &ncount, &ecount) != 2) { @@ -300,7 +335,7 @@ int TSP_read_problem( } else { - ncount = ncount_rand; + ncount = NODE_COUNT_RAND; } x = (double *) malloc(ncount * sizeof(double)); @@ -326,10 +361,10 @@ int TSP_read_problem( } else { - rval = CO759_build_xy(ncount, x, y, gridsize_rand); + rval = build_random_2d_points(ncount, x, y, GRID_SIZE_RAND); if (rval) { - fprintf(stderr, "CO759_build_xy failed\n"); + fprintf(stderr, "build_random_2d_points failed\n"); goto CLEANUP; } @@ -385,29 +420,28 @@ int TSP_read_problem( return rval; } -int TSP_add_cutting_planes(int ncount, int ecount, int *elist, struct LP *lp) +int TSP_add_cutting_planes(struct LP *lp, struct TSPData *data) { int rval = 0; - rval = TSP_find_violated_subtour_elimination_cut(ncount, ecount, elist, lp); + rval = TSP_find_violated_subtour_elimination_cut(lp, data); ABORT_IF (rval, "TSP_find_violated_subtour_elimination_cut failed\n"); CLEANUP: return rval; } -double TSP_find_initial_solution( - int *edge_weights, int *edge_list, int node_count, int edge_count) +double TSP_find_initial_solution(struct TSPData *data) { double best_val = 1e99; time_printf("Finding closest neighbor tour\n"); - for (int i = 0; i < node_count; i++) + for (int i = 0; i < data->node_count; i++) { int path_length = 0; - TSP_find_closest_neighbor_tour(i, node_count, edge_count, edge_list, - edge_weights, &path_length); + TSP_find_closest_neighbor_tour(i, data->node_count, data->edge_count, + data->edge_list, data->edge_weights, &path_length); if (best_val > path_length) best_val = path_length; } diff --git a/src/tsp.h b/src/tsp.h index da149b2..2c4160e 100644 --- a/src/tsp.h +++ b/src/tsp.h @@ -1,39 +1,48 @@ -// -// Created by isoron on 3/17/15. -// - -#ifndef ___TSP_H_ -#define ___TSP_H_ +#ifndef _PROJECT_TSP_H_ +#define _PROJECT_TSP_H_ #include "lp.h" #include "graph.h" -int add_all_subtours(int ncount, int ecount, int *elist, struct LP *lp); +struct TSPData +{ + int node_count; + int edge_count; + int *edge_list; + int *edge_weights; +}; + +int TSP_init_data(struct TSPData *data); + +void TSP_free_data(struct TSPData *data); int TSP_find_violated_subtour_elimination_cut - (int ncount, int ecount, int *elist, struct LP *lp); + (struct LP *lp, struct TSPData *data); int TSP_is_graph_connected( - struct Graph *G, double *x, int *island_count, int *island_sizes, - int *island_start, int *island_nodes); + struct Graph *G, + double *x, + int *island_count, + int *island_sizes, + int *island_start, + int *island_nodes); int TSP_find_closest_neighbor_tour( - int start, int node_count, int edge_count, int *edges, int *elen, + int start, + int node_count, + int edge_count, + int *edges, + int *elen, int *path_length); -int TSP_add_subtour_elimination_cut(struct LP *lp, int deltacount, int *delta); +int TSP_add_subtour_elimination_cut(struct LP *lp, int delta_length, int *delta); -int TSP_read_problem( - char *filename, int *p_ncount, int *p_ecount, int **p_elist, - int **p_elen); +int TSP_read_problem(char *filename, struct TSPData *data); -int TSP_add_cutting_planes(int ncount, int ecount, int *elist, struct LP *lp); +int TSP_add_cutting_planes(struct LP *lp, struct TSPData *data); -int TSP_init_lp( - int node_count, struct LP *lp, int edge_count, int *edge_weights, - int *edge_list); +int TSP_init_lp(struct LP *lp, struct TSPData *data); -double TSP_find_initial_solution - (int *edge_weights, int *edge_list, int node_count, int edge_count); +double TSP_find_initial_solution(struct TSPData *data); -#endif //_PROJECT_TSP_H_ +#endif diff --git a/src/util.c b/src/util.c index 7822140..f4bf1a3 100644 --- a/src/util.c +++ b/src/util.c @@ -1,103 +1,111 @@ -/****************************************************************************/ -/* */ -/* Utility Functions for CO759 */ -/* */ -/****************************************************************************/ - -#include "main.h" #include #include #include #include #include "util.h" -double util_get_current_time(void) +double get_current_time(void) { struct rusage ru; - getrusage (RUSAGE_SELF, &ru); + getrusage(RUSAGE_SELF, &ru); - return ((double) ru.ru_utime.tv_sec) + - ((double) ru.ru_utime.tv_usec)/1000000.0; + return ((double) ru.ru_utime.tv_sec) + + ((double) ru.ru_utime.tv_usec) / 1000000.0; } /* function for creating a random set of points in unit square */ -int CO759_build_xy (int ncount, double *xlist, double *ylist, int gridsize) +int build_random_2d_points( + int node_count, double *x_list, double *y_list, int grid_size) { int rval = 0, i, j, winner, x, y; int **hit = (int **) NULL, *hitcount = (int *) NULL; - printf ("Random %d point set, gridsize = %d\n", ncount, gridsize); - fflush (stdout); + printf("Random %d point set, grid_size = %d\n", node_count, grid_size); + fflush(stdout); - hit = (int **) malloc (gridsize * sizeof (int *)); - if (!hit) { - fprintf (stderr, "out of memory for hit\n"); - rval = 1; goto CLEANUP; + hit = (int **) malloc(grid_size * sizeof(int *)); + if (!hit) + { + fprintf(stderr, "out of memory for hit\n"); + rval = 1; + goto CLEANUP; } - for (i = 0; i < gridsize; i++) hit[i] = (int *) NULL; - - hitcount = (int *) malloc (gridsize * sizeof (int)); - if (!hitcount) { - fprintf (stderr, "out of memory for hitcount\n"); - rval = 1; goto CLEANUP; + for (i = 0; i < grid_size; i++) hit[i] = (int *) NULL; + + hitcount = (int *) malloc(grid_size * sizeof(int)); + if (!hitcount) + { + fprintf(stderr, "out of memory for hitcount\n"); + rval = 1; + goto CLEANUP; } - for (i = 0; i < gridsize; i++) hitcount[i] = 0; + for (i = 0; i < grid_size; i++) hitcount[i] = 0; - for (i = 0; i < ncount; i++) { + for (i = 0; i < node_count; i++) + { winner = 0; - do { - x = (int) (rand () % gridsize); - y = (int) (rand () % gridsize); + do + { + x = (int) (rand() % grid_size); + y = (int) (rand() % grid_size); /* check to see if (x,y) is a duplicate point */ - for (j = 0; j < hitcount[x]; j++) { + for (j = 0; j < hitcount[x]; j++) + { if (hit[x][j] == y) break; } - if (j == hitcount[x]) { + if (j == hitcount[x]) + { void *tmp_ptr = (void *) hit[x]; - tmp_ptr = realloc (tmp_ptr, (hitcount[x]+1)*sizeof (int)); - if (!tmp_ptr) { - fprintf (stderr, "out of member in realloc of hit\n"); - rval = 1; goto CLEANUP; + tmp_ptr = realloc(tmp_ptr, (hitcount[x] + 1) * sizeof(int)); + if (!tmp_ptr) + { + fprintf(stderr, "out of member in realloc of hit\n"); + rval = 1; + goto CLEANUP; } hit[x] = (int *) tmp_ptr; hit[x][hitcount[x]] = y; hitcount[x]++; winner = 1; } - if (!winner) { - printf ("X"); fflush (stdout); + if (!winner) + { + printf("X"); + fflush(stdout); } } while (!winner); - xlist[i] = (double) x; - ylist[i] = (double) y; + x_list[i] = (double) x; + y_list[i] = (double) y; } -CLEANUP: + CLEANUP: - printf ("\n"); + printf("\n"); - if (hit) { - for (i = 0; i < gridsize; i++) { - if (hit[i]) free (hit[i]); + if (hit) + { + for (i = 0; i < grid_size; i++) + { + if (hit[i]) free(hit[i]); } - free (hit); + free(hit); } - if (hitcount) free (hitcount); + if (hitcount) free(hitcount); return rval; } -double initial_time = 0; +static double initial_time = 0; void time_printf(const char *fmt, ...) { - if(initial_time == 0) - initial_time = util_get_current_time(); + if (initial_time == 0) + initial_time = get_current_time(); - printf("[%10.2lf] ", util_get_current_time() - initial_time); + printf("[%10.2lf] ", get_current_time() - initial_time); va_list args; va_start(args, fmt); @@ -107,9 +115,9 @@ void time_printf(const char *fmt, ...) fflush(stdout); } -void next_set (int sz, int *Set) +void next_set(int sz, int *set) { - int i; - for (i=0; i < sz-1 && Set[i]+1 == Set[i+1]; i++) Set[i] = i; - Set[i] = Set[i]+1; + int i; + for (i = 0; i < sz - 1 && set[i] + 1 == set[i + 1]; i++) set[i] = i; + set[i] = set[i] + 1; } \ No newline at end of file diff --git a/src/util.h b/src/util.h index f871309..a8f3eca 100644 --- a/src/util.h +++ b/src/util.h @@ -1,17 +1,18 @@ -#ifndef __CO759_UTIL_H -#define __CO759_UTIL_H +#ifndef _PROJECT_UTIL_H_ +#define _PROJECT_UTIL_H_ #define ABORT_IF(cond, msg) if(cond) { \ fprintf(stderr, msg); rval = 1; goto CLEANUP; } -double util_get_current_time(void); +double get_current_time(void); -int CO759_build_xy(int ncount, double *xlist, double *ylist, int gridsize); +int build_random_2d_points + (int node_count, double *x_list, double *y_list, int grid_size); -double util_get_current_time(void); +double get_current_time(void); void time_printf(const char *fmt, ...); -void next_set(int sz, int *Set); +void next_set(int sz, int *set); -#endif /* __CO759_UTIL_H */ +#endif