First version of the project

master
Alinson S. Xavier 11 years ago
commit ad8e20c62b

@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.1)
project(project)
include_directories(/opt/cplex-12.4/distribution/cplex/include/ilcplex)
set(CMAKE_BINARY_DIR bin)
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
src/main.c
src/main.h
src/util.c
src/util.h
src/graph.c
src/graph.h
src/tsp.h
src/tsp.c
src/branch_and_cut.h
src/branch_and_cut.c)
add_executable(project ${SOURCE_FILES} )
target_link_libraries(project cplex m pthread)

@ -0,0 +1,23 @@
10 22
0 9 1
0 8 1
0 1 2
0 7 4
0 4 3
1 8 2
1 4 3
1 6 5
2 5 8
2 7 4
2 3 2
2 6 6
3 5 6
3 7 2
4 7 4
4 6 2
5 8 4
5 9 4
5 7 5
6 7 5
7 9 4
8 9 1

@ -0,0 +1,77 @@
76
3600 2300
3100 3300
4700 5750
5400 5750
5608 7103
4493 7102
3600 6950
3100 7250
4700 8450
5400 8450
5610 10053
4492 10052
3600 10800
3100 10950
4700 11650
5400 11650
6650 10800
7300 10950
7300 7250
6650 6950
7300 3300
6650 2300
5400 1600
8350 2300
7850 3300
9450 5750
10150 5750
10358 7103
9243 7102
8350 6950
7850 7250
9450 8450
10150 8450
10360 10053
9242 10052
8350 10800
7850 10950
9450 11650
10150 11650
11400 10800
12050 10950
12050 7250
11400 6950
12050 3300
11400 2300
10150 1600
13100 2300
12600 3300
14200 5750
14900 5750
15108 7103
13993 7102
13100 6950
12600 7250
14200 8450
14900 8450
15110 10053
13992 10052
13100 10800
12600 10950
14200 11650
14900 11650
16150 10800
16800 10950
16800 7250
16150 6950
16800 3300
16150 2300
14900 1600
19800 800
19800 10000
19800 11900
19800 12200
200 12200
200 1100
200 800

@ -0,0 +1,11 @@
10
64 96
80 39
69 23
72 42
48 67
58 43
81 34
79 17
30 23
42 67

@ -0,0 +1,16 @@
15
95 53
77 93
0 28
40 76
76 6
21 70
26 78
47 73
32 5
77 13
85 32
84 32
43 13
42 5
96 29

@ -0,0 +1,21 @@
20
95 53
77 93
0 28
40 76
76 6
21 70
26 78
47 73
32 5
77 13
85 32
84 32
43 13
42 5
96 29
84 21
90 18
98 44
91 25
73 70

@ -0,0 +1,26 @@
25
95 53
77 93
0 28
40 76
76 6
21 70
26 78
47 73
32 5
77 13
85 32
84 32
43 13
42 5
96 29
84 21
90 18
98 44
91 25
73 70
38 43
34 1
6 17
75 94
40 16

@ -0,0 +1,31 @@
30
95 53
77 93
0 28
40 76
76 6
21 70
26 78
47 73
32 5
77 13
85 32
84 32
43 13
42 5
96 29
84 21
90 18
98 44
91 25
73 70
38 43
34 1
6 17
75 94
40 16
29 34
28 68
5 74
70 66
95 56

@ -0,0 +1,41 @@
40
95 53
77 93
0 28
40 76
76 6
21 70
26 78
47 73
32 5
77 13
85 32
84 32
43 13
42 5
96 29
84 21
90 18
98 44
91 25
73 70
38 43
34 1
6 17
75 94
40 16
29 34
28 68
5 74
70 66
95 56
44 22
10 6
75 78
36 32
79 37
98 38
72 61
91 51
4 16
34 76

@ -0,0 +1,51 @@
50
95 53
77 93
0 28
40 76
76 6
21 70
26 78
47 73
32 5
77 13
85 32
84 32
43 13
42 5
96 29
84 21
90 18
98 44
91 25
73 70
38 43
34 1
6 17
75 94
40 16
29 34
28 68
5 74
70 66
95 56
44 22
10 6
75 78
36 32
79 37
98 38
72 61
91 51
4 16
34 76
50 76
10 40
85 69
18 84
43 20
15 59
53 36
72 0
71 73
17 55

