You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

491 lines
13 KiB

#include "gtsp.h"
#include "util.h"
#include <assert.h>
int add_comb_cut(
struct LP *lp,
struct Graph *graph,
int current_component,
int *clusters,
int *components,
int *component_sizes,
int *teeth,
int tooth_count,
double *x)
{
int rval = 0;
char sense = 'G';
const int node_count = graph->node_count;
const int edge_count = graph->edge_count;
struct Row *cut = 0;
int *rmatind = 0;
double *rmatval = 0;
rmatind = (int *) malloc((node_count + edge_count) * sizeof(int));
rmatval = (double *) malloc((node_count + edge_count) * sizeof(double));
abort_if(!rmatind, "could not allocate rmatind");
abort_if(!rmatval, "could not allocate rmatval");
double rhs = -component_sizes[current_component] - tooth_count +
(tooth_count + 1) / 2;
int nz = 0;
// Edges inside handle
for (int i = 0; i < edge_count; i++)
{
struct Edge *e = &graph->edges[i];
if (components[clusters[e->from->index]] != current_component) continue;
if (components[clusters[e->to->index]] != current_component) continue;
rmatind[nz] = node_count + e->index;
rmatval[nz] = -1.0;
nz++;
log_debug(" handle (%d %d)\n", e->from->index, e->to->index);
}
// Edges inside each tooth
for (int i = 0; i < edge_count; i++)
{
struct Edge *e = &graph->edges[i];
struct Node *from = e->from;
struct Node *to = e->to;
if (teeth[clusters[from->index]] < 0) continue;
if (teeth[clusters[to->index]] < 0) continue;
if (teeth[clusters[from->index]] != teeth[clusters[to->index]])
continue;
log_debug(" tooth (%d %d)\n", e->from->index, e->to->index);
rmatind[nz] = node_count + e->index;
rmatval[nz] = -1.0;
nz++;
}
// // Lifting of the nodes
// for (int i = 0; i < node_count; i++)
// {
// double val;
// struct Node *n = &graph->nodes[i];
// int c = clusters[n->index];
//
// if (components[c] == current_component)
// val = (teeth[c] < 0 ? 1.0 : 0.0);
// else
// val = (teeth[c] < 0 ? 0.0 : 0.0);
//
// if (val == 0.0) continue;
//
// rmatind[nz] = n->index;
// rmatval[nz] = val;
// nz++;
//
// rhs = val;
// }
#if LOG_LEVEL >= LOG_LEVEL_DEBUG
log_debug("Generated cut:\n");
for (int i = 0; i < nz; i++)
{
if (OPTIMAL_X[rmatind[i]] < LP_EPSILON) continue;
if (rmatind[i] >= node_count)
{
struct Edge *e = &graph->edges[rmatind[i] - node_count];
log_debug(" %.2lf x%d (%d %d %.4lf)\n", rmatval[i], rmatind[i],
e->from->index, e->to->index, OPTIMAL_X[rmatind[i]]);
}
else
{
log_debug(" %.2lf x%d (%.4lf)\n", rmatval[i], rmatind[i],
OPTIMAL_X[rmatind[i]]);
}
}
log_debug(" %c %.2lf\n", sense, rhs);
#endif
if (OPTIMAL_X)
{
double sum = 0;
for (int i = 0; i < nz; i++)
sum += rmatval[i] * OPTIMAL_X[rmatind[i]];
log_debug("%.2lf >= %.2lf\n", sum, rhs);
abort_if(sum <= rhs - LP_EPSILON, "cannot add invalid cut");
}
double lhs = 0.0;
for (int i = 0; i < nz; i++)
lhs += rmatval[i] * x[rmatind[i]];
log_debug("Violation: %.4lf >= %.4lf\n", lhs, rhs);
if (lhs + LP_EPSILON > rhs) goto CLEANUP;
cut = (struct Row *) malloc(sizeof(struct Row));
abort_if(!cut, "could not allocate cut");
cut->nz = nz;
cut->sense = sense;
cut->rhs = rhs;
cut->rmatval = rmatval;
cut->rmatind = rmatind;
rval = LP_add_cut(lp, cut);
abort_if(rval, "LP_add_cut failed");
CLEANUP:
if (rmatind) free(rmatind);
if (rmatval) free(rmatval);
return rval;
}
int find_components(
struct Graph *graph, double *x, int *components, int *component_sizes)
{
int rval = 0;
struct Node **stack = 0;
const int node_count = graph->node_count;
for (int i = 0; i < node_count; i++)
{
components[i] = -1;
graph->nodes[i].mark = 0;
}
int stack_top = 0;
stack = (struct Node **) malloc(node_count * sizeof(struct Node *));
abort_if(!stack, "could not allocate stack");
for (int i = 0; i < node_count; i++)
{
struct Node *root = &graph->nodes[i];
if (root->mark) continue;
stack[stack_top++] = root;
while (stack_top > 0)
{
struct Node *n = stack[--stack_top];
components[n->index] = i;
for (int j = 0; j < n->degree; j++)
{
struct Adjacency *adj = &n->adj[j];
struct Node *neighbor = adj->neighbor;
if (neighbor->mark) continue;
double x_e = x[adj->edge->index];
if (x_e < LP_EPSILON) continue;
if (x_e > 1 - LP_EPSILON) continue;
stack[stack_top++] = neighbor;
neighbor->mark = 1;
}
}
}
for (int i = 0; i < node_count; i++)
component_sizes[i] = 0;
for (int i = 0; i < node_count; i++)
component_sizes[components[i]]++;
log_debug("Components:\n");
for (int i = 0; i < graph->node_count; i++)
log_debug(" %d %d\n", i, components[i]);
log_debug("Component sizes:\n");
for (int i = 0; i < graph->node_count; i++)
log_debug(" %d %d\n", i, component_sizes[i]);
CLEANUP:
if (stack) free(stack);
return rval;
}
int find_teeth(
struct Graph *graph,
double *x,
int current_component,
int *components,
int *teeth,
int *tooth_count)
{
const int node_count = graph->node_count;
const int edge_count = graph->edge_count;
for (int i = 0; i < node_count; i++)
{
graph->nodes[i].mark = 0;
teeth[i] = -1;
}
*tooth_count = 0;
for (int i = 0; i < edge_count; i++)
{
struct Edge *e = &graph->edges[i];
struct Node *from = e->from;
struct Node *to = e->to;
if (x[e->index] < 1 - LP_EPSILON) continue;
if (to->mark || from->mark) continue;
int z = 0;
if (components[from->index] == current_component) z++;
if (components[to->index] == current_component) z++;
if (z != 1) continue;
to->mark = 1;
from->mark = 1;
teeth[to->index] = *tooth_count;
teeth[from->index] = *tooth_count;
(*tooth_count)++;
}
return 0;
}
int write_shrunken_graph(
double *shrunken_x,
struct Graph *shrunken_graph,
int const cluster_count);
static int shrink_clusters(
const struct GTSP *data,
double *x,
struct Graph *shrunken_graph,
double *shrunken_x)
{
int rval = 0;
double *x_coords = 0;
double *y_coords = 0;
int *cluster_sizes = 0;
const int *clusters = data->clusters;
const int cluster_count = data->cluster_count;
const struct Graph *graph = data->graph;
int *edges = 0;
int *edge_map = 0;
int edge_count = (cluster_count * (cluster_count - 1)) / 2;
edge_map = (int *) malloc(cluster_count * cluster_count * sizeof(int));
abort_if(!edge_map, "could not allocate edge_map");
edges = (int *) malloc(2 * edge_count * sizeof(int));
abort_if(!edges, "could not allocate edges");
cluster_sizes = (int *) malloc(cluster_count * sizeof(int));
x_coords = (double *) malloc(cluster_count * sizeof(double));
y_coords = (double *) malloc(cluster_count * sizeof(double));
abort_if(!cluster_sizes, "could not allocate cluster_sizes");
abort_if(!x_coords, "could not allocate x_coords");
abort_if(!y_coords, "could not allocate y_coords");
for (int i = 0; i < cluster_count; i++)
{
x_coords[i] = 0.0;
y_coords[i] = 0.0;
cluster_sizes[i] = 0;
}
for (int i = 0; i < graph->node_count; i++)
{
struct Node *n = &graph->nodes[i];
int c = clusters[n->index];
cluster_sizes[c]++;
x_coords[c] += graph->x_coordinates[n->index];
y_coords[c] += graph->y_coordinates[n->index];
}
for (int i = 0; i < cluster_count; i++)
{
x_coords[i] = x_coords[i] / cluster_sizes[i];
y_coords[i] = y_coords[i] / cluster_sizes[i];
}
shrunken_graph->x_coordinates = x_coords;
shrunken_graph->y_coordinates = y_coords;
int curr_edge = 0;
for (int i = 0; i < cluster_count; i++)
{
for (int j = i + 1; j < cluster_count; j++)
{
edges[curr_edge * 2] = i;
edges[curr_edge * 2 + 1] = j;
edge_map[i * cluster_count + j] = curr_edge;
edge_map[j * cluster_count + i] = curr_edge;
curr_edge++;
}
}
assert(curr_edge == edge_count);
rval = graph_build(cluster_count, edge_count, edges, 0, shrunken_graph);
abort_if(rval, "graph_build failed");
for (int i = 0; i < edge_count; i++)
shrunken_x[i] = 0.0;
for (int i = 0; i < graph->edge_count; i++)
{
struct Edge *e = &graph->edges[i];
int from = clusters[e->from->index];
int to = clusters[e->to->index];
int shunk_e_index = edge_map[from * cluster_count + to];
shrunken_x[shunk_e_index] += x[graph->node_count + e->index];
}
CLEANUP:
if (edges) free(edges);
if (edge_map) free(edge_map);
if (cluster_sizes) free(cluster_sizes);
return rval;
}
int find_comb_cuts(struct LP *lp, struct GTSP *data)
{
int rval = 0;
double *x = 0;
double *shrunken_x = 0;
int *teeth = 0;
int *components = 0;
int *component_sizes = 0;
int num_cols = LP_get_num_cols(lp);
x = (double *) malloc(num_cols * sizeof(double));
abort_if(!x, "could not allocate x");
rval = LP_get_x(lp, x);
abort_if(rval, "LP_get_x failed");
struct Graph shrunken_graph;
graph_init(&shrunken_graph);
const int cluster_count = data->cluster_count;
const int shrunken_edge_count = (cluster_count * (cluster_count - 1)) / 2;
shrunken_x = (double *) malloc(shrunken_edge_count * sizeof(double));
abort_if(!shrunken_x, "could not allocate shrunken_x");
rval = shrink_clusters(data, x, &shrunken_graph, shrunken_x);
abort_if(rval, "shrink_clusters failed");
#if LOG_LEVEL >= LOG_LEVEL_DEBUG
rval = write_shrunken_graph(shrunken_x, &shrunken_graph, cluster_count);
abort_if(rval, "write_shrunken_graph failed");
#endif
teeth = (int *) malloc(cluster_count * sizeof(int));
components = (int *) malloc(cluster_count * sizeof(int));
component_sizes = (int *) malloc(cluster_count * sizeof(int));
abort_if(!teeth, "could not allocate teeth");
abort_if(!components, "could not allocate components");
abort_if(!component_sizes, "could not allocate component_sizes");
rval = find_components(&shrunken_graph, shrunken_x, components,
component_sizes);
abort_if(rval, "find_components failed");
#if LOG_LEVEL >= LOG_LEVEL_DEBUG
int original_cut_pool_size = lp->cut_pool_size;
#endif
for (int i = 0; i < cluster_count; i++)
{
if (component_sizes[i] < 3) continue;
int tooth_count;
rval = find_teeth(&shrunken_graph, shrunken_x, i, components, teeth,
&tooth_count);
abort_if(rval, "find_teeth failed");
log_debug("Component %d has %d teeth:\n", i, tooth_count);
for (int j = 0; j < cluster_count; j++)
{
if (teeth[j] < 0) continue;
log_debug(" %d %d\n", j, teeth[j]);
}
if (tooth_count % 2 == 0) continue;
rval = add_comb_cut(lp, data->graph, i, data->clusters, components,
component_sizes, teeth, tooth_count, x);
abort_if(rval, "add_comb_cut failed");
}
log_debug(" %d combs\n", lp->cut_pool_size - original_cut_pool_size);
CLEANUP:
graph_free(&shrunken_graph);
if (teeth) free(teeth);
if (components) free(components);
if (component_sizes) free(component_sizes);
if (shrunken_x) free(shrunken_x);
return rval;
}
int write_shrunken_graph(
double *shrunken_x,
struct Graph *shrunken_graph,
int const cluster_count)
{
int rval = 0;
FILE *file = 0;
file = fopen("gtsp-shrunken.in", "w");
abort_if(!file, "could not open file");
fprintf(file, "%d %d\n", (*shrunken_graph).node_count, cluster_count);
for (int i = 0; i < (*shrunken_graph).node_count; i++)
{
fprintf(file, "%.2lf %.2lf %d\n", (*shrunken_graph).x_coordinates[i],
(*shrunken_graph).y_coordinates[i], i);
}
fclose(file);
file = fopen("gtsp-shrunken.out", "w");
abort_if(!file, "could not open file");
int positive_edge_count = 0;
for (int i = 0; i < (*shrunken_graph).edge_count; i++)
if (shrunken_x[i] > LP_EPSILON)
positive_edge_count++;
fprintf(file, "%d %d\n", (*shrunken_graph).node_count,
(*shrunken_graph).edge_count);
fprintf(file, "%d\n", positive_edge_count);
for (int i = 0; i < (*shrunken_graph).edge_count; i++)
if (shrunken_x[i] > LP_EPSILON)
fprintf(file, "%d %d %.4lf\n",
(*shrunken_graph).edges[i].from->index,
(*shrunken_graph).edges[i].to->index, shrunken_x[i]);
fclose(file);
CLEANUP:
return rval;
}