Refactoring

master
Alinson S. Xavier 11 years ago
parent ad8e20c62b
commit 67ca00a0e0

@ -8,7 +8,6 @@ set(CMAKE_SOURCE_DIR src)
set(CMAKE_C_FLAGS "-O3 -g -Wall -pedantic -g --std=c11 -Winline") set(CMAKE_C_FLAGS "-O3 -g -Wall -pedantic -g --std=c11 -Winline")
set(SOURCE_FILES set(SOURCE_FILES
src/lp.c src/lp.c
src/lp.h src/lp.h

@ -3,25 +3,81 @@
#include <math.h> #include <math.h>
#include "lp.h" #include "lp.h"
#include "branch_and_cut.h" #include "branch_and_cut.h"
#include "tsp.h"
#include "util.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( static int BNC_is_integral(double *x, int num_cols);
struct LP *lp, double *best_val, int ncount, int ecount, int *elist,
int depth) 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; int rval = 0;
double *x = (double *) NULL; double *x = (double *) NULL;
time_printf("Optimizing...\n"); time_printf("Optimizing...\n");
int is_infeasible; int is_infeasible;
rval = lp_optimize(lp, &is_infeasible); rval = LP_optimize(lp, &is_infeasible);
ABORT_IF (rval, "lp_optimize failed\n"); ABORT_IF (rval, "LP_optimize failed\n");
if (is_infeasible) if (is_infeasible)
{ {
@ -30,8 +86,8 @@ int bnc_solve_node(
} }
double objval; double objval;
rval = lp_get_obj_val(lp, &objval); rval = LP_get_obj_val(lp, &objval);
ABORT_IF (rval, "lp_get_obj_val failed\n"); ABORT_IF (rval, "LP_get_obj_val failed\n");
time_printf(" objective value = %.2f\n", objval); time_printf(" objective value = %.2f\n", objval);
@ -43,25 +99,30 @@ int bnc_solve_node(
goto CLEANUP; 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"); ABORT_IF(!x, "could not allocate x\n");
rval = lp_get_x(lp, x); rval = LP_get_x(lp, x);
ABORT_IF(rval, "lp_get_x failed\n"); ABORT_IF(rval, "LP_get_x failed\n");
rval = TSP_add_cutting_planes(ncount, ecount, elist, lp); 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"); ABORT_IF(rval, "TSP_add_cutting_planes failed\n");
}
rval = lp_optimize(lp, &is_infeasible); rval = LP_optimize(lp, &is_infeasible);
ABORT_IF (rval, "lp_optimize failed\n"); ABORT_IF (rval, "LP_optimize failed\n");
rval = lp_get_obj_val(lp, &objval); rval = LP_get_obj_val(lp, &objval);
ABORT_IF(rval, "lp_get_obj_val failed\n"); ABORT_IF(rval, "LP_get_obj_val failed\n");
rval = lp_get_x(lp, x); rval = LP_get_x(lp, x);
ABORT_IF(rval, "lp_get_x failed\n"); 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"); time_printf(" solution is integral\n");
@ -71,11 +132,12 @@ int bnc_solve_node(
time_printf("Found a better integral solution:\n"); time_printf("Found a better integral solution:\n");
time_printf(" objval = %.2lf **\n", objval); time_printf(" objval = %.2lf **\n", objval);
} }
} else }
else
{ {
time_printf(" solution is fractional\n"); time_printf(" solution is fractional\n");
rval = bnc_branch_node(lp, x, ncount, ecount, depth, best_val, elist); rval = BNC_branch_node(bnc, x, depth);
ABORT_IF(rval, "bnc_branch_node failed\n"); ABORT_IF(rval, "BNC_branch_node failed\n");
} }
CLEANUP: CLEANUP:
@ -83,95 +145,66 @@ int bnc_solve_node(
return rval; return rval;
} }
int bnc_branch_node( static int BNC_branch_node(struct BNC *bnc, double *x, int depth)
struct LP *lp, double *x, int ncount, int ecount, int depth,
double *best_val, int *elist)
{ {
int rval = 0; 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, int num_cols = LP_get_num_cols(lp);
x[best_index], depth); int best_branch_var = BNC_find_best_branching_var(x, num_cols);
time_printf("Fixing variable x%d to one...\n", best_index); time_printf("Branching on variable x%d = %.6lf (depth %d)...\n",
rval = lp_change_bound(lp, best_index, 'L', 1.0); best_branch_var, x[best_branch_var], depth);
ABORT_IF(rval, "lp_change_bound failed\n");
rval = bnc_solve_node(lp, best_val, ncount, ecount, elist, depth + 1); time_printf("Fixing variable x%d to one...\n", best_branch_var);
ABORT_IF(rval, "bnc_solve_node failed\n"); 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); rval = BNC_solve_node(bnc, depth + 1);
ABORT_IF(rval, "lp_change_bound failed\n"); 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_branch_var, 'L', 0.0);
rval = lp_change_bound(lp, best_index, 'U', 0.0); ABORT_IF(rval, "LP_change_bound failed\n");
ABORT_IF(rval, "lp_change_bound failed\n");
rval = bnc_solve_node(lp, best_val, ncount, ecount, elist, depth + 1); time_printf("Fixing variable x%d to zero...\n", best_branch_var);
ABORT_IF(rval, "bnc_solve_node failed\n"); 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); rval = BNC_solve_node(bnc, depth + 1);
ABORT_IF(rval, "lp_change_bound failed\n"); 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: CLEANUP:
return rval; 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; for (int i = 0; i < num_cols; i++)
double best_index_frac = 1.0; if (x[i] > LP_EPSILON && x[i] < 1.0 - LP_EPSILON)
return 0;
for (int j = 0; j < length; j++) return 1;
{
if (fabs(x[j] - 0.5) < best_index_frac)
{
best_index = j;
best_index_frac = fabs(x[j] - 0.5);
}
}
return best_index;
} }
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; best_index = i;
break; 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;
} }

