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

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

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

@ -6,6 +6,7 @@
#include "util.h" #include "util.h"
#define LP_EPSILON 0.000001 #define LP_EPSILON 0.000001
#define MAX_CUT_POOL_SIZE 100000
int LP_open(struct LP *lp) int LP_open(struct LP *lp)
{ {
@ -13,11 +14,11 @@ int LP_open(struct LP *lp)
lp->cplex_lp = (CPXLPptr) NULL; lp->cplex_lp = (CPXLPptr) NULL;
lp->cplex_env = CPXopenCPLEX(&rval); lp->cplex_env = CPXopenCPLEX(&rval);
if (rval) abort_if(rval, "CPXopenCPLEX failed");
{
fprintf(stderr, "CPXopenCPLEX failed, return code %d\n", rval); lp->cut_pool = (struct Row **) malloc(
goto CLEANUP; MAX_CUT_POOL_SIZE * sizeof(struct Row *));
} abort_if(!lp->cut_pool, "could not allocate cut_pool");
CLEANUP: CLEANUP:
return rval; return rval;
@ -33,6 +34,7 @@ void LP_free(struct LP *lp)
CPXcloseCPLEX(&lp->cplex_env); CPXcloseCPLEX(&lp->cplex_env);
lp->cplex_env = 0; lp->cplex_env = 0;
if (lp->cut_pool) free(lp->cut_pool);
} }
int LP_create(struct LP *lp, const char *name) int LP_create(struct LP *lp, const char *name)
@ -252,3 +254,69 @@ int LP_write(struct LP *lp, const char *fname)
CLEANUP: CLEANUP:
return rval; 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; CPXENVptr cplex_env;
CPXLPptr cplex_lp; 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; 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_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 #endif

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