#include "mincov_int.h"
ABC_NAMESPACE_IMPL_START
#define USE_GIMPEL
#define USE_INDEP_SET
static int select_column();
static void select_essential();
static int verify_cover();
#define fail(why) {\
(void) fprintf(stderr, "Fatal error: file %s, line %d\n%s\n",\
__FILE__, __LINE__, why);\
(void) fflush(stdout);\
abort();\
}
sm_row *
sm_minimum_cover(A, weight, heuristic, debug_level)
sm_matrix *A;
int *weight;
int heuristic;
int debug_level;
{
stats_t stats;
solution_t *best, *select;
sm_row *prow, *sol;
sm_col *pcol;
sm_matrix *dup_A;
int nelem, bound;
double sparsity;
if (A->nrows <= 0) {
return sm_row_alloc();
}
stats.start_time = util_cpu_time();
stats.debug = debug_level > 0;
stats.max_print_depth = debug_level;
stats.max_depth = -1;
stats.nodes = 0;
stats.component = stats.comp_count = 0;
stats.gimpel = stats.gimpel_count = 0;
stats.no_branching = heuristic != 0;
stats.lower_bound = -1;
nelem = 0;
sm_foreach_row(A, prow) {
nelem += prow->length;
}
sparsity = (double) nelem / (double) (A->nrows * A->ncols);
bound = 1;
sm_foreach_col(A, pcol) {
bound += WEIGHT(weight, pcol->col_num);
}
select = solution_alloc();
dup_A = sm_dup(A);
best = sm_mincov(dup_A, select, weight, 0, bound, 0, &stats);
sm_free(dup_A);
solution_free(select);
if (stats.debug) {
if (stats.no_branching) {
(void) printf("**** heuristic covering ...\n");
(void) printf("lower bound = %d\n", stats.lower_bound);
}
(void) printf("matrix = %d by %d with %d elements (%4.3f%%)\n",
A->nrows, A->ncols, nelem, sparsity * 100.0);
(void) printf("cover size = %d elements\n", best->row->length);
(void) printf("cover cost = %d\n", best->cost);
(void) printf("time = %s\n",
util_print_time(util_cpu_time() - stats.start_time));
(void) printf("components = %d\n", stats.comp_count);
(void) printf("gimpel = %d\n", stats.gimpel_count);
(void) printf("nodes = %d\n", stats.nodes);
(void) printf("max_depth = %d\n", stats.max_depth);
}
sol = sm_row_dup(best->row);
if (! verify_cover(A, sol)) {
fail("mincov: internal error -- cover verification failed\n");
}
solution_free(best);
return sol;
}
solution_t *
sm_mincov(A, select, weight, lb, bound, depth, stats)
sm_matrix *A;
solution_t *select;
int *weight;
int lb;
int bound;
int depth;
stats_t *stats;
{
sm_matrix *A1, *A2, *L, *R;
sm_element *p;
solution_t *select1, *select2, *best, *best1, *best2, *indep;
int pick, lb_new, debug;
stats->nodes++;
if (depth > stats->max_depth) stats->max_depth = depth;
debug = stats->debug && (depth <= stats->max_print_depth);
select_essential(A, select, weight, bound);
if (select->cost >= bound) {
return NIL(solution_t);
}
#ifdef USE_GIMPEL
if ( weight == NIL(int)) {
if (gimpel_reduce(A, select, weight, lb, bound, depth, stats, &best)) {
return best;
}
}
#endif
#ifdef USE_INDEP_SET
indep = sm_maximal_independent_set(A, weight);
lb_new = MAX(select->cost + indep->cost, lb);
pick = select_column(A, weight, indep);
solution_free(indep);
#else
lb_new = select->cost + (A->nrows > 0);
pick = select_column(A, weight, NIL(solution_t));
#endif
if (depth == 0) {
stats->lower_bound = lb_new + stats->gimpel;
}
if (debug) {
(void) printf("ABSMIN[%2d]%s", depth, stats->component ? "*" : " ");
(void) printf(" %3dx%3d sel=%3d bnd=%3d lb=%3d %12s ",
A->nrows, A->ncols, select->cost + stats->gimpel,
bound + stats->gimpel, lb_new + stats->gimpel,
util_print_time(util_cpu_time()-stats->start_time));
}
if (lb_new >= bound) {
if (debug) (void) printf("bounded\n");
best = NIL(solution_t);
} else if (A->nrows == 0) {
best = solution_dup(select);
if (debug) (void) printf("BEST\n");
if (stats->debug && stats->component == 0) {
(void) printf("new 'best' solution %d at level %d (time is %s)\n",
best->cost + stats->gimpel, depth,
util_print_time(util_cpu_time() - stats->start_time));
}
} else if (sm_block_partition(A, &L, &R)) {
if (L->ncols > R->ncols) {
A1 = L;
L = R;
R = A1;
}
if (debug) (void) printf("comp %d %d\n", L->nrows, R->nrows);
stats->comp_count++;
select1 = solution_alloc();
stats->component++;
best1 = sm_mincov(L, select1, weight, 0,
bound-select->cost, depth+1, stats);
stats->component--;
solution_free(select1);
sm_free(L);
if (best1 == NIL(solution_t)) {
best = NIL(solution_t);
} else {
for(p = best1->row->first_col; p != 0; p = p->next_col) {
solution_add(select, weight, p->col_num);
}
solution_free(best1);
best = sm_mincov(R, select, weight, lb_new, bound, depth+1, stats);
}
sm_free(R);
} else {
if (debug) (void) printf("pick=%d\n", pick);
A1 = sm_dup(A);
select1 = solution_dup(select);
solution_accept(select1, A1, weight, pick);
best1 = sm_mincov(A1, select1, weight, lb_new, bound, depth+1, stats);
solution_free(select1);
sm_free(A1);
if (best1 != NIL(solution_t) && bound > best1->cost) {
bound = best1->cost;
}
if (stats->no_branching) {
return best1;
}
if (best1 != NIL(solution_t) && best1->cost == lb_new) {
return best1;
}
A2 = sm_dup(A);
select2 = solution_dup(select);
solution_reject(select2, A2, weight, pick);
best2 = sm_mincov(A2, select2, weight, lb_new, bound, depth+1, stats);
solution_free(select2);
sm_free(A2);
best = solution_choose_best(best1, best2);
}
return best;
}
static int
select_column(A, weight, indep)
sm_matrix *A;
int *weight;
solution_t *indep;
{
register sm_col *pcol;
register sm_row *prow, *indep_cols;
register sm_element *p, *p1;
double w, best;
int best_col;
indep_cols = sm_row_alloc();
if (indep != NIL(solution_t)) {
for(p = indep->row->first_col; p != 0; p = p->next_col) {
prow = sm_get_row(A, p->col_num);
for(p1 = prow->first_col; p1 != 0; p1 = p1->next_col) {
(void) sm_row_insert(indep_cols, p1->col_num);
}
}
} else {
sm_foreach_col(A, pcol) {
(void) sm_row_insert(indep_cols, pcol->col_num);
}
}
best_col = -1;
best = -1;
sm_foreach_row_element(indep_cols, p1) {
pcol = sm_get_col(A, p1->col_num);
w = 0.0;
for(p = pcol->first_row; p != 0; p = p->next_row) {
prow = sm_get_row(A, p->row_num);
w += 1.0 / ((double) prow->length - 1.0);
}
w = w / (double) WEIGHT(weight, pcol->col_num);
if (w > best) {
best_col = pcol->col_num;
best = w;
}
}
sm_row_free(indep_cols);
return best_col;
}
static void
select_essential(A, select, weight, bound)
sm_matrix *A;
solution_t *select;
int *weight;
int bound;
{
register sm_element *p;
register sm_row *prow, *essen;
int delcols, delrows, essen_count;
do {
delcols = sm_col_dominance(A, weight);
essen = sm_row_alloc();
sm_foreach_row(A, prow) {
if (prow->length == 1) {
(void) sm_row_insert(essen, prow->first_col->col_num);
}
}
sm_foreach_row_element(essen, p) {
solution_accept(select, A, weight, p->col_num);
if (select->cost >= bound) {
sm_row_free(essen);
return;
}
}
essen_count = essen->length;
sm_row_free(essen);
delrows = sm_row_dominance(A);
} while (delcols > 0 || delrows > 0 || essen_count > 0);
}
static int
verify_cover(A, cover)
sm_matrix *A;
sm_row *cover;
{
sm_row *prow;
sm_foreach_row(A, prow) {
if (! sm_row_intersects(prow, cover)) {
return 0;
}
}
return 1;
}
ABC_NAMESPACE_IMPL_END