|
|
@ -178,60 +178,6 @@ int GTSP_init_lp(struct LP *lp, struct GTSP *data)
|
|
|
|
return rval;
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int add_subcluster_cut(
|
|
|
|
|
|
|
|
struct LP *lp,
|
|
|
|
|
|
|
|
struct Graph *graph,
|
|
|
|
|
|
|
|
struct Edge *e,
|
|
|
|
|
|
|
|
struct Edge **cut_edges,
|
|
|
|
|
|
|
|
int cut_edges_count)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int rval = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char sense = 'G';
|
|
|
|
|
|
|
|
double rhs = 0.0;
|
|
|
|
|
|
|
|
int newnz = cut_edges_count + 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int rmatbeg = 0;
|
|
|
|
|
|
|
|
int *rmatind = 0;
|
|
|
|
|
|
|
|
double *rmatval = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rmatind = (int *) malloc(newnz * sizeof(int));
|
|
|
|
|
|
|
|
abort_if(!rmatind, "could not allocate rmatind");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rmatval = (double *) malloc(newnz * sizeof(double));
|
|
|
|
|
|
|
|
abort_if(!rmatval, "could not allocate rmatval");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < cut_edges_count; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
rmatind[i] = cut_edges[i]->index + graph->node_count;
|
|
|
|
|
|
|
|
rmatval[i] = 1.0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rmatind[cut_edges_count] = graph->node_count + e->index;
|
|
|
|
|
|
|
|
rmatval[cut_edges_count] = -1.0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log_debug("Generated cut:\n");
|
|
|
|
|
|
|
|
for (int i = 0; i < newnz; i++)
|
|
|
|
|
|
|
|
log_debug("%8.2f x%d\n", rmatval[i], rmatind[i]);
|
|
|
|
|
|
|
|
log_debug(" %c %.2lf\n", sense, rhs);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (OPTIMAL_X)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
double sum = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < newnz; i++)
|
|
|
|
|
|
|
|
sum += rmatval[i] * OPTIMAL_X[rmatind[i]];
|
|
|
|
|
|
|
|
abort_if(sum <= rhs - LP_EPSILON, "cannot add invalid cut");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rval = LP_add_rows(lp, 1, newnz, &rhs, &sense, &rmatbeg, rmatind, rmatval);
|
|
|
|
|
|
|
|
abort_if(rval, "LP_add_rows failed");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CLEANUP:
|
|
|
|
|
|
|
|
if (rmatval) free(rmatval);
|
|
|
|
|
|
|
|
if (rmatind) free(rmatind);
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int add_subtour_cut(
|
|
|
|
static int add_subtour_cut(
|
|
|
|
struct LP *lp,
|
|
|
|
struct LP *lp,
|
|
|
|
struct Graph *graph,
|
|
|
|
struct Graph *graph,
|
|
|
@ -366,7 +312,7 @@ static int build_flow_digraph(
|
|
|
|
capacities[kc++] = 0;
|
|
|
|
capacities[kc++] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create an extra node and connect it to each cluster node through
|
|
|
|
// Create an extra root node and connect it to each cluster node through
|
|
|
|
// some edge with zero capacity
|
|
|
|
// some edge with zero capacity
|
|
|
|
for (int i = 0; i < data->cluster_count; i++)
|
|
|
|
for (int i = 0; i < data->cluster_count; i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -400,7 +346,6 @@ static int build_flow_digraph(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int map_cut_edges_from_digraph_to_graph(
|
|
|
|
static int map_cut_edges_from_digraph_to_graph(
|
|
|
|
struct Graph *graph,
|
|
|
|
|
|
|
|
struct Edge **edge_map,
|
|
|
|
struct Edge **edge_map,
|
|
|
|
int *cut_edges_count,
|
|
|
|
int *cut_edges_count,
|
|
|
|
struct Edge **cut_edges)
|
|
|
|
struct Edge **cut_edges)
|
|
|
@ -495,13 +440,11 @@ int find_exact_subtour_cuts_cluster_to_cluster(
|
|
|
|
|
|
|
|
|
|
|
|
if (flow_value >= 2 - LP_EPSILON) continue;
|
|
|
|
if (flow_value >= 2 - LP_EPSILON) continue;
|
|
|
|
|
|
|
|
|
|
|
|
// log_debug("Flow from cluster %d to %d is insufficient\n", i, j);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rval = get_cut_edges_from_marks(digraph, &cut_edges_count,
|
|
|
|
rval = get_cut_edges_from_marks(digraph, &cut_edges_count,
|
|
|
|
cut_edges);
|
|
|
|
cut_edges);
|
|
|
|
abort_if(rval, "get_cut_edges_from_marks failed");
|
|
|
|
abort_if(rval, "get_cut_edges_from_marks failed");
|
|
|
|
|
|
|
|
|
|
|
|
rval = map_cut_edges_from_digraph_to_graph(graph, edge_map,
|
|
|
|
rval = map_cut_edges_from_digraph_to_graph(edge_map,
|
|
|
|
&cut_edges_count, cut_edges);
|
|
|
|
&cut_edges_count, cut_edges);
|
|
|
|
abort_if(rval, "map_cut_edges_from_digraph_to_graph failed");
|
|
|
|
abort_if(rval, "map_cut_edges_from_digraph_to_graph failed");
|
|
|
|
|
|
|
|
|
|
|
@ -576,7 +519,7 @@ int find_exact_subtour_cuts_node_to_cluster(
|
|
|
|
cut_edges);
|
|
|
|
cut_edges);
|
|
|
|
abort_if(rval, "get_cut_edges_from_marks failed");
|
|
|
|
abort_if(rval, "get_cut_edges_from_marks failed");
|
|
|
|
|
|
|
|
|
|
|
|
rval = map_cut_edges_from_digraph_to_graph(graph, edge_map,
|
|
|
|
rval = map_cut_edges_from_digraph_to_graph(edge_map,
|
|
|
|
&cut_edges_count, cut_edges);
|
|
|
|
&cut_edges_count, cut_edges);
|
|
|
|
abort_if(rval, "map_cut_edges_from_digraph_to_graph failed");
|
|
|
|
abort_if(rval, "map_cut_edges_from_digraph_to_graph failed");
|
|
|
|
|
|
|
|
|
|
|
@ -656,8 +599,8 @@ int find_exact_subtour_cuts_node_to_node(
|
|
|
|
rval = get_cut_edges_from_marks(digraph, &cut_edges_count, cut_edges);
|
|
|
|
rval = get_cut_edges_from_marks(digraph, &cut_edges_count, cut_edges);
|
|
|
|
abort_if(rval, "get_cut_edges_from_marks failed");
|
|
|
|
abort_if(rval, "get_cut_edges_from_marks failed");
|
|
|
|
|
|
|
|
|
|
|
|
rval = map_cut_edges_from_digraph_to_graph(graph, edge_map,
|
|
|
|
rval = map_cut_edges_from_digraph_to_graph(edge_map, &cut_edges_count,
|
|
|
|
&cut_edges_count, cut_edges);
|
|
|
|
cut_edges);
|
|
|
|
abort_if(rval, "map_cut_edges_from_digraph_to_graph failed");
|
|
|
|
abort_if(rval, "map_cut_edges_from_digraph_to_graph failed");
|
|
|
|
|
|
|
|
|
|
|
|
rval = add_subtour_cut(lp, graph, from, to, cut_edges, cut_edges_count,
|
|
|
|
rval = add_subtour_cut(lp, graph, from, to, cut_edges, cut_edges_count,
|
|
|
@ -738,145 +681,6 @@ int find_exact_subtour_cuts(
|
|
|
|
log_debug("Added %d node-to-node subtour cuts\n", added_cuts_count);
|
|
|
|
log_debug("Added %d node-to-node subtour cuts\n", added_cuts_count);
|
|
|
|
(*total_added_cuts) += added_cuts_count;
|
|
|
|
(*total_added_cuts) += added_cuts_count;
|
|
|
|
|
|
|
|
|
|
|
|
// // subcluster
|
|
|
|
|
|
|
|
// struct Node *root = &digraph.nodes[digraph.node_count - 1];
|
|
|
|
|
|
|
|
// for (int e_index = 0; e_index < graph->edge_count; e_index++)
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// struct Edge *e = &graph->edges[e_index];
|
|
|
|
|
|
|
|
// double x_e = x[node_count + e_index];
|
|
|
|
|
|
|
|
// if (x_e < LP_EPSILON) continue;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// struct Node *from = &digraph.nodes[e->from->index];
|
|
|
|
|
|
|
|
// struct Node *to = &digraph.nodes[e->to->index];
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// if (x[from->index] > 1 - LP_EPSILON && x[to->index] > 1 - LP_EPSILON)
|
|
|
|
|
|
|
|
// continue;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// capacities[4 * e_index] = capacities[4 * e_index + 2] = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// int cluster_from_index = data->clusters[from->index];
|
|
|
|
|
|
|
|
// int cluster_to_index = data->clusters[to->index];
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// for (int k = 0; k < data->cluster_count; k++)
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// if (cluster_from_index == k) continue;
|
|
|
|
|
|
|
|
// if (cluster_to_index == k) continue;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// int offset = 4 * graph->edge_count + 2 * node_count + 2 * k;
|
|
|
|
|
|
|
|
// capacities[offset] = 1e10;
|
|
|
|
|
|
|
|
// capacities[offset + 1] = 1e10;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// for (int k = 0; k < graph->node_count; k++)
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// struct Node *n = &graph->nodes[k];
|
|
|
|
|
|
|
|
// if (clusters[n->index] != cluster_from_index &&
|
|
|
|
|
|
|
|
// clusters[n->index] != cluster_to_index)
|
|
|
|
|
|
|
|
// continue;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// int offset = 4 * graph->edge_count + 2 * k;
|
|
|
|
|
|
|
|
// capacities[offset] = 0;
|
|
|
|
|
|
|
|
// capacities[offset + 1] = 0;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// // First direction
|
|
|
|
|
|
|
|
// log_debug("Calculating max flow from (%d,%d) to root\n", from->index,
|
|
|
|
|
|
|
|
// to->index);
|
|
|
|
|
|
|
|
// double flow_value;
|
|
|
|
|
|
|
|
// rval = flow_find_max_flow(&digraph, capacities, from, root, flow,
|
|
|
|
|
|
|
|
// &flow_value);
|
|
|
|
|
|
|
|
// abort_if(rval, "flow_find_max_flow failed");
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// log_debug(" %.2lf\n", flow_value);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// if (flow_value + LP_EPSILON < x_e)
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// log_debug("violation: %.2lf > %.2lf\n", flow_value, x_e);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// int cut_edges_count;
|
|
|
|
|
|
|
|
// rval = get_cut_edges_from_marks(&digraph, &cut_edges_count,
|
|
|
|
|
|
|
|
// cut_edges);
|
|
|
|
|
|
|
|
// abort_if(rval, "get_cut_edges_from_marks failed");
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// log_debug("Adding cut for i=%d j=root, cut edges:\n", from->index);
|
|
|
|
|
|
|
|
// int c = 0;
|
|
|
|
|
|
|
|
// for (int k = 0; k < cut_edges_count / 2; k++)
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// int idx = cut_edges[k * 2]->index / 4;
|
|
|
|
|
|
|
|
// if (idx == e_index) continue;
|
|
|
|
|
|
|
|
// if (idx >= graph->edge_count) continue;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// cut_edges[c++] = &graph->edges[idx];
|
|
|
|
|
|
|
|
// log_debug(" %d %d\n", cut_edges[c - 1]->from->index,
|
|
|
|
|
|
|
|
// cut_edges[c - 1]->to->index);
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// rval = add_subcluster_cut(lp, graph, e, cut_edges, c);
|
|
|
|
|
|
|
|
// abort_if(rval, "add_subcluster_cut failed");
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// (*total_added_cuts)++;
|
|
|
|
|
|
|
|
// if (*total_added_cuts > 10) goto CLEANUP;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// } else
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// // Reverse direction
|
|
|
|
|
|
|
|
// log_debug("Trying reverse edge:\n", to->index, from->index);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// rval = flow_find_max_flow(&digraph, capacities, to, root, flow,
|
|
|
|
|
|
|
|
// &flow_value);
|
|
|
|
|
|
|
|
// abort_if(rval, "flow_find_max_flow failed");
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// log_debug(" %.2lf\n", flow_value);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// if (flow_value + LP_EPSILON < x_e)
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// log_debug("violation: %.2lf > %.2lf\n", flow_value, x_e);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// int cut_edges_count;
|
|
|
|
|
|
|
|
// rval = get_cut_edges_from_marks(&digraph, &cut_edges_count,
|
|
|
|
|
|
|
|
// cut_edges);
|
|
|
|
|
|
|
|
// abort_if(rval, "get_cut_edges_from_marks failed");
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// log_debug("Adding cut for i=%d j=root, cut edges:\n",
|
|
|
|
|
|
|
|
// from->index);
|
|
|
|
|
|
|
|
// int c = 0;
|
|
|
|
|
|
|
|
// for (int k = 0; k < cut_edges_count / 2; k++)
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// int idx = cut_edges[k * 2]->index / 4;
|
|
|
|
|
|
|
|
// if (idx == e_index) continue;
|
|
|
|
|
|
|
|
// if (idx >= graph->edge_count) continue;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// cut_edges[c++] = &graph->edges[idx];
|
|
|
|
|
|
|
|
// log_debug(" %d %d\n", cut_edges[c - 1]->from->index,
|
|
|
|
|
|
|
|
// cut_edges[c - 1]->to->index);
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// rval = add_subcluster_cut(lp, graph, e, cut_edges, c);
|
|
|
|
|
|
|
|
// abort_if(rval, "add_subcluster_cut failed");
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// (*total_added_cuts)++;
|
|
|
|
|
|
|
|
// if (*total_added_cuts > 10) goto CLEANUP;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// capacities[4 * e_index] = x_e;
|
|
|
|
|
|
|
|
// capacities[4 * e_index + 2] = x_e;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// for (int k = 0; k < graph->node_count; k++)
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// int offset = 4 * graph->edge_count + 2 * k;
|
|
|
|
|
|
|
|
// capacities[offset] = 1e10;
|
|
|
|
|
|
|
|
// capacities[offset + 1] = 1e10;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// for (int k = 0; k < data->cluster_count; k++)
|
|
|
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
// int offset = 4 * graph->edge_count + 2 * graph->node_count;
|
|
|
|
|
|
|
|
// capacities[offset + 2 * k] = 0;
|
|
|
|
|
|
|
|
// capacities[offset + 2 * k + 1] = 0;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CLEANUP:
|
|
|
|
CLEANUP:
|
|
|
|
graph_free(&digraph);
|
|
|
|
graph_free(&digraph);
|
|
|
|
if (edge_map) free(edge_map);
|
|
|
|
if (edge_map) free(edge_map);
|
|
|
@ -1108,7 +912,7 @@ int GTSP_solution_found(struct GTSP *data, double *x)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int rval = 0;
|
|
|
|
int rval = 0;
|
|
|
|
|
|
|
|
|
|
|
|
log_info("Writting solution to file gtsp.out\n");
|
|
|
|
log_info("Writting integral solution to file gtsp.out\n");
|
|
|
|
rval = GTSP_write_solution(data, "gtsp.out", x);
|
|
|
|
rval = GTSP_write_solution(data, "gtsp.out", x);
|
|
|
|
abort_if(rval, "GTSP_write_solution failed");
|
|
|
|
abort_if(rval, "GTSP_write_solution failed");
|
|
|
|
|
|
|
|
|
|
|
|