@ -3,15 +3,23 @@
#include "lp.h" #include "lp.h"
int bnc_solve_node( struct BNC
struct LP *lp, double *best_val, int ncount, int ecount, int *elist, {
int depth); struct LP *lp;
double best_val;
int *problem_data;
int bnc_branch_node( int (*problem_init_lp)(struct LP *, void *);
struct LP *lp, double *x, int ncount, int ecount, int depth,
double *current_val, int *elist);
int bnc_init_lp( int (*problem_add_cutting_planes)(struct LP *, void *);
struct LP *lp, int node_count, int edge_count, int *edge_list, int *edge_weights); };
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_ #endif //_PROJECT_BRANCH_AND_CUT_H_

@ -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)); (struct AdjObj *) malloc(2 * edge_count * sizeof(struct AdjObj));
ABORT_IF(!G->node_list, "could not allocate G->node_list\n"); 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++) for (int i = 0; i < node_count; i++)
G->node_list[i].deg = 0; G->node_list[i].deg = 0;
@ -109,8 +109,13 @@ int euclid_edgelen(int i, int j, double *x, double *y)
} }
void get_delta( void get_delta(
int island_node_count, int *island_nodes, int edge_count, int *edges, int island_node_count,
int *delta_count, int *delta, int *marks) int *island_nodes,
int edge_count,
int *edges,
int *delta_count,
int *delta,
int *marks)
{ {
for (int i = 0; i < island_node_count; i++) for (int i = 0; i < island_node_count; i++)
marks[island_nodes[i]] = 1; marks[island_nodes[i]] = 1;

@ -1,8 +1,32 @@
#ifndef __GRAPH_H_ #ifndef _PROJECT_GRAPH_H_
#define __GRAPH_H_ #define _PROJECT_GRAPH_H_
#include "main.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( void graph_dfs(
int n, struct Graph *G, double *x, int *icount, int *island); 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); 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); int euclid_edgelen(int i, int j, double *x, double *y);
void get_delta( void get_delta(
int nsize, int *nlist, int ecount, int *elist, int *deltacount, int nsize,
int *delta, int *marks); int *nlist,
int ecount,
#endif //___GRAPH_H_ int *elist,
int *deltacount,
int *delta,
int *marks);
#endif

