Implement simple cut pool; avoid duplicate cuts

master
Alinson S. Xavier 11 years ago
parent 66b3eef3a4
commit cb580892b9

@ -114,7 +114,6 @@ int static add_subtour_cut(
double rhs = 2.0 - 2.0 * type;
int newnz = cut_edges_count + type;
int rmatbeg = 0;
int *rmatind = 0;
double *rmatval = 0;
@ -155,18 +154,27 @@ int static add_subtour_cut(
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");
struct Row *cut = 0;
cut = (struct Row *) malloc(sizeof(struct Row));
abort_if(!cut, "could not allocate cut");
cut->nz = newnz;
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 (rmatval) free(rmatval);
if (rmatind) free(rmatind);
return rval;
}
int find_exact_subtour_cuts(
struct LP *lp, struct GTSP *data, int *total_added_cuts, double min_cut_violation)
struct LP *lp,
struct GTSP *data,
double min_cut_violation)
{
int rval = 0;
@ -190,10 +198,11 @@ int find_exact_subtour_cuts(
struct Graph digraph;
graph_init(&digraph);
int digraph_edge_count = 4 * graph->edge_count + 2 * graph->node_count +
2 * data->cluster_count;
int original_cut_pool_size = lp->cut_pool_size;
capacities = (double *) malloc(digraph_edge_count * sizeof(double));
abort_if(!capacities, "could not allocate capacities");
@ -202,29 +211,31 @@ int find_exact_subtour_cuts(
// Constraints (2.1)
rval = find_exact_subtour_cuts_cluster_to_cluster(lp, data, &digraph,
capacities, &added_cuts_count, min_cut_violation);
capacities, min_cut_violation);
abort_if(rval, "find_exact_subtour_cuts_cluster_to_cluster failed");
added_cuts_count = lp->cut_pool_size - original_cut_pool_size;
log_debug("Added %d cluster-to-cluster subtour cuts\n", added_cuts_count);
(*total_added_cuts) += added_cuts_count;
if (added_cuts_count > 0) goto CLEANUP;
// Constraints (2.2)
original_cut_pool_size = lp->cut_pool_size;
rval = find_exact_subtour_cuts_node_to_cluster(lp, data, x, &digraph,
capacities, &added_cuts_count, min_cut_violation);
capacities, min_cut_violation);
abort_if(rval, "find_exact_subtour_cuts_node_to_cluster failed");
added_cuts_count = lp->cut_pool_size - original_cut_pool_size;
log_debug("Added %d node-to-cluster subtour cuts\n", added_cuts_count);
(*total_added_cuts) += added_cuts_count;
if (added_cuts_count > 0) goto CLEANUP;
// Constraints (2.3)
original_cut_pool_size = lp->cut_pool_size;
rval = find_exact_subtour_cuts_node_to_node(lp, data, x, &digraph,
capacities, &added_cuts_count, min_cut_violation);
capacities, min_cut_violation);
abort_if(rval, "find_exact_subtour_cuts_node_to_node failed");
added_cuts_count = lp->cut_pool_size - original_cut_pool_size;
log_debug("Added %d node-to-node subtour cuts\n", added_cuts_count);
(*total_added_cuts) += added_cuts_count;
CLEANUP:
graph_free(&digraph);
@ -239,7 +250,6 @@ int find_exact_subtour_cuts_node_to_node(
double *x,
struct Graph *digraph,
double *capacities,
int *added_cuts_count,
double min_cut_violation)
{
int rval = 0;
@ -309,8 +319,6 @@ int find_exact_subtour_cuts_node_to_node(
rval = add_subtour_cut(lp, graph, from, to, cut_edges, cut_edges_count,
2);
abort_if(rval, "add_subtour_cut failed");
(*added_cuts_count)++;
}
CLEANUP:
@ -325,7 +333,6 @@ int find_exact_subtour_cuts_node_to_cluster(
double *x,
struct Graph *digraph,
double *capacities,
int *added_cuts_count,
double min_cut_violation)
{
int rval = 0;
@ -396,7 +403,6 @@ int find_exact_subtour_cuts_node_to_cluster(
cut_edges_count, 1);
abort_if(rval, "add_subtour_cut failed");
(*added_cuts_count)++;
cuts_count++;
}
}
@ -412,7 +418,6 @@ int find_exact_subtour_cuts_cluster_to_cluster(
struct GTSP *data,
struct Graph *digraph,
double *capacities,
int *added_cuts_count,
double min_cut_violation)
{
int rval = 0;
@ -480,11 +485,8 @@ int find_exact_subtour_cuts_cluster_to_cluster(
0);
abort_if(rval, "add_subtour_cut failed");
(*added_cuts_count)++;
cuts_count++;
}
// if(cuts_count > 0) break;
}
CLEANUP:

