00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "mincov_int.h"
00011
00012
00013
00014
00015
00016 #define USE_GIMPEL
00017 #define USE_INDEP_SET
00018
00019 static int select_column();
00020 static void select_essential();
00021 static int verify_cover();
00022
00023 #define fail(why) {\
00024 (void) fprintf(stderr, "Fatal error: file %s, line %d\n%s\n",\
00025 __FILE__, __LINE__, why);\
00026 (void) fflush(stdout);\
00027 abort();\
00028 }
00029
00030 sm_row *
00031 sm_minimum_cover(A, weight, heuristic, debug_level)
00032 sm_matrix *A;
00033 int *weight;
00034 int heuristic;
00035 int debug_level;
00036 {
00037 stats_t stats;
00038 solution_t *best, *select;
00039 sm_row *prow, *sol;
00040 sm_col *pcol;
00041 sm_matrix *dup_A;
00042 int nelem, bound;
00043 double sparsity;
00044
00045
00046 if (A->nrows <= 0) {
00047 return sm_row_alloc();
00048 }
00049
00050
00051 stats.start_time = util_cpu_time();
00052 stats.debug = debug_level > 0;
00053 stats.max_print_depth = debug_level;
00054 stats.max_depth = -1;
00055 stats.nodes = 0;
00056 stats.component = stats.comp_count = 0;
00057 stats.gimpel = stats.gimpel_count = 0;
00058 stats.no_branching = heuristic != 0;
00059 stats.lower_bound = -1;
00060
00061
00062 nelem = 0;
00063 sm_foreach_row(A, prow) {
00064 nelem += prow->length;
00065 }
00066 sparsity = (double) nelem / (double) (A->nrows * A->ncols);
00067
00068
00069 bound = 1;
00070 sm_foreach_col(A, pcol) {
00071 bound += WEIGHT(weight, pcol->col_num);
00072 }
00073
00074
00075 select = solution_alloc();
00076 dup_A = sm_dup(A);
00077 best = sm_mincov(dup_A, select, weight, 0, bound, 0, &stats);
00078 sm_free(dup_A);
00079 solution_free(select);
00080
00081 if (stats.debug) {
00082 if (stats.no_branching) {
00083 (void) printf("**** heuristic covering ...\n");
00084 (void) printf("lower bound = %d\n", stats.lower_bound);
00085 }
00086 (void) printf("matrix = %d by %d with %d elements (%4.3f%%)\n",
00087 A->nrows, A->ncols, nelem, sparsity * 100.0);
00088 (void) printf("cover size = %d elements\n", best->row->length);
00089 (void) printf("cover cost = %d\n", best->cost);
00090 (void) printf("time = %s\n",
00091 util_print_time(util_cpu_time() - stats.start_time));
00092 (void) printf("components = %d\n", stats.comp_count);
00093 (void) printf("gimpel = %d\n", stats.gimpel_count);
00094 (void) printf("nodes = %d\n", stats.nodes);
00095 (void) printf("max_depth = %d\n", stats.max_depth);
00096 }
00097
00098 sol = sm_row_dup(best->row);
00099 if (! verify_cover(A, sol)) {
00100 fail("mincov: internal error -- cover verification failed\n");
00101 }
00102 solution_free(best);
00103 return sol;
00104 }
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 solution_t *
00116 sm_mincov(A, select, weight, lb, bound, depth, stats)
00117 sm_matrix *A;
00118 solution_t *select;
00119 int *weight;
00120 int lb;
00121 int bound;
00122 int depth;
00123 stats_t *stats;
00124 {
00125 sm_matrix *A1, *A2, *L, *R;
00126 sm_element *p;
00127 solution_t *select1, *select2, *best, *best1, *best2, *indep;
00128 int pick, lb_new, debug;
00129
00130
00131 stats->nodes++;
00132 if (depth > stats->max_depth) stats->max_depth = depth;
00133 debug = stats->debug && (depth <= stats->max_print_depth);
00134
00135
00136 select_essential(A, select, weight, bound);
00137 if (select->cost >= bound) {
00138 return NIL(solution_t);
00139 }
00140
00141
00142 #ifdef USE_GIMPEL
00143 if ( weight == NIL(int)) {
00144 if (gimpel_reduce(A, select, weight, lb, bound, depth, stats, &best)) {
00145 return best;
00146 }
00147 }
00148 #endif
00149
00150 #ifdef USE_INDEP_SET
00151
00152 indep = sm_maximal_independent_set(A, weight);
00153
00154
00155 lb_new = MAX(select->cost + indep->cost, lb);
00156 pick = select_column(A, weight, indep);
00157 solution_free(indep);
00158 #else
00159 lb_new = select->cost + (A->nrows > 0);
00160 pick = select_column(A, weight, NIL(solution_t));
00161 #endif
00162
00163 if (depth == 0) {
00164 stats->lower_bound = lb_new + stats->gimpel;
00165 }
00166
00167 if (debug) {
00168 (void) printf("ABSMIN[%2d]%s", depth, stats->component ? "*" : " ");
00169 (void) printf(" %3dx%3d sel=%3d bnd=%3d lb=%3d %12s ",
00170 A->nrows, A->ncols, select->cost + stats->gimpel,
00171 bound + stats->gimpel, lb_new + stats->gimpel,
00172 util_print_time(util_cpu_time()-stats->start_time));
00173 }
00174
00175
00176 if (lb_new >= bound) {
00177 if (debug) (void) printf("bounded\n");
00178 best = NIL(solution_t);
00179
00180
00181
00182 } else if (A->nrows == 0) {
00183 best = solution_dup(select);
00184 if (debug) (void) printf("BEST\n");
00185 if (stats->debug && stats->component == 0) {
00186 (void) printf("new 'best' solution %d at level %d (time is %s)\n",
00187 best->cost + stats->gimpel, depth,
00188 util_print_time(util_cpu_time() - stats->start_time));
00189 }
00190
00191
00192
00193 } else if (sm_block_partition(A, &L, &R)) {
00194
00195 if (L->ncols > R->ncols) {
00196 A1 = L;
00197 L = R;
00198 R = A1;
00199 }
00200 if (debug) (void) printf("comp %d %d\n", L->nrows, R->nrows);
00201 stats->comp_count++;
00202
00203
00204 select1 = solution_alloc();
00205 stats->component++;
00206 best1 = sm_mincov(L, select1, weight, 0,
00207 bound-select->cost, depth+1, stats);
00208 stats->component--;
00209 solution_free(select1);
00210 sm_free(L);
00211
00212
00213 if (best1 == NIL(solution_t)) {
00214 best = NIL(solution_t);
00215 } else {
00216 for(p = best1->row->first_col; p != 0; p = p->next_col) {
00217 solution_add(select, weight, p->col_num);
00218 }
00219 solution_free(best1);
00220
00221
00222 best = sm_mincov(R, select, weight, lb_new, bound, depth+1, stats);
00223 }
00224 sm_free(R);
00225
00226
00227 } else {
00228 if (debug) (void) printf("pick=%d\n", pick);
00229
00230
00231 A1 = sm_dup(A);
00232 select1 = solution_dup(select);
00233 solution_accept(select1, A1, weight, pick);
00234 best1 = sm_mincov(A1, select1, weight, lb_new, bound, depth+1, stats);
00235 solution_free(select1);
00236 sm_free(A1);
00237
00238
00239 if (best1 != NIL(solution_t) && bound > best1->cost) {
00240 bound = best1->cost;
00241 }
00242
00243
00244 if (stats->no_branching) {
00245 return best1;
00246 }
00247
00248
00249 if (best1 != NIL(solution_t) && best1->cost == lb_new) {
00250 return best1;
00251 }
00252
00253
00254 A2 = sm_dup(A);
00255 select2 = solution_dup(select);
00256 solution_reject(select2, A2, weight, pick);
00257 best2 = sm_mincov(A2, select2, weight, lb_new, bound, depth+1, stats);
00258 solution_free(select2);
00259 sm_free(A2);
00260
00261 best = solution_choose_best(best1, best2);
00262 }
00263
00264 return best;
00265 }
00266
00267 static int
00268 select_column(A, weight, indep)
00269 sm_matrix *A;
00270 int *weight;
00271 solution_t *indep;
00272 {
00273 register sm_col *pcol;
00274 register sm_row *prow, *indep_cols;
00275 register sm_element *p, *p1;
00276 double w, best;
00277 int best_col;
00278
00279 indep_cols = sm_row_alloc();
00280 if (indep != NIL(solution_t)) {
00281
00282 for(p = indep->row->first_col; p != 0; p = p->next_col) {
00283 prow = sm_get_row(A, p->col_num);
00284 for(p1 = prow->first_col; p1 != 0; p1 = p1->next_col) {
00285 (void) sm_row_insert(indep_cols, p1->col_num);
00286 }
00287 }
00288 } else {
00289
00290 sm_foreach_col(A, pcol) {
00291 (void) sm_row_insert(indep_cols, pcol->col_num);
00292 }
00293 }
00294
00295
00296 best_col = -1;
00297 best = -1;
00298
00299
00300 sm_foreach_row_element(indep_cols, p1) {
00301 pcol = sm_get_col(A, p1->col_num);
00302
00303
00304 w = 0.0;
00305 for(p = pcol->first_row; p != 0; p = p->next_row) {
00306 prow = sm_get_row(A, p->row_num);
00307 w += 1.0 / ((double) prow->length - 1.0);
00308 }
00309
00310
00311 w = w / (double) WEIGHT(weight, pcol->col_num);
00312
00313
00314 if (w > best) {
00315 best_col = pcol->col_num;
00316 best = w;
00317 }
00318 }
00319
00320 sm_row_free(indep_cols);
00321 return best_col;
00322 }
00323
00324 static void
00325 select_essential(A, select, weight, bound)
00326 sm_matrix *A;
00327 solution_t *select;
00328 int *weight;
00329 int bound;
00330 {
00331 register sm_element *p;
00332 register sm_row *prow, *essen;
00333 int delcols, delrows, essen_count;
00334
00335 do {
00336
00337 delcols = sm_col_dominance(A, weight);
00338
00339
00340 essen = sm_row_alloc();
00341 sm_foreach_row(A, prow) {
00342 if (prow->length == 1) {
00343 (void) sm_row_insert(essen, prow->first_col->col_num);
00344 }
00345 }
00346
00347
00348 sm_foreach_row_element(essen, p) {
00349 solution_accept(select, A, weight, p->col_num);
00350
00351 if (select->cost >= bound) {
00352 sm_row_free(essen);
00353 return;
00354 }
00355 }
00356 essen_count = essen->length;
00357 sm_row_free(essen);
00358
00359
00360 delrows = sm_row_dominance(A);
00361
00362 } while (delcols > 0 || delrows > 0 || essen_count > 0);
00363 }
00364
00365 static int
00366 verify_cover(A, cover)
00367 sm_matrix *A;
00368 sm_row *cover;
00369 {
00370 sm_row *prow;
00371
00372 sm_foreach_row(A, prow) {
00373 if (! sm_row_intersects(prow, cover)) {
00374 return 0;
00375 }
00376 }
00377 return 1;
00378 }