@ -7,11 +7,11 @@
#define LP_EPSILON 0.000001 #define LP_EPSILON 0.000001
int lp_open(struct LP *lp) int LP_open(struct LP *lp)
{ {
int rval = 0; int rval = 0;
lp->cplex_lp = (CPXLPptr)NULL; lp->cplex_lp = (CPXLPptr) NULL;
lp->cplex_env = CPXopenCPLEX(&rval); lp->cplex_env = CPXopenCPLEX(&rval);
if (rval) if (rval)
{ {
@ -23,7 +23,7 @@ int lp_open(struct LP *lp)
return rval; return rval;
} }
void lp_free(struct LP *lp) void LP_free(struct LP *lp)
{ {
if (!lp) return; if (!lp) return;
if (!lp->cplex_env) return; if (!lp->cplex_env) return;
@ -35,7 +35,7 @@ void lp_free(struct LP *lp)
lp->cplex_env = 0; 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; int rval = 0;
char nambuf[MAX_NAME_LENGTH]; char nambuf[MAX_NAME_LENGTH];
@ -52,12 +52,11 @@ int lp_create(struct LP *lp, const char *name)
return rval; 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; int rval = 0;
rval = CPXnewrows(lp->cplex_env, lp->cplex_lp, 1, &rhs, &sense, rval = CPXnewrows(lp->cplex_env, lp->cplex_lp, 1, &rhs, &sense, 0, 0);
(double *) NULL, (char **) NULL);
ABORT_IF(rval, "CPXnewrows failed\n"); ABORT_IF(rval, "CPXnewrows failed\n");
@ -65,14 +64,20 @@ int lp_new_row(struct LP *lp, char sense, double rhs)
return rval; return rval;
} }
int lp_add_rows( int LP_add_rows(
struct LP *lp, int newrows, int newnz, double *rhs, char *sense, struct LP *lp,
int *rmatbeg, int *rmatind, double *rmatval) int newrows,
int newnz,
double *rhs,
char *sense,
int *rmatbeg,
int *rmatind,
double *rmatval)
{ {
int rval = 0; int rval = 0;
rval = CPXaddrows(lp->cplex_env, lp->cplex_lp, 0, newrows, newnz, rhs, 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"); ABORT_IF(rval, "CPXaddrows failed\n");
@ -80,9 +85,16 @@ int lp_add_rows(
return rval; return rval;
} }
int lp_add_cols( int LP_add_cols(
struct LP *lp, int newcols, int newnz, double *obj, int *cmatbeg, struct LP *lp,
int *cmatind, double *cmatval, double *lb, double *ub) int newcols,
int newnz,
double *obj,
int *cmatbeg,
int *cmatind,
double *cmatval,
double *lb,
double *ub)
{ {
int rval = 0; int rval = 0;
@ -95,7 +107,7 @@ int lp_add_cols(
return rval; 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; int rval = 0;
@ -107,7 +119,7 @@ int lp_change_bound(struct LP *lp, int col, char lower_or_upper, double bnd)
return rval; return rval;
} }
int lp_optimize(struct LP *lp, int *infeasible) int LP_optimize(struct LP *lp, int *infeasible)
{ {
int rval = 0, solstat; int rval = 0, solstat;
@ -134,7 +146,7 @@ int lp_optimize(struct LP *lp, int *infeasible)
return rval; 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; int rval = 0;
@ -145,7 +157,7 @@ int lp_get_obj_val(struct LP *lp, double *obj)
return rval; return rval;
} }
int lp_get_x(struct LP *lp, double *x) int LP_get_x(struct LP *lp, double *x)
{ {
int rval = 0; int rval = 0;
@ -159,7 +171,12 @@ int lp_get_x(struct LP *lp, double *x)
return rval; 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; int rval = 0;

@ -1,5 +1,5 @@
#ifndef __MAIN_ #ifndef _PROJECT_LP_H_
#define __MAIN_ #define _PROJECT_LP_H_
#include <cplex.h> #include <cplex.h>
@ -13,28 +13,45 @@ struct LP
static const int MAX_NAME_LENGTH = 100; 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 LP_add_rows(
int *rmatbeg, int *rmatind, double *rmatval); 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 LP_add_cols(
int *cmatbeg, int *cmatind, double *cmatval, double *lb, double *ub); 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 #endif

@ -7,82 +7,69 @@
#include "tsp.h" #include "tsp.h"
#include "branch_and_cut.h" #include "branch_and_cut.h"
char *fname = (char *) NULL; char *INPUT_FILENAME = 0;
int seed = 0; unsigned int SEED = 0;
int geometric_data = 0; int GEOMETRIC_DATA = 0;
int ncount_rand = 0; int NODE_COUNT_RAND = 0;
int gridsize_rand = 100; int GRID_SIZE_RAND = 100;
int use_all_subtours = 0;
static int parse_arguments(int ac, char **av);
static void print_usage(char *f);
int main(int ac, char **av) int main(int ac, char **av)
{ {
int rval = 0; 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(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); printf("Seed = %d\n", SEED);
srand(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");
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, rval = TSP_read_problem(INPUT_FILENAME, &data);
node_count, edge_count); 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; bnc.best_val = TSP_find_initial_solution(&data);
lp = (struct LP *) malloc(sizeof(struct LP *)); 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); rval = BNC_init_lp(&bnc);
ABORT_IF(rval, "bnc_init_lp failed\n"); ABORT_IF(rval, "BNC_init_lp failed");
rval = bnc_solve_node(lp, &best_val, node_count, edge_count, edge_list, 1); rval = BNC_solve(&bnc);
ABORT_IF(rval, "bnc_solve_node failed\n"); ABORT_IF(rval, "BNC_solve_node failed\n");
time_printf("Optimal integral solution:\n"); time_printf("Optimal integral solution:\n");
time_printf(" objective value = %.2lf **\n", best_val); time_printf(" obj value = %.2lf **\n", bnc.best_val);
printf("\nRunning Time: %.2f seconds\n",
util_get_current_time() - initial_time);
fflush(stdout);
CLEANUP: CLEANUP:
if (tlist) free(tlist); BNC_free(&bnc);
if (edge_list) free(edge_list); TSP_free_data(&data);
if (edge_weights) free(edge_weights);
return rval; return rval;
} }
int parseargs(int ac, char **av) static int parse_arguments(int ac, char **av)
{ {
int rval = 0;
int c; int c;
if (ac == 1) if (ac == 1)
{ {
usage(av[0]); print_usage(av[0]);
return 1; return 1;
} }
@ -90,46 +77,49 @@ int parseargs(int ac, char **av)
{ {
switch (c) switch (c)
{ {
case 'a': case 'a':;
use_all_subtours = 1;
break; break;
case 'b': case 'b':
gridsize_rand = atoi(optarg); GRID_SIZE_RAND = atoi(optarg);
break; break;
case 'g': case 'g':
geometric_data = 1; GEOMETRIC_DATA = 1;
break; break;
case 'k': case 'k':
ncount_rand = atoi(optarg); NODE_COUNT_RAND = atoi(optarg);
break; break;
case 's': case 's':
seed = atoi(optarg); SEED = (unsigned) atoi(optarg);
break; break;
case '?': case '?':
default: default:
usage(av[0]); print_usage(av[0]);
return 1; return 1;
} }
} }
if (optind < ac) fname = av[optind++]; if (optind < ac) INPUT_FILENAME = av[optind++];
if (optind != ac) if (optind != ac)
{ {
usage(av[0]); print_usage(av[0]);
return 1; 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" fprintf(stderr, "Usage: %s [-see below-] [prob_file]\n"
" -a add all subtours cuts at once\n" " -a add all subtours cuts at once\n"
" -b d gridsize d for random problems\n" " -b d gridsize d for random problems\n"
" -g prob_file has x-y coordinates\n" " -g prob_file has x-y coordinates\n"
" -k d generate problem with d cities\n" " -k d generate problem with d cities\n"
" -s d random seed\n", f); " -s d random SEED\n", f);
} }

@ -1,39 +1,10 @@
#ifndef __MAIN_H_ #ifndef _PROJECT_MAIN_H_
#define __MAIN_H_ #define _PROJECT_MAIN_H_
struct AdjObj extern char *INPUT_FILENAME;
{ extern unsigned int SEED;
int n; extern int GEOMETRIC_DATA;
/* index of neighbor node */ extern int NODE_COUNT_RAND;
int e; /* index of adj joining neighbor */ extern int GRID_SIZE_RAND;
};
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;
#endif #endif

@ -4,17 +4,36 @@
#include "tsp.h" #include "tsp.h"
#include "util.h" #include "util.h"
int TSP_init_lp( int TSP_init_data(struct TSPData *data)
int node_count, struct LP *lp, int edge_count, int *edge_weights,
int *edge_list)
{ {
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; int rval = 0;
/* Build a row for each degree equation */ /* Build a row for each degree equation */
for (int i = 0; i < node_count; i++) for (int i = 0; i < node_count; i++)
{ {
rval = lp_new_row(lp, 'E', 2.0); rval = LP_new_row(lp, 'E', 2.0);
ABORT_IF(rval, "lp_new_row failed\n"); ABORT_IF(rval, "LP_new_row failed\n");
} }
/* Build a column for each edge of the graph */ /* Build a column for each edge of the graph */
@ -27,10 +46,10 @@ int TSP_init_lp(
double obj = (double) edge_weights[j]; double obj = (double) edge_weights[j];
int cmatind[] = {edge_list[2 * j], edge_list[2 * j + 1]}; 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); &ub);
ABORT_IF(rval, "lp_add_cols failed\n"); ABORT_IF(rval, "LP_add_cols failed\n");
} }
CLEANUP: CLEANUP:
@ -38,8 +57,13 @@ int TSP_init_lp(
} }
int TSP_find_violated_subtour_elimination_cut( 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 rval = 0;
int is_infeasible = 0; int is_infeasible = 0;
@ -53,8 +77,8 @@ int TSP_find_violated_subtour_elimination_cut(
struct Graph G; struct Graph G;
graph_init(&G); graph_init(&G);
rval = lp_optimize(lp, &is_infeasible); rval = LP_optimize(lp, &is_infeasible);
ABORT_IF(rval, "lp_optimize failed\n"); ABORT_IF(rval, "LP_optimize failed\n");
ABORT_IF(is_infeasible, "LP is infeasible\n"); ABORT_IF(is_infeasible, "LP is infeasible\n");
rval = graph_build(ncount, edge_count, edges, &G); 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++) for (int i = 0; i < ncount; i++)
marks[i] = 0; marks[i] = 0;
rval = lp_get_x(lp, x); rval = LP_get_x(lp, x);
ABORT_IF(rval, "lp_get_x failed\n"); ABORT_IF(rval, "LP_get_x failed\n");
int round = 0; int round = 0;
int delta_count = 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, while (!TSP_is_graph_connected(&G, x, &island_count, island_sizes,
island_start, island_nodes)) 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++) for (int i = 0; i < island_count; i++)
{ {
get_delta(island_sizes[i], island_nodes + island_start[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); time_printf("Reoptimizing (round %d)...\n", ++round);
ABORT_IF(rval, "TSP_add_subtour_elimination_cut failed"); ABORT_IF(rval, "TSP_add_subtour_elimination_cut failed");
rval = lp_optimize(lp, &is_infeasible); rval = LP_optimize(lp, &is_infeasible);
ABORT_IF(rval, "lp_optimize failed\n"); ABORT_IF(rval, "LP_optimize failed\n");
ABORT_IF(is_infeasible, "LP is infeasible\n"); ABORT_IF(is_infeasible, "LP is infeasible\n");
double objval = 0; double objval = 0;
rval = lp_get_obj_val(lp, &objval); rval = LP_get_obj_val(lp, &objval);
ABORT_IF(rval, "lp_get_obj_val failed\n"); ABORT_IF(rval, "LP_get_obj_val failed\n");
rval = lp_get_x(lp, x); rval = LP_get_x(lp, x);
ABORT_IF(rval, "lp_get_x failed\n"); ABORT_IF(rval, "LP_get_x failed\n");
} }
time_printf(" graph is TSP_is_graph_connected\n"); time_printf(" graph is connected\n");
CLEANUP: CLEANUP:
graph_free(&G); graph_free(&G);
@ -122,7 +146,7 @@ int TSP_find_violated_subtour_elimination_cut(
return rval; 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; int rval = 0;
char sense = 'G'; char sense = 'G';
@ -132,16 +156,16 @@ int TSP_add_subtour_elimination_cut(struct LP *lp, int deltacount, int *delta)
double *rmatval; double *rmatval;
int *rmatind = delta; 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"); 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; 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); rmatval);
ABORT_IF(rval, "lp_add_rows failed"); ABORT_IF(rval, "LP_add_rows failed");
CLEANUP: CLEANUP:
if (rmatval) free(rmatval); 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( int TSP_is_graph_connected(
struct Graph *G, double *x, int *island_count, int *island_sizes, struct Graph *G,
int *island_start, int *island_nodes) double *x,
int *island_count,
int *island_sizes,
int *island_start,
int *island_nodes)
{ {
for (int i = 0; i < G->node_count; i++) 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 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 *path_length)
{ {
int rval; int rval;
@ -227,10 +259,13 @@ int TSP_find_closest_neighbor_tour(
return rval; return rval;
} }
int TSP_read_problem( int TSP_read_problem(char *filename, struct TSPData *data)
char *filename, int *p_ncount, int *p_ecount, int **p_elist,
int **p_elen)
{ {
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; struct _IO_FILE *f = (struct _IO_FILE *) NULL;
int i, j, end1, end2, w, rval = 0, ncount, ecount; int i, j, end1, end2, w, rval = 0, ncount, ecount;
int *elist = (int *) NULL, *elen = (int *) NULL; 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) if (fscanf(f, "%d %d", &ncount, &ecount) != 2)
{ {
@ -300,7 +335,7 @@ int TSP_read_problem(
} }
else else
{ {
ncount = ncount_rand; ncount = NODE_COUNT_RAND;
} }
x = (double *) malloc(ncount * sizeof(double)); x = (double *) malloc(ncount * sizeof(double));
@ -326,10 +361,10 @@ int TSP_read_problem(
} }
else else
{ {
rval = CO759_build_xy(ncount, x, y, gridsize_rand); rval = build_random_2d_points(ncount, x, y, GRID_SIZE_RAND);
if (rval) if (rval)
{ {
fprintf(stderr, "CO759_build_xy failed\n"); fprintf(stderr, "build_random_2d_points failed\n");
goto CLEANUP; goto CLEANUP;
} }
@ -385,29 +420,28 @@ int TSP_read_problem(
return rval; 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; 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"); ABORT_IF (rval, "TSP_find_violated_subtour_elimination_cut failed\n");
CLEANUP: CLEANUP:
return rval; return rval;
} }
double TSP_find_initial_solution( double TSP_find_initial_solution(struct TSPData *data)
int *edge_weights, int *edge_list, int node_count, int edge_count)
{ {
double best_val = 1e99; double best_val = 1e99;
time_printf("Finding closest neighbor tour\n"); 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; int path_length = 0;
TSP_find_closest_neighbor_tour(i, node_count, edge_count, edge_list, TSP_find_closest_neighbor_tour(i, data->node_count, data->edge_count,
edge_weights, &path_length); data->edge_list, data->edge_weights, &path_length);
if (best_val > path_length) best_val = path_length; if (best_val > path_length) best_val = path_length;
} }

@ -1,39 +1,48 @@
// #ifndef _PROJECT_TSP_H_
// Created by isoron on 3/17/15. #define _PROJECT_TSP_H_
//
#ifndef ___TSP_H_
#define ___TSP_H_
#include "lp.h" #include "lp.h"
#include "graph.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 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( int TSP_is_graph_connected(
struct Graph *G, double *x, int *island_count, int *island_sizes, struct Graph *G,
int *island_start, int *island_nodes); double *x,
int *island_count,
int *island_sizes,
int *island_start,
int *island_nodes);
int TSP_find_closest_neighbor_tour( 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 *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( int TSP_read_problem(char *filename, struct TSPData *data);
char *filename, int *p_ncount, int *p_ecount, int **p_elist,
int **p_elen);
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 TSP_init_lp(struct LP *lp, struct TSPData *data);
int node_count, struct LP *lp, int edge_count, int *edge_weights,
int *edge_list);
double TSP_find_initial_solution double TSP_find_initial_solution(struct TSPData *data);
(int *edge_weights, int *edge_list, int node_count, int edge_count);
#endif //_PROJECT_TSP_H_ #endif

@ -1,103 +1,111 @@
/****************************************************************************/
/* */
/* Utility Functions for CO759 */
/* */
/****************************************************************************/
#include "main.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <stdarg.h> #include <stdarg.h>
#include "util.h" #include "util.h"
double util_get_current_time(void) double get_current_time(void)
{ {
struct rusage ru; struct rusage ru;
getrusage (RUSAGE_SELF, &ru); getrusage(RUSAGE_SELF, &ru);
return ((double) ru.ru_utime.tv_sec) + return ((double) ru.ru_utime.tv_sec)
((double) ru.ru_utime.tv_usec)/1000000.0; + ((double) ru.ru_utime.tv_usec) / 1000000.0;
} }
/* function for creating a random set of points in unit square */ /* 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 rval = 0, i, j, winner, x, y;
int **hit = (int **) NULL, *hitcount = (int *) NULL; int **hit = (int **) NULL, *hitcount = (int *) NULL;
printf ("Random %d point set, gridsize = %d\n", ncount, gridsize); printf("Random %d point set, grid_size = %d\n", node_count, grid_size);
fflush (stdout); fflush(stdout);
hit = (int **) malloc (gridsize * sizeof (int *)); hit = (int **) malloc(grid_size * sizeof(int *));
if (!hit) { if (!hit)
fprintf (stderr, "out of memory for hit\n"); {
rval = 1; goto CLEANUP; fprintf(stderr, "out of memory for hit\n");
rval = 1;
goto CLEANUP;
} }
for (i = 0; i < gridsize; i++) hit[i] = (int *) NULL; for (i = 0; i < grid_size; i++) hit[i] = (int *) NULL;
hitcount = (int *) malloc (gridsize * sizeof (int)); hitcount = (int *) malloc(grid_size * sizeof(int));
if (!hitcount) { if (!hitcount)
fprintf (stderr, "out of memory for hitcount\n"); {
rval = 1; goto CLEANUP; 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; winner = 0;
do { do
x = (int) (rand () % gridsize); {
y = (int) (rand () % gridsize); x = (int) (rand() % grid_size);
y = (int) (rand() % grid_size);
/* check to see if (x,y) is a duplicate point */ /* 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 (hit[x][j] == y) break;
} }
if (j == hitcount[x]) { if (j == hitcount[x])
{
void *tmp_ptr = (void *) hit[x]; void *tmp_ptr = (void *) hit[x];
tmp_ptr = realloc (tmp_ptr, (hitcount[x]+1)*sizeof (int)); tmp_ptr = realloc(tmp_ptr, (hitcount[x] + 1) * sizeof(int));
if (!tmp_ptr) { if (!tmp_ptr)
fprintf (stderr, "out of member in realloc of hit\n"); {
rval = 1; goto CLEANUP; fprintf(stderr, "out of member in realloc of hit\n");
rval = 1;
goto CLEANUP;
} }
hit[x] = (int *) tmp_ptr; hit[x] = (int *) tmp_ptr;
hit[x][hitcount[x]] = y; hit[x][hitcount[x]] = y;
hitcount[x]++; hitcount[x]++;
winner = 1; winner = 1;
} }
if (!winner) { if (!winner)
printf ("X"); fflush (stdout); {
printf("X");
fflush(stdout);
} }
} while (!winner); } while (!winner);
xlist[i] = (double) x; x_list[i] = (double) x;
ylist[i] = (double) y; y_list[i] = (double) y;
} }
CLEANUP: CLEANUP:
printf ("\n"); printf("\n");
if (hit) { if (hit)
for (i = 0; i < gridsize; i++) { {
if (hit[i]) free (hit[i]); 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; return rval;
} }
double initial_time = 0; static double initial_time = 0;
void time_printf(const char *fmt, ...) void time_printf(const char *fmt, ...)
{ {
if(initial_time == 0) if (initial_time == 0)
initial_time = util_get_current_time(); 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_list args;
va_start(args, fmt); va_start(args, fmt);
@ -107,9 +115,9 @@ void time_printf(const char *fmt, ...)
fflush(stdout); fflush(stdout);
} }
void next_set (int sz, int *Set) void next_set(int sz, int *set)
{ {
int i; int i;
for (i=0; i < sz-1 && Set[i]+1 == Set[i+1]; i++) Set[i] = i; for (i = 0; i < sz - 1 && set[i] + 1 == set[i + 1]; i++) set[i] = i;
Set[i] = Set[i]+1; set[i] = set[i] + 1;
} }

@ -1,17 +1,18 @@
#ifndef __CO759_UTIL_H #ifndef _PROJECT_UTIL_H_
#define __CO759_UTIL_H #define _PROJECT_UTIL_H_
#define ABORT_IF(cond, msg) if(cond) { \ #define ABORT_IF(cond, msg) if(cond) { \
fprintf(stderr, msg); rval = 1; goto CLEANUP; } 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 time_printf(const char *fmt, ...);
void next_set(int sz, int *Set); void next_set(int sz, int *set);
#endif /* __CO759_UTIL_H */ #endif