00001 #include <stdio.h>
00002 #include <stdlib.h>
00003
00004 #include "eg_list.h"
00005 #include "eg_mempool.h"
00006 #include "graph_boyer.h"
00007 #include "graphdual.h"
00008
00009 #include "eg_util.h"
00010 #include "eg_dgraph.h"
00011 #include "eg_ddomino.h"
00012 #include "eg_pdp.h"
00013 #include "eg_util.h"
00014 #include "eg_ddpconstraint.h"
00015 #include "bc_spanning.h"
00016 #include "bc_util.h"
00017 #include "cookInterface.h"
00018 #include "eg_1pchecker.h"
00019 #include "eg_emptyhandles.h"
00020 double DDP_HEURISTIC_MAXTIME = 10.0;
00021
00022
00023 int DPseparator (int nnodes,
00024 int norig_edges,
00025 int *const orig_edges,
00026 double *const orig_weight,
00027 int *const nIneq,
00028 int **const ndominoes,
00029 int ***const naset,
00030 int ***const nbset,
00031 int **const nhandle,
00032 int ****const aset,
00033 int ****const bset,
00034 int ***const handle,
00035 const char *const boss_name,
00036 double percentage,
00037 double ddp_heuristic_maxtime)
00038 {
00039
00040 int i,
00041 rval;
00042 int is_connected;
00043
00044 int eliminated_edges_b = 0,
00045 is_G_planar_b = 0;
00046 int l_count = 0;
00047 unsigned int n_empty_handle = 0;
00048
00049 int *edges = 0,
00050 nedges = 0,
00051 nelim_edges = 0;
00052 double *weight = 0;
00053 double dpViolation;
00054 double *slack = 0;
00055
00056 graphP primalG = 0;
00057
00058 EGdGraph_t *biDualG = 0;
00059
00060 EGlist_t *dlist = 0;
00061 EGlist_t **dembed = 0;
00062
00063 EGlist_t *ddpc_list = 0;
00064
00065 EGmemPool_t *mem = 0;
00066
00067 EGddomino_t *ddom;
00068 EGlistNode_t *ddom_it,
00069 *ddp_it;
00070 #if ELIM_EDGES
00071 int *planar_edges = 0,
00072 nplanar_edges = 0,
00073 *elim_edges = 0;
00074 double *planar_weight = 0,
00075 error = 0;
00076 #endif
00077 #if DISPLAY_MODE
00078 int nfeasible = 0;
00079 int ncorrected = 0;
00080 int nnegative = 0;
00081 double dual_val,
00082 prim_val;
00083 #endif
00084
00085 DDP_HEURISTIC_MAXTIME = ddp_heuristic_maxtime;
00086 fprintf (stderr, "DP Version %s\n", DP_VERSION_STRING);
00087 #if DISPLAY_MODE
00088 if (!boss_name)
00089 fprintf (stdout, "DP Separator: NO boss.\n");
00090 else
00091 fprintf (stdout, "DP Separator: Noss name = %s.\n", boss_name);
00092 fflush (stdout);
00093 #endif
00094
00095 #if LOG_MODE
00096 saveBgraph ("graph.b.x", nnodes, norig_edges, orig_edges, orig_weight);
00097 #endif
00098
00099
00100 mem = EGnewMemPool (512, EGmemPoolNewSize, EGmemPoolNewSize (1));
00101
00102
00103 dlist = EGnewList (mem);
00104 ddpc_list = EGnewList (mem);
00105
00106 #if DISPLAY_MODE
00107 fprintf (stdout, "DP Separator: Graph G^* has %d nodes, and %d edges.\n",
00108 nnodes, norig_edges);
00109 fprintf (stdout,
00110 "DP Separator: Number of necessary edges for non-planarity = %d.\n",
00111 3 * nnodes - 5);
00112 fflush (stdout);
00113 #endif
00114
00115
00116 rval = removeSmallEdges (ZERO_X_EPSILON, orig_edges, norig_edges, orig_weight,
00117 &nedges, &edges, &weight, mem);
00118 CHECKRVAL (rval);
00119
00120 #if DISPLAY_MODE
00121 fprintf (stdout,
00122 "DP Separator: Eliminated %d edges of value less than %lf.\n",
00123 (norig_edges - nedges), ZERO_X_EPSILON);
00124 fflush (stdout);
00125 fprintf (stdout, "DP Separator: Graph G^* now has %d nodes, and %d edges.\n",
00126 nnodes, nedges);
00127 fflush (stdout);
00128 #endif
00129
00130
00131 primalG = gp_New ();
00132 rval = cook2boyerGraph (primalG, nnodes, nedges, edges);
00133 CHECKRVAL (rval);
00134 is_G_planar_b = gp_Embed (primalG, EMBEDFLAGS_PLANAR);
00135 rval = gp_SortVertices (primalG);
00136 EXITRVAL (rval);
00137
00138
00139 if (is_G_planar_b != OK)
00140 {
00141 #if DISPLAY_MODE
00142 fprintf (stdout, "DP Separator: Graph G^* is not planar.\n");
00143 fflush (stdout);
00144 #endif
00145
00146
00147 #if ELIM_EDGES
00148 #if DISPLAY_MODE
00149 fprintf (stdout, "DP Separator: Running edge-elimination "
00150 "heuristic to find planar sub-graph.\n");
00151 fflush (stdout);
00152 #endif
00153
00154
00155 planar_edges = EGmemPoolMalloc (mem, sizeof (int) * 2 * nedges);
00156 planar_weight = EGmemPoolMalloc (mem, sizeof (double) * nedges);
00157 elim_edges = EGmemPoolMalloc (mem, sizeof (int) * nedges);
00158
00159
00160 rval =
00161 DPedgeEliminationHeuristic (nnodes, nedges, edges, weight, &nplanar_edges,
00162 planar_edges, planar_weight, &nelim_edges,
00163 elim_edges);
00164
00165
00166
00167
00168
00169
00170
00171 CHECKRVAL (rval);
00172
00173 #if DISPLAY_MODE
00174 fprintf (stdout, "DP Separator: Completed edge-elimination.");
00175 fflush (stdout);
00176 #endif
00177
00178 eliminated_edges_b = 1;
00179 TEST (nplanar_edges == nedges, "ERROR: Graph is not planar, yet no edges "
00180 "were eliminated.");
00181
00182 for (i = 0; i < nedges - nplanar_edges; i++)
00183 error += weight[elim_edges[i]];
00184
00185 #if DISPLAY_MODE
00186 fprintf (stdout, "DP Separator: Found a planar sub-graph with %d edges.\n",
00187 nplanar_edges);
00188 fflush (stdout);
00189 fprintf (stdout, "DP Separator: Total weight of eliminated edges is %lf.\n",
00190 error);
00191 fflush (stdout);
00192 #endif
00193 #endif
00194 }
00195
00196
00197 else
00198 {
00199 #if DISPLAY_MODE
00200 fprintf (stdout, "DP Separator: Graph G^* is planar.\n");
00201 fflush (stdout);
00202 #endif
00203 eliminated_edges_b = 0;
00204 planar_edges = edges;
00205 nplanar_edges = nedges;
00206 planar_weight = weight;
00207 }
00208
00209 #if LOG_MODE
00210 saveBgraph ("graph.planar.b.x", nnodes, nplanar_edges, planar_edges,
00211 planar_weight);
00212 saveGraph ("graph.planar.x", nnodes, nplanar_edges, planar_edges,
00213 planar_weight);
00214 #endif
00215 #if DISPLAY_MODE
00216 fprintf (stdout, "DP Separator: Computing dual of G^*.\n");
00217 fflush (stdout);
00218 #endif
00219 is_connected = EGisCookGraphConnected (nnodes, nplanar_edges, planar_edges,
00220 mem);
00221
00222 #if DISPLAY_MODE
00223 if (is_connected)
00224 fprintf (stdout, "DP Separator: G^* is connected.\n");
00225 else
00226 fprintf (stdout, "DP Separator: G^* is not connected.\n");
00227 #endif
00228
00229 if (!is_connected)
00230 goto END_DP;
00231
00232
00233 gp_Free (&primalG);
00234 primalG = gp_New ();
00235 rval = cook2boyerGraph (primalG, nnodes, nplanar_edges, planar_edges);
00236 CHECKRVAL (rval);
00237 biDualG = getDualBoyer (primalG, nnodes, nplanar_edges, planar_weight,
00238 &dembed, mem,0);
00239 if (!biDualG)
00240 goto END_DP;
00241
00242 #if DISPLAY_MODE
00243 fprintf (stdout, "DP Separator: Bi-directed dual graph "
00244 "has %d nodes and %d edges.\n",
00245 biDualG->nodes->size, biDualG->nedges);
00246 fprintf (stdout, "DP Separator: Looking for dual dominoes.\n");
00247 fflush (stdout);
00248 #endif
00249
00250
00251 if (boss_name == 0)
00252 rval = EGddominoComputeAll (mem, biDualG, dlist, 1, percentage);
00253 else
00254 rval = EGddominoComputeAllRemote (mem, biDualG, dlist, 1, boss_name,
00255 DDP_HEURISTIC_MAXTIME);
00256 CHECKRVAL (rval);
00257
00258 #if DISPLAY_MODE
00259 fprintf (stdout, "DP Separator: Found %d dual dominoes.\n", dlist->size);
00260 fflush (stdout);
00261 #endif
00262
00263
00264 rval = EGuntangleAllDomino (dlist, biDualG, dembed, mem);
00265 CHECKRVAL (rval);
00266
00267 if (!dlist->size)
00268 goto END_DP;
00269
00270
00271 rval =
00272 EGfixDualDominos (dlist, nnodes, nedges, weight, edges,
00273 elim_edges, nelim_edges, primalG, mem);
00274 CHECKRVAL (rval);
00275
00276
00277 #if DISPLAY_MODE
00278 if (eliminated_edges_b)
00279 {
00280
00281 ncorrected = 0;
00282 nnegative = 0;
00283 nfeasible = 0;
00284
00285 for (ddom_it = dlist->begin; ddom_it; ddom_it = ddom_it->next)
00286 {
00287
00288 ddom = (EGddomino_t *) (ddom_it->this);
00289 dual_val = EGdijkstraCostToLf (ddom->value);
00290 prim_val = EGdijkstraCostToLf (ddom->primalValue);
00291
00292 if (fabs (dual_val - prim_val) > 0.0001)
00293 {
00294 ncorrected++;
00295 }
00296 if (dual_val < 0)
00297 {
00298 nnegative++;
00299 }
00300 if (prim_val < 1.0000)
00301 nfeasible++;
00302 }
00303 fprintf (stdout,
00304 "DP Separator: Corrected %d values. %d / %d dominoes remain feasible.\n",
00305 ncorrected, nfeasible, dlist->size);
00306 fflush (stdout);
00307 }
00308 #endif
00309
00310
00311 rval = EGddpcComputeAll (mem, biDualG, dlist, ddpc_list, nedges, 1);
00312 CHECKRVAL (rval);
00313
00314 #if DISPLAY_MODE
00315
00316 double thresh,
00317 thresh_n;
00318 unsigned int range[DISPLAY_RESOLUTION],
00319 max_violated = 0;
00320
00321 for (i = 0; i < DISPLAY_RESOLUTION; i++)
00322 range[i] = 0;
00323
00324 #endif
00325
00326
00327 *nIneq = 0;
00328 *ndominoes = 0;
00329 *naset = 0;
00330 *nbset = 0;
00331 *aset = 0;
00332 *bset = 0;
00333 *nhandle = 0;
00334 *handle = 0;
00335
00336
00337 if (ddpc_list->size)
00338 {
00339 *ndominoes = EGsMalloc (int,
00340 ddpc_list->size);
00341 *naset = EGsMalloc (int *,
00342 ddpc_list->size);
00343 *nbset = EGsMalloc (int *,
00344 ddpc_list->size);
00345 *nhandle = EGsMalloc (int,
00346 ddpc_list->size);
00347 *aset = EGsMalloc (int **,
00348 ddpc_list->size);
00349 *bset = EGsMalloc (int **,
00350 ddpc_list->size);
00351 *handle = EGsMalloc (int *,
00352 ddpc_list->size);
00353 (*aset)[0] = 0;
00354 }
00355
00356 if (ddpc_list->size)
00357 slack = EGsMalloc (double,
00358 ddpc_list->size);
00359
00360 #if DISPLAY_MODE
00361 fprintf (stdout,
00362 "DP Separator: Primalizing constraints and computing primal slack.\n");
00363 #endif
00364
00365 for (ddp_it = ddpc_list->begin; ddp_it; ddp_it = ddp_it->next)
00366 {
00367 rval = EGgetPrimalDP ((EGddpConstraint_t *) (ddp_it->this),
00368 nnodes,
00369 nedges,
00370 edges,
00371 elim_edges,
00372 nelim_edges,
00373 weight,
00374 (*ndominoes) + (*nIneq),
00375 (*naset) + (*nIneq),
00376 (*nbset) + (*nIneq),
00377 (*nhandle) + (*nIneq),
00378 (*aset) + (*nIneq),
00379 (*bset) + (*nIneq),
00380 (*handle) + (*nIneq), &dpViolation, primalG, mem);
00381 CHECKRVAL (rval);
00382 if (!((*nhandle)[*nIneq]))
00383 n_empty_handle++;
00384
00385 l_count++;
00386 if (dpViolation < 0)
00387 {
00388 slack[*nIneq] = dpViolation;
00389 (*nIneq)++;
00390 #if DISPLAY_MODE
00391 for (i = 0; i < DISPLAY_RESOLUTION; i++)
00392 {
00393 thresh = IDR * i + IDR;
00394 thresh_n = IDR * i;
00395 if (thresh_n <= -1 * dpViolation && -1 * dpViolation <= thresh)
00396 {
00397 range[i] += 1;
00398 break;
00399 }
00400 }
00401
00402 if (-1 * dpViolation > 1.0 - DP_MAXVIOLATED_EPSILON)
00403 max_violated += 1;
00404
00405 #endif
00406
00407 }
00408 else
00409 {
00410 for (i = (*ndominoes)[*nIneq]; i--;)
00411 {
00412 EGfree ((*aset)[*nIneq][i]);
00413 EGfree ((*bset)[*nIneq][i]);
00414 }
00415 EGfree ((*naset)[*nIneq]);
00416 EGfree ((*nbset)[*nIneq]);
00417 EGfree ((*aset)[*nIneq]);
00418 EGfree ((*bset)[*nIneq]);
00419 if ((*nhandle)[*nIneq])
00420 EGfree ((*handle)[*nIneq]);
00421 }
00422 }
00423
00424 #if DISPLAY_MODE
00425 fprintf (stdout, "DP Separator: Found %d primal DP-Constraints.\n", *nIneq);
00426 fprintf (stdout, "DP Separator: Found %u empty handles.\n", n_empty_handle);
00427 fflush (stdout);
00428
00429 if (nelim_edges || 1)
00430 {
00431
00432 fprintf (stdout, "DP Separator: Final |slack values|\n");
00433 fflush (stdout);
00434
00435 for (i = 0; i < DISPLAY_RESOLUTION; i++)
00436 {
00437 thresh = IDR * i + IDR;
00438 thresh_n = IDR * i;
00439 if (range[i])
00440 fprintf (stdout, "[%8lf, %8lf] %d\n", thresh_n, thresh, range[i]);
00441 fflush (stdout);
00442 }
00443
00444 fprintf (stdout, "Max-Violations %d\n", max_violated);
00445 fflush (stdout);
00446
00447 }
00448 #endif
00449
00450 if (*nIneq)
00451 {
00452 double *violation;
00453 int **e_coeff;
00454 violation = EGsMalloc (double,
00455 *nIneq);
00456 e_coeff = EGsMalloc (int *,
00457 *nIneq);
00458 for (i = *nIneq; i--;)
00459 e_coeff[i] = EGsMalloc (int,
00460 norig_edges);
00461 rval = EG1pChecker (nnodes, norig_edges, orig_edges, orig_weight, *nIneq,
00462 *ndominoes, *naset, *nbset, *nhandle,
00463 *aset, *bset, *handle, violation, e_coeff);
00464 CHECKRVAL (rval);
00465 for (i = *nIneq; i--;)
00466 {
00467 WARNING (fabs (violation[i] - slack[i]) > 1e-2,
00468 "Violation don't agree for ineq "
00469 "%i\n(computed)%7.5lf (alg)%7.5lf (diff)%7.5lf\n", i,
00470 violation[i], slack[i], fabs (violation[i] - slack[i]));
00471 EGfree (e_coeff[i]);
00472 }
00473 EGfree (violation);
00474 EGfree (e_coeff);
00475 }
00476 if (slack)
00477 EGfree (slack);
00478
00479 #if DP_REMOVE_EMPTY_HANDLES
00480 if (n_empty_handle)
00481 {
00482
00483 #if DISPLAY_MODE
00484 fprintf (stdout, "DP Separator: Removing empty-handle constraints.\n");
00485 fflush (stdout);
00486 #endif
00487
00488 rval =
00489 DPremoveEmptyHandles (nIneq, ndominoes, naset, nbset, nhandle, aset, bset,
00490 handle);
00491 CHECKRVAL (rval);
00492
00493 #if DISPLAY_MODE
00494 fprintf (stdout,
00495 "DP Separator: Final number of non-empty-handle constraints: %d.\n",
00496 *nIneq);
00497 fflush (stdout);
00498 #endif
00499
00500 }
00501 #endif
00502
00503
00504
00505 END_DP:
00506
00507 #if DISPLAY_MODE
00508 fprintf (stdout, "DP Separator: Bye.\n");
00509 fflush (stdout);
00510 #endif
00511
00512
00513 if (dlist)
00514 {
00515 if (dlist->size)
00516 EGlistClearMP (dlist, EGfreeDdomino, mem);
00517 EGfreeList (dlist);
00518 }
00519
00520 if (ddpc_list)
00521 {
00522 if (ddpc_list->size)
00523 EGlistClearMP (ddpc_list, EGfreeDDPconstraintMP, mem);
00524 EGfreeList (ddpc_list);
00525 }
00526
00527
00528 if (weight)
00529 EGmemPoolFree (weight, sizeof (double) * nedges, mem);
00530 if (edges)
00531 EGmemPoolFree (edges, sizeof (int) * 2 * nedges, mem);
00532
00533 #if ELIM_EDGES
00534
00535 if (eliminated_edges_b)
00536 {
00537 EGmemPoolSFree (planar_edges, int,
00538 2 * nedges,
00539 mem);
00540 EGmemPoolSFree (elim_edges, int,
00541 nedges,
00542 mem);
00543 EGmemPoolSFree (planar_weight, double,
00544 nedges,
00545 mem);
00546 }
00547 #endif
00548
00549
00550 if (biDualG)
00551 {
00552 EGdGraphClearMP (biDualG, EGfreeMengerEdgeDataMP, EGfreeMengerNodeDataMP, 0,
00553 mem, mem, 0);
00554 EGfreeDGraph (biDualG);
00555 }
00556
00557 if (dembed)
00558 {
00559 for (i = nplanar_edges - nnodes + 2; i--;)
00560 EGfreeList (dembed[i]);
00561 EGmemPoolSFree (dembed, EGlist_t *, nplanar_edges - nnodes + 2, mem);
00562 }
00563
00564 EGfreeMemPool (mem);
00565 gp_Free (&primalG);
00566
00567
00568 return 0;
00569
00570 }