@ -0,0 +1,177 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "lp.h"
#include "branch_and_cut.h"
#include "tsp.h"
#include "util.h"
int bnc_is_integral(double *x, int length);
int bnc_find_best_branch_var(double *x, int length);
int bnc_solve_node(
struct LP *lp, double *best_val, int ncount, int ecount, int *elist,
int depth)
{
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");
if (is_infeasible)
{
time_printf("Branch pruned by infeasibility.\n");
goto CLEANUP;
}
double objval;
rval = lp_get_obj_val(lp, &objval);
ABORT_IF (rval, "lp_get_obj_val failed\n");
time_printf(" objective value = %.2f\n", objval);
if (objval > *best_val)
{
time_printf("Branch pruned by bound (%.2lf > %.2lf).\n", objval,
*best_val);
rval = 0;
goto CLEANUP;
}
x = (double *) malloc(ecount * 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 = TSP_add_cutting_planes(ncount, ecount, elist, lp);
ABORT_IF(rval, "TSP_add_cutting_planes 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_x(lp, x);
ABORT_IF(rval, "lp_get_x failed\n");
if (bnc_is_integral(x, ecount))
{
time_printf(" solution is integral\n");
if (objval < *best_val)
{
*best_val = objval;
time_printf("Found a better integral solution:\n");
time_printf(" objval = %.2lf **\n", objval);
}
} 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");
}
CLEANUP:
if (x) free(x);
return rval;
}
int bnc_branch_node(
struct LP *lp, double *x, int ncount, int ecount, int depth,
double *best_val, int *elist)
{
int rval = 0;
int best_index = bnc_find_best_branch_var(x, ecount);
time_printf("Branching on variable x%d = %.6lf (depth %d)...\n", best_index,
x[best_index], depth);
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");
rval = bnc_solve_node(lp, best_val, ncount, ecount, elist, depth + 1);
ABORT_IF(rval, "bnc_solve_node failed\n");
rval = lp_change_bound(lp, best_index, 'L', 0.0);
ABORT_IF(rval, "lp_change_bound 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 = bnc_solve_node(lp, best_val, ncount, ecount, elist, depth + 1);
ABORT_IF(rval, "bnc_solve_node failed\n");
rval = lp_change_bound(lp, best_index, 'U', 1.0);
ABORT_IF(rval, "lp_change_bound failed\n");
time_printf("Finished branching on variable %d\n", best_index);
CLEANUP:
return rval;
}
int bnc_find_best_branch_var(double *x, int length)
{
int best_index = 0;
double best_index_frac = 1.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;
}
int bnc_is_integral(double *x, int length)
{
int all_integral = 1;
for (int j = 0; j < length; j++)
{
if (x[j] > LP_EPSILON && x[j] < 1.0 - LP_EPSILON)
{
all_integral = 0;
break;
}
}
return all_integral;
}
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;
}

@ -0,0 +1,17 @@
#ifndef _PROJECT_BRANCH_AND_CUT_H_
#define _PROJECT_BRANCH_AND_CUT_H_
#include "lp.h"
int bnc_solve_node(
struct LP *lp, double *best_val, int ncount, int ecount, int *elist,
int depth);
int bnc_branch_node(
struct LP *lp, double *x, int ncount, int ecount, int depth,
double *current_val, int *elist);
int bnc_init_lp(
struct LP *lp, int node_count, int edge_count, int *edge_list, int *edge_weights);
#endif //_PROJECT_BRANCH_AND_CUT_H_

@ -0,0 +1,127 @@
#include <malloc.h>
#include <math.h>
#include "main.h"
#include "graph.h"
#include "util.h"
#include "lp.h"
void graph_dfs(
int n, struct Graph *G, double *x, int *island_size, int *island_nodes)
{
*(island_nodes + (*island_size)) = n;
(*island_size)++;
struct Node *pn = &G->node_list[n];
pn->mark = 1;
for (int i = 0; i < pn->deg; i++)
{
if (x[pn->adj[i].e] > LP_EPSILON)
{
int neighbor = pn->adj[i].n;
if (G->node_list[neighbor].mark == 0)
graph_dfs(neighbor, G, x, island_size, island_nodes);
}
}
}
void graph_init(struct Graph *G)
{
if (!G) return;
G->node_list = 0;
G->adj_space = 0;
G->node_count = 0;
G->edge_count = 0;
}
void graph_free(struct Graph *G)
{
if (!G) return;
if (G->node_list) free(G->node_list);
if (G->adj_space) free(G->adj_space);
}
int graph_build(int node_count, int edge_count, int *edge_list, struct Graph *G)
{
int rval = 0;
struct Node *n;
struct AdjObj *p;
G->node_list = (struct Node *) malloc(node_count * sizeof(struct Node));
G->adj_space =
(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");
for (int i = 0; i < node_count; i++)
G->node_list[i].deg = 0;
for (int i = 0; i < edge_count; i++)
{
int a = edge_list[2 * i];
int b = edge_list[2 * i + 1];
G->node_list[a].deg++;
G->node_list[b].deg++;
}
p = G->adj_space;
for (int i = 0; i < node_count; i++)
{
G->node_list[i].adj = p;
p += G->node_list[i].deg;
G->node_list[i].deg = 0;
}
for (int i = 0; i < edge_count; i++)
{
int a = edge_list[2 * i];
int b = edge_list[2 * i + 1];
n = &G->node_list[a];
n->adj[n->deg].n = b;
n->adj[n->deg].e = i;
n->deg++;
n = &G->node_list[b];
n->adj[n->deg].n = a;
n->adj[n->deg].e = i;
n->deg++;
}
G->node_count = node_count;
G->edge_count = edge_count;
CLEANUP:
if (rval)
{
if (G->node_list) free(G->node_list);
if (G->adj_space) free(G->adj_space);
}
return rval;
}
int euclid_edgelen(int i, int j, double *x, double *y)
{
double t1 = x[i] - x[j], t2 = y[i] - y[j];
return (int) (sqrt(t1 * t1 + t2 * t2) + 0.5);
}
void get_delta(
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;
int k = 0;
for (int i = 0; i < edge_count; i++)
if (marks[edges[2 * i]] + marks[edges[2 * i + 1]] == 1)
delta[k++] = i;
*delta_count = k;
for (int i = 0; i < island_node_count; i++)
marks[island_nodes[i]] = 0;
}

@ -0,0 +1,21 @@
#ifndef __GRAPH_H_
#define __GRAPH_H_
#include "main.h"
void graph_dfs(
int n, struct Graph *G, double *x, int *icount, int *island);
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 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_

@ -0,0 +1,175 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cplex.h>
#include "lp.h"
#include "util.h"
#define LP_EPSILON 0.000001
int lp_open(struct LP *lp)
{
int rval = 0;
lp->cplex_lp = (CPXLPptr)NULL;
lp->cplex_env = CPXopenCPLEX(&rval);
if (rval)
{
fprintf(stderr, "CPXopenCPLEX failed, return code %d\n", rval);
goto CLEANUP;
}
CLEANUP:
return rval;
}
void lp_free(struct LP *lp)
{
if (!lp) return;
if (!lp->cplex_env) return;
if (lp->cplex_lp)
CPXfreeprob(lp->cplex_env, &(lp->cplex_lp));
CPXcloseCPLEX(&lp->cplex_env);
lp->cplex_env = 0;
}
int lp_create(struct LP *lp, const char *name)
{
int rval = 0;
char nambuf[MAX_NAME_LENGTH];
ABORT_IF(!lp->cplex_env, "cplex_env is null\n");
strncpy(nambuf, name, MAX_NAME_LENGTH);
nambuf[MAX_NAME_LENGTH - 1] = '\0';
lp->cplex_lp = CPXcreateprob(lp->cplex_env, &rval, nambuf);
ABORT_IF(rval, "CPXcreateprob failed\n");
CLEANUP:
return rval;
}
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);
ABORT_IF(rval, "CPXnewrows failed\n");
CLEANUP:
return rval;
}
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);
ABORT_IF(rval, "CPXaddrows failed\n");
CLEANUP:
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 rval = 0;
rval = CPXaddcols(lp->cplex_env, lp->cplex_lp, newcols, newnz, obj, cmatbeg,
cmatind, cmatval, lb, ub, (char **) NULL);
ABORT_IF(rval, "CPXaddcols failed\n");
CLEANUP:
return rval;
}
int lp_change_bound(struct LP *lp, int col, char lower_or_upper, double bnd)
{
int rval = 0;
rval = CPXchgbds(lp->cplex_env, lp->cplex_lp, 1, &col, &lower_or_upper,
&bnd);
ABORT_IF(rval, "CPXchgbds failed\n");
CLEANUP:
return rval;
}
int lp_optimize(struct LP *lp, int *infeasible)
{
int rval = 0, solstat;
*infeasible = 0;
rval = CPXdualopt(lp->cplex_env, lp->cplex_lp);
ABORT_IF(rval, "CPXdualopt failed\n");
solstat = CPXgetstat(lp->cplex_env, lp->cplex_lp);
if (solstat == CPX_STAT_INFEASIBLE)
{
if (infeasible)
*infeasible = 1;
}
else
{
ABORT_IF(solstat != CPX_STAT_OPTIMAL
&& solstat != CPX_STAT_OPTIMAL_INFEAS,
"Invalid solution status");
}
CLEANUP:
return rval;
}
int lp_get_obj_val(struct LP *lp, double *obj)
{
int rval = 0;
rval = CPXgetobjval(lp->cplex_env, lp->cplex_lp, obj);
ABORT_IF(rval, "CPXgetobjval failed\n");
CLEANUP:
return rval;
}
int lp_get_x(struct LP *lp, double *x)
{
int rval = 0;
int ncols = CPXgetnumcols(lp->cplex_env, lp->cplex_lp);
ABORT_IF(!ncols, "No columns in LP\n");
rval = CPXgetx(lp->cplex_env, lp->cplex_lp, x, 0, ncols - 1);
ABORT_IF(rval, "CPXgetx failed\n");
CLEANUP:
return rval;
}
int lp_write(struct LP *lp, const char *fname)
{
int rval = 0;
char nambuf[MAX_NAME_LENGTH];
strncpy(nambuf, fname, MAX_NAME_LENGTH);
nambuf[MAX_NAME_LENGTH - 1] = '\0';
rval = CPXwriteprob(lp->cplex_env, lp->cplex_lp, nambuf, "RLP");
ABORT_IF(rval, "CPXwriteprob failed\n");
CLEANUP:
return rval;
}