@ -12,7 +12,6 @@ int find_exact_subtour_cuts_cluster_to_cluster(
struct GTSP *data,
struct Graph *digraph,
double *capacities,
int *added_cuts_count,
double min_cut_violation);
int find_exact_subtour_cuts_node_to_cluster(
@ -21,7 +20,6 @@ int find_exact_subtour_cuts_node_to_cluster(
double *x,
struct Graph *digraph,
double *capacities,
int *added_cuts_count,
double min_cut_violation);
int find_exact_subtour_cuts_node_to_node(
@ -30,13 +28,11 @@ int find_exact_subtour_cuts_node_to_node(
double *x,
struct Graph *digraph,
double *capacities,
int *added_cuts_count,
double min_cut_violation);
int find_exact_subtour_cuts(
struct LP *lp,
struct GTSP *data,
int *total_added_cuts,
double min_cut_violation);
#endif //_PROJECT_GTSP_SUBTOUR_H_

@ -188,7 +188,6 @@ int GTSP_add_cutting_planes(struct LP *lp, struct GTSP *data)
int rval = 0;
int round = 0;
int added_cuts_count = 0;
int violation_total = 3;
int violation_current = 0;
@ -197,19 +196,17 @@ int GTSP_add_cutting_planes(struct LP *lp, struct GTSP *data)
while (1)
{
round++;
int added_cuts_this_round = 0;
log_debug("Finding subtour cuts, round %d, violation %.4lf...\n", round,
violations[violation_current]);
rval = find_exact_subtour_cuts(lp, data, &added_cuts_this_round,
violations[violation_current]);
int original_cut_pool_size = lp->cut_pool_size;
rval = find_exact_subtour_cuts(lp, data, violations[violation_current]);
abort_if(rval, "find_exact_subtour_cuts failed");
if (added_cuts_this_round == 0)
if (lp->cut_pool_size - original_cut_pool_size == 0)
{
++violation_current;
if (violation_current < violation_total)
if (++violation_current < violation_total)
{
log_debug("No cuts found. Decreasing minimum cut violation.\n");
continue;
@ -234,7 +231,7 @@ int GTSP_add_cutting_planes(struct LP *lp, struct GTSP *data)
abort_if(rval, "LP_get_obj_val failed");
log_debug(" obj val = %.4lf\n", obj_val);
log_debug(" time = %.2lf\n", time_after_lp-time_before_lp);
log_debug(" time = %.2lf\n", time_after_lp - time_before_lp);
if (time_after_lp - time_before_lp > 10.0)
{
@ -248,8 +245,6 @@ int GTSP_add_cutting_planes(struct LP *lp, struct GTSP *data)
abort_if(rval, "LP_optimize failed");
if (is_infeasible) break;
added_cuts_count += added_cuts_this_round;
}
CLEANUP:

@ -6,6 +6,7 @@
#include "util.h"
#define LP_EPSILON 0.000001
#define MAX_CUT_POOL_SIZE 100000
int LP_open(struct LP *lp)
{
@ -13,11 +14,11 @@ int LP_open(struct LP *lp)
lp->cplex_lp = (CPXLPptr) NULL;
lp->cplex_env = CPXopenCPLEX(&rval);
if (rval)
{
fprintf(stderr, "CPXopenCPLEX failed, return code %d\n", rval);
goto CLEANUP;
}
abort_if(rval, "CPXopenCPLEX failed");
lp->cut_pool = (struct Row **) malloc(
MAX_CUT_POOL_SIZE * sizeof(struct Row *));
abort_if(!lp->cut_pool, "could not allocate cut_pool");
CLEANUP:
return rval;
@ -33,6 +34,7 @@ void LP_free(struct LP *lp)
CPXcloseCPLEX(&lp->cplex_env);
lp->cplex_env = 0;
if (lp->cut_pool) free(lp->cut_pool);
}
int LP_create(struct LP *lp, const char *name)
@ -158,9 +160,9 @@ int LP_remove_slacks(struct LP *lp, int first_row, double max_slack)
int *should_remove = 0;
int numrows = CPXgetnumrows(lp->cplex_env, lp->cplex_lp);
if(numrows < 5000) return 0;
if (numrows < 5000) return 0;
should_remove = (int *) malloc((numrows+1) * sizeof(int));
should_remove = (int *) malloc((numrows + 1) * sizeof(int));
abort_if(!should_remove, "could not allocate should_remove");
slacks = (double *) malloc(numrows * sizeof(double));
@ -190,12 +192,12 @@ int LP_remove_slacks(struct LP *lp, int first_row, double max_slack)
rval = CPXdelrows(lp->cplex_env, lp->cplex_lp, start - count,
end - count);
abort_if(rval, "CPXdelrows failed");
log_verbose(" %d %d (%d)\n", start, end, end-start+1);
log_verbose(" %d %d (%d)\n", start, end, end - start + 1);
count += end - start + 1;
}
start = i+1;
start = i + 1;
end = i;
}
}
@ -252,3 +254,69 @@ int LP_write(struct LP *lp, const char *fname)
CLEANUP:
return rval;
}
#define return_if_neq(a, b) \
if((a)<(b)) return -1; \
if((a)>(b)) return 1;
#define return_if_neq_epsilon(a, b) \
if((a+LP_EPSILON)<(b)) return -1; \
if((a-LP_EPSILON)>(b)) return 1;
int compare_cuts(struct Row *cut1, struct Row *cut2)
{
return_if_neq(cut1->nz, cut2->nz);
for (int i = 0; i < cut1->nz; i++)
{
return_if_neq(cut1->rmatind[i], cut2->rmatind[i]);
return_if_neq_epsilon(cut1->rmatval[i], cut2->rmatval[i]);
}
return 0;
}
int LP_add_cut(struct LP *lp, struct Row *cut)
{
int rval = 0;
rval = LP_update_hash(cut);
abort_if(rval, "LP_update_hash failed");
for (int i = 0; i < lp->cut_pool_size; i++)
{
if (lp->cut_pool[i]->hash != cut->hash) continue;
if (!compare_cuts(lp->cut_pool[i], cut))
{
free(cut->rmatval);
free(cut->rmatind);
free(cut);
return 0;
}
}
lp->cut_pool[lp->cut_pool_size++] = cut;
int rmatbeg = 0;
rval = LP_add_rows(lp, 1, cut->nz, &cut->rhs, &cut->sense, &rmatbeg,
cut->rmatind, cut->rmatval);
abort_if(rval, "LP_add_rows failed");
CLEANUP:
return rval;
}
int LP_update_hash(struct Row *cut)
{
unsigned long hash = 0;
for (int i = 0; i < cut->nz; i++)
{
hash += cut->rmatind[i] * 65521;
hash %= 4294967291;
}
cut->hash = hash;
return 0;
}

@ -9,6 +9,21 @@ struct LP
{
CPXENVptr cplex_env;
CPXLPptr cplex_lp;
int cut_pool_size;
struct Row **cut_pool;
};
struct Row
{
unsigned long hash;
// int cplex_row_index;
int nz;
char sense;
double rhs;
double *rmatval;
int *rmatind;
};
static const int MAX_NAME_LENGTH = 100;
@ -56,4 +71,8 @@ int LP_get_num_cols(struct LP *lp);
int LP_remove_slacks(struct LP *lp, int start, double max_slack);
int LP_update_hash(struct Row *cut);
int LP_add_cut(struct LP *lp, struct Row *cut);
#endif

@ -9,7 +9,7 @@
#define LOG_LEVEL_DEBUG 40
#define LOG_LEVEL_VERBOSE 50
#define LOG_LEVEL LOG_LEVEL_DEBUG
#define LOG_LEVEL LOG_LEVEL_INFO
#if LOG_LEVEL < LOG_LEVEL_VERBOSE
#define log_verbose(...)