@ -0,0 +1,40 @@
#ifndef __MAIN_
#define __MAIN_
#include <cplex.h>
#define LP_EPSILON 0.000001
struct LP
{
CPXENVptr cplex_env;
CPXLPptr cplex_lp;
};
static const int MAX_NAME_LENGTH = 100;
int lp_open(struct LP *lp);
int lp_create(struct LP *lp, const char *name);
int lp_write(struct LP *lp, const char *fname);
void lp_free(struct LP *lp);
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_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_optimize(struct LP *lp, int *infeasible);
int lp_get_obj_val(struct LP *lp, double *obj);
int lp_get_x(struct LP *lp, double *x);
#endif

@ -0,0 +1,135 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include "lp.h"
#include "util.h"
#include "main.h"
#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;
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();
rval = parseargs(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");
tlist = (int *) malloc((node_count) * sizeof(int));
ABORT_IF(!tlist, "out of memory for tlist\n");
double best_val = TSP_find_initial_solution(edge_weights, edge_list,
node_count, edge_count);
initial_time = util_get_current_time();
struct LP *lp;
lp = (struct LP *) malloc(sizeof(struct LP *));
rval = bnc_init_lp(lp, node_count, edge_count, edge_list, edge_weights);
ABORT_IF(rval, "bnc_init_lp failed\n");
rval = bnc_solve_node(lp, &best_val, node_count, edge_count, edge_list, 1);
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);
CLEANUP:
if (tlist) free(tlist);
if (edge_list) free(edge_list);
if (edge_weights) free(edge_weights);
return rval;
}
int parseargs(int ac, char **av)
{
int c;
if (ac == 1)
{
usage(av[0]);
return 1;
}
while ((c = getopt(ac, av, "ab:gk:s:")) != EOF)
{
switch (c)
{
case 'a':
use_all_subtours = 1;
break;
case 'b':
gridsize_rand = atoi(optarg);
break;
case 'g':
geometric_data = 1;
break;
case 'k':
ncount_rand = atoi(optarg);
break;
case 's':
seed = atoi(optarg);
break;
case '?':
default:
usage(av[0]);
return 1;
}
}
if (optind < ac) fname = av[optind++];
if (optind != ac)
{
usage(av[0]);
return 1;
}
return 0;
}
void 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);
}

@ -0,0 +1,39 @@
#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;
#endif

@ -0,0 +1,418 @@
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
#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 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");
}
/* Build a column for each edge of the graph */
double lb = 0.0;
double ub = 1.0;
int cmatbeg = 0;
double cmatval[] = {1.0, 1.0};
for (int j = 0; j < edge_count; j++)
{
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,
&ub);
ABORT_IF(rval, "lp_add_cols failed\n");
}
CLEANUP:
return rval;
}
int TSP_find_violated_subtour_elimination_cut(
int ncount, int edge_count, int *edges, struct LP *lp)
{
int rval = 0;
int is_infeasible = 0;
double *x = 0;
int *delta = 0;
int *marks = 0;
int *island_nodes = 0;
int *island_start = 0;
int *island_sizes = 0;
struct Graph G;
graph_init(&G);
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);
ABORT_IF(rval, "graph_build failed\n");
x = (double *) malloc(edge_count * sizeof(double));
delta = (int *) malloc(edge_count * sizeof(int));
marks = (int *) malloc(ncount * sizeof(int));
ABORT_IF(!x, "Could not allocate memory for x");
ABORT_IF(!delta, "Could not allocate memory for delta");
ABORT_IF(!marks, "Could not allocate memory for marks");
island_nodes = (int *) malloc(ncount * sizeof(int));
island_start = (int *) malloc(ncount * sizeof(int));
island_sizes = (int *) malloc(ncount * sizeof(int));
ABORT_IF(!island_nodes, "Could not allocate memory for island_nodes");
ABORT_IF(!island_start, "Could not allocate memory for island_start");
ABORT_IF(!island_sizes, "Could not allocate memory for island_sizes");
for (int i = 0; i < ncount; i++)
marks[i] = 0;
rval = lp_get_x(lp, x);
ABORT_IF(rval, "lp_get_x failed\n");
int round = 0;
int delta_count = 0;
int island_count = 0;
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);
for (int i = 0; i < island_count; i++)
{
get_delta(island_sizes[i], island_nodes + island_start[i],
edge_count, edges, &delta_count, delta, marks);
rval = TSP_add_subtour_elimination_cut(lp, delta_count, delta);
}
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");
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_x(lp, x);
ABORT_IF(rval, "lp_get_x failed\n");
}
time_printf(" graph is TSP_is_graph_connected\n");
CLEANUP:
graph_free(&G);
if (x) free(x);
if (island_nodes) free(island_nodes);
if (delta) free(delta);
if (marks) free(marks);
return rval;
}
int TSP_add_subtour_elimination_cut(struct LP *lp, int deltacount, int *delta)
{
int rval = 0;
char sense = 'G';
double rhs = 2.0;
int rmatbeg = 0;
double *rmatval;
int *rmatind = delta;
rmatval = (double *) malloc(deltacount * sizeof(double));
ABORT_IF(!rmatval, "out of memory for rmatval\n");
for (int i = 0; i < deltacount; i++)
rmatval[i] = 1.0;
rval = lp_add_rows(lp, 1, deltacount, &rhs, &sense, &rmatbeg, rmatind,
rmatval);
ABORT_IF(rval, "lp_add_rows failed");
CLEANUP:
if (rmatval) free(rmatval);
return rval;
}
int TSP_is_graph_connected(
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++)
{
G->node_list[i].mark = 0;
island_nodes[i] = -1;
}
int k = 0, current_island = 0;
for (int i = 0; i < G->node_count; i++)
{
if (G->node_list[i].mark != 0) continue;
island_sizes[current_island] = 0;
graph_dfs(i, G, x, island_sizes + current_island, island_nodes + k);
island_start[current_island] = k;
k += island_sizes[current_island];
current_island++;
}
(*island_count) = current_island;
return (*island_count == 1);
}
int TSP_find_closest_neighbor_tour(
int start, int node_count, int edge_count, int *edges, int *elen,
int *path_length)
{
int rval;
int current_node = start;
struct Graph G;
graph_init(&G);
rval = graph_build(node_count, edge_count, edges, &G);
ABORT_IF(rval, "graph_build failed\n");
for (int j = 0; j < node_count; j++)
G.node_list[j].mark = 0;
for (int j = 0; j < node_count; j++)
{
if (j == node_count - 1)
G.node_list[start].mark = 0;
struct Node *pn = &G.node_list[current_node];
pn->mark = 1;
int closest_neighbor = -1;
int closest_edge_length = 10000000;
for (int i = 0; i < pn->deg; i++)
{
int edge = pn->adj[i].e;
int neighbor = pn->adj[i].n;
if (G.node_list[neighbor].mark == 1) continue;
if (elen[edge] > closest_edge_length) continue;
closest_neighbor = neighbor;
closest_edge_length = elen[edge];
}
*path_length += closest_edge_length;
current_node = closest_neighbor;
}
CLEANUP:
graph_free(&G);
return rval;
}
int TSP_read_problem(
char *filename, int *p_ncount, int *p_ecount, int **p_elist,
int **p_elen)
{
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;
double *x = (double *) NULL, *y = (double *) NULL;
if (filename)
{
if ((f = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Unable to open %s for input\n", filename);
rval = 1;
goto CLEANUP;
}
}
if (filename && geometric_data == 0)
{
if (fscanf(f, "%d %d", &ncount, &ecount) != 2)
{
fprintf(stderr, "Input file %s has invalid format\n", filename);
rval = 1;
goto CLEANUP;
}
printf("Nodes: %d Edges: %d\n", ncount, ecount);
fflush(stdout);
elist = (int *) malloc(2 * ecount * sizeof(int));
if (!elist)
{
fprintf(stderr, "out of memory for elist\n");
rval = 1;
goto CLEANUP;
}
elen = (int *) malloc(ecount * sizeof(int));
if (!elen)
{
fprintf(stderr, "out of memory for elen\n");
rval = 1;
goto CLEANUP;
}
for (i = 0; i < ecount; i++)
{
if (fscanf(f, "%d %d %d", &end1, &end2, &w) != 3)
{
fprintf(stderr, "%s has invalid input format\n", filename);
rval = 1;
goto CLEANUP;
}
elist[2 * i] = end1;
elist[2 * i + 1] = end2;
elen[i] = w;
}
}
else
{
if (filename)
{
if (fscanf(f, "%d", &ncount) != 1)
{
fprintf(stderr, "Input file %s has invalid format\n", filename);
rval = 1;
goto CLEANUP;
}
}
else
{
ncount = ncount_rand;
}
x = (double *) malloc(ncount * sizeof(double));
y = (double *) malloc(ncount * sizeof(double));
if (!x || !y)
{
fprintf(stdout, "out of memory for x or y\n");
rval = 1;
goto CLEANUP;
}
if (filename)
{
for (i = 0; i < ncount; i++)
{
if (fscanf(f, "%lf %lf", &x[i], &y[i]) != 2)
{
fprintf(stderr, "%s has invalid input format\n", filename);
rval = 1;
goto CLEANUP;
}
}
}
else
{
rval = CO759_build_xy(ncount, x, y, gridsize_rand);
if (rval)
{
fprintf(stderr, "CO759_build_xy failed\n");
goto CLEANUP;
}
printf("%d\n", ncount);
for (i = 0; i < ncount; i++)
{
printf("%.0f %.0f\n", x[i], y[i]);
}
printf("\n");
}
ecount = (ncount * (ncount - 1)) / 2;
time_printf("Complete graph: %d nodes, %d edges\n", ncount, ecount);
elist = (int *) malloc(2 * ecount * sizeof(int));
if (!elist)
{
fprintf(stderr, "out of memory for elist\n");
rval = 1;
goto CLEANUP;
}
elen = (int *) malloc(ecount * sizeof(int));
if (!elen)
{
fprintf(stderr, "out of memory for elen\n");
rval = 1;
goto CLEANUP;
}
ecount = 0;
for (i = 0; i < ncount; i++)
{
for (j = i + 1; j < ncount; j++)
{
elist[2 * ecount] = i;
elist[2 * ecount + 1] = j;
elen[ecount] = euclid_edgelen(i, j, x, y);
ecount++;
}
}
}
*p_ncount = ncount;
*p_ecount = ecount;
*p_elist = elist;
*p_elen = elen;
CLEANUP:
if (f) fclose(f);
if (x) free(x);
if (y) free(y);
return rval;
}
int TSP_add_cutting_planes(int ncount, int ecount, int *elist, struct LP *lp)
{
int rval = 0;
rval = TSP_find_violated_subtour_elimination_cut(ncount, ecount, elist, lp);
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 best_val = 1e99;
time_printf("Finding closest neighbor tour\n");
for (int i = 0; i < node_count; i++)
{
int path_length = 0;
TSP_find_closest_neighbor_tour(i, node_count, edge_count, edge_list,
edge_weights, &path_length);
if (best_val > path_length) best_val = path_length;
}
time_printf(" length = %lf\n", best_val);
return best_val;
}

@ -0,0 +1,39 @@
//
// Created by isoron on 3/17/15.
//
#ifndef ___TSP_H_
#define ___TSP_H_
#include "lp.h"
#include "graph.h"
int add_all_subtours(int ncount, int ecount, int *elist, struct LP *lp);
int TSP_find_violated_subtour_elimination_cut
(int ncount, int ecount, int *elist, struct LP *lp);
int TSP_is_graph_connected(
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 *path_length);
int TSP_add_subtour_elimination_cut(struct LP *lp, int deltacount, int *delta);
int TSP_read_problem(
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_init_lp(
int node_count, struct LP *lp, int edge_count, int *edge_weights,
int *edge_list);
double TSP_find_initial_solution
(int *edge_weights, int *edge_list, int node_count, int edge_count);
#endif //_PROJECT_TSP_H_

@ -0,0 +1,115 @@
/****************************************************************************/
/* */
/* Utility Functions for CO759 */
/* */
/****************************************************************************/
#include "main.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <stdarg.h>
#include "util.h"
double util_get_current_time(void)
{
struct rusage ru;
getrusage (RUSAGE_SELF, &ru);
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 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);
hit = (int **) malloc (gridsize * 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 < gridsize; i++) hitcount[i] = 0;
for (i = 0; i < ncount; i++) {
winner = 0;
do {
x = (int) (rand () % gridsize);
y = (int) (rand () % gridsize);
/* check to see if (x,y) is a duplicate point */
for (j = 0; j < hitcount[x]; j++) {
if (hit[x][j] == y) break;
}
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;
}
hit[x] = (int *) tmp_ptr;
hit[x][hitcount[x]] = y;
hitcount[x]++;
winner = 1;
}
if (!winner) {
printf ("X"); fflush (stdout);
}
} while (!winner);
xlist[i] = (double) x;
ylist[i] = (double) y;
}
CLEANUP:
printf ("\n");
if (hit) {
for (i = 0; i < gridsize; i++) {
if (hit[i]) free (hit[i]);
}
free (hit);
}
if (hitcount) free (hitcount);
return rval;
}
double initial_time = 0;
void time_printf(const char *fmt, ...)
{
if(initial_time == 0)
initial_time = util_get_current_time();
printf("[%10.2lf] ", util_get_current_time() - initial_time);
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
fflush(stdout);
}
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;
}

@ -0,0 +1,17 @@
#ifndef __CO759_UTIL_H
#define __CO759_UTIL_H
#define ABORT_IF(cond, msg) if(cond) { \
fprintf(stderr, msg); rval = 1; goto CLEANUP; }
double util_get_current_time(void);
int CO759_build_xy(int ncount, double *xlist, double *ylist, int gridsize);
double util_get_current_time(void);
void time_printf(const char *fmt, ...);
void next_set(int sz, int *Set);
#endif /* __CO759_UTIL_H */