Scippy

SCIP

Solving Constraint Integer Programs

reduce_bnd.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2015 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file dirreduce.c
17  * @brief bound based reductions for Steiner tree problems
18  * @author Daniel Rehfeldt
19  *
20  * This file implements bound-based reduction techniques for several Steiner problems.
21  * All tests can be found in "A Generic Approach to Solving the Steiner Tree Problem and Variants" by Daniel Rehfeldt.
22  *
23  * A list of all interface methods can be found in grph.h.
24  *
25  */
26 
27 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 #include "scip/scip.h"
34 #include "grph.h"
35 #include "heur_tm.h"
36 #include "cons_stp.h"
37 #include "heur_local.h"
38 #include "misc_stp.h"
39 #include "prop_stp.h"
40 #include "probdata_stp.h"
41 
42 #define DEFAULT_HEURRUNS 100 /**< number of runs of constructive heuristic */
43 #define DEFAULT_DARUNS 5 /**< number of runs for dual ascent heuristic */
44 
45 #if 0
46 /** print graph (in undirected form) in GML format */
47 static
48 SCIP_RETCODE probdataPrintGraph(
49  GRAPH* graph, /**< Graph to be printed */
50  const char* filename, /**< Name of the output file */
51  SCIP_Bool* edgemark /**< Array of (undirected) edges to highlight */
52  )
53 {
54  char label[SCIP_MAXSTRLEN];
55  FILE* file;
56  int e;
57  int n;
58  int m;
59 
60  assert(graph != NULL);
61  file = fopen((filename != NULL) ? filename : "stpgraph.gml", "w");
62 
63 #ifndef NDEBUG
64  for( e = 0; e < graph->edges; e += 2 )
65  {
66  assert(graph->tail[e] == graph->head[e + 1]);
67  assert(graph->tail[e + 1] == graph->head[e]);
68  }
69 #endif
70 
71  /* write GML format opening, undirected */
72  SCIPgmlWriteOpening(file, FALSE);
73 
74  /* write all nodes, discriminate between root, terminals and the other nodes */
75  e = 0;
76  m = 0;
77  for( n = 0; n < graph->knots; ++n )
78  {
79 #if 1
80  if( n == graph->source[0] )
81  {
82  (void)SCIPsnprintf(label, SCIP_MAXSTRLEN, "(%d) Root", n);
83  SCIPgmlWriteNode(file, (unsigned int)n, label, "rectangle", "#666666", NULL);
84  m = 1;
85  }
86  else if( graph->term[n] == 0 )
87  {
88  (void)SCIPsnprintf(label, SCIP_MAXSTRLEN, "(%d) Terminal %d", n, e + 1);
89  SCIPgmlWriteNode(file, (unsigned int)n, label, "circle", "#ff0000", NULL);
90  e += 1;
91  }
92  else
93  {
94  (void)SCIPsnprintf(label, SCIP_MAXSTRLEN, "(%d) Node %d", n, n + 1 - e - m);
95  SCIPgmlWriteNode(file, (unsigned int)n, label, "circle", "#336699", NULL);
96  }
97 #else
98  (void)SCIPsnprintf(label, SCIP_MAXSTRLEN, "");
99  if( n == graph->source[0] )
100  {
101 
102  SCIPgmlWriteNode(file, (unsigned int)n, label, "rectangle", "#666666", NULL);
103  m = 1;
104  }
105  else if( graph->term[n] == 0 )
106  {
107 
108  SCIPgmlWriteNode(file, (unsigned int)n, label, "rectangle", "#666666", NULL);
109  e += 1;
110  }
111  else
112  {
113  SCIPgmlWriteNode(file, (unsigned int)n, label, "circle", "#666666", NULL);
114  }
115 #endif
116 
117  }
118 
119  /* write all edges (undirected) */
120  for( e = 0; e < graph->edges; e += 2 )
121  {
122 #if 1
123  (void)SCIPsnprintf(label, SCIP_MAXSTRLEN, "%8.2f", graph->cost[e]);
124 #endif
125  if( edgemark != NULL && edgemark[e / 2] )
126  SCIPgmlWriteEdge(file, (unsigned int)graph->tail[e], (unsigned int)graph->head[e], label, "#ff0000");
127  else
128  SCIPgmlWriteEdge(file, (unsigned int)graph->tail[e], (unsigned int)graph->head[e], label, NULL);
129  }
130 
131  /* write GML format closing */
132  SCIPgmlWriteClosing(file);
133 
134  return SCIP_OKAY;
135 }
136 #endif
137 
138 /** compute starting points for constructive heuristics */
139 static
141  GRAPH* graph, /**< graph data structure */
142  int* starts, /**< starting points array */
143  unsigned int* seed, /**< random seed */
144  int runs /**< number of runs */
145  )
146 {
147  int r;
148  int k;
149  int l;
150  int e;
151  int root;
152  int nnodes;
153  int nterms;
154  int randval;
155 
156  assert(graph != NULL);
157  assert(starts != NULL);
158 
159  root = graph->source[0];
160  nnodes = graph->knots;
161  nterms = graph->terms;
162 
163  r = 0;
164  if( graph->mark[root] )
165  starts[r++] = root;
166  randval = SCIPgetRandomInt(0, nnodes - 1, seed);
167 
168  /* use non-isolated terminals as starting points for TM heuristic */
169  for( k = 0; k < nnodes; k++ )
170  {
171  if( r >= runs || r >= nterms )
172  break;
173 
174  l = (k + randval) % nnodes;
175  if( Is_term(graph->term[l]) && graph->mark[l] && l != root )
176  starts[r++] = l;
177  }
178 
179  /* still empty slots in start array? */
180 
181  /* fill empty slots with terminal neighbours */
182  for( k = 0; k < r && r < runs; k++ )
183  {
184  for( e = graph->outbeg[starts[k]]; e != EAT_LAST && r < runs; e = graph->oeat[e] )
185  {
186  l = graph->head[e];
187  if( !Is_term(graph->term[l]) && graph->mark[l] )
188  starts[r++] = l;
189  }
190  }
191 
192  /* fill empty slots randomly */
193  for( k = 0; k < nnodes && r < runs; k++ )
194  {
195  l = (k + randval) % nnodes;
196  if( !Is_term(graph->term[l]) && graph->mark[l] )
197  starts[r++] = l;
198  }
199 }
200 
201 /** dual ascent based reductions */
202 SCIP_RETCODE da_reduce(
203  SCIP* scip, /**< SCIP data structure */
204  GRAPH* graph, /**< graph data structure */
205  PATH* vnoi, /**< Voronoi data structure */
206  GNODE** gnodearr, /**< GNODE* terminals array for internal computations or NULL */
207  SCIP_Real* cost, /**< edge costs */
208  SCIP_Real* costrev, /**< reverse edge costs */
209  SCIP_Real* pathdist, /**< distance array for shortest path calculations */
210  int* edgearrint, /**< int edges array for internal computations or NULL */
211  int* vbase, /**< array for Voronoi bases */
212  int* pathedge, /**< array for predecessor edge on a path */
213  int* state, /**< int 4 * nnodes array for internal computations */
214  int* heursources, /**< array to store starting points of TM heuristic */
215  char* nodearrchar, /**< char node array for internal computations or NULL */
216  int* nelims /**< pointer to store number of reduced edges */
217  )
218 {
219  SCIP_HEURDATA* tmheurdata;
220  IDX** ancestors;
221  IDX** revancestors;
222  SCIP_Real maxcost;
223  SCIP_Real lpobjval;
224  SCIP_Real upperbound;
225  SCIP_Real minpathcost;
226  SCIP_Bool rpc;
227  SCIP_Bool success;
228  SCIP_Real hopfactor;
229  SCIP_Real* sd;
230  SCIP_Real* ecost;
231  int* terms;
232  int* result;
233  int* starts;
234  int* adjvert;
235  int* incedge;
236  int* reinsert;
237  int* termdegs;
238  int i;
239  int k;
240  int e;
241  int run;
242  int etmp;
243  int runs;
244  int root;
245  int nruns;
246  int nterms;
247  int nedges;
248  int nnodes;
249  int nfixed;
250  int best_start;
251  unsigned int seed;
252  char* marked;
253 
254  assert(scip != NULL);
255  assert(graph != NULL);
256  assert(nelims != NULL);
257 
258  seed = 0;
259  root = graph->source[0];
260  rpc = (graph->stp_type == STP_ROOTED_PRIZE_COLLECTING);
261  nfixed = 0;
262  nedges = graph->edges;
263  nnodes = graph->knots;
264  maxcost = 0.0;
265  hopfactor = DEFAULT_HOPFACTOR;
266 
267  /* allocate memory */
268  SCIP_CALL( SCIPallocBufferArray(scip, &result, nedges) );
269  SCIP_CALL( SCIPallocBufferArray(scip, &marked, nedges) );
270 
271  if( !rpc )
272  {
273  SCIP_CALL( SCIPallocBufferArray(scip, &terms, graph->terms) );
274  SCIP_CALL( SCIPallocBufferArray(scip, &termdegs, graph->terms) );
275  }
276  else
277  {
278  terms = NULL;
279  termdegs = NULL;
280  }
281 
282  /* allocate length-4 buffer memory */
283  SCIP_CALL( SCIPallocBufferArray(scip, &sd, 4) );
284  SCIP_CALL( SCIPallocBufferArray(scip, &ancestors, 4) );
285  SCIP_CALL( SCIPallocBufferArray(scip, &revancestors, 4) );
286  SCIP_CALL( SCIPallocBufferArray(scip, &ecost, 4) );
287  SCIP_CALL( SCIPallocBufferArray(scip, &adjvert, 4) );
288  SCIP_CALL( SCIPallocBufferArray(scip, &reinsert, 4) );
289  SCIP_CALL( SCIPallocBufferArray(scip, &incedge, 4) );
290 
291  for( i = 0; i < 4; i++ )
292  {
293  sd[i] = 0.0;
294  ancestors[i] = NULL;
295  revancestors[i] = NULL;
296  }
297 
298  /* 1. step: compute upper bound */
299 
300  /* initialize */
301  k = 0;
302  nterms = 0;
303  for( i = 0; i < nnodes; i++ )
304  {
305  if( !rpc )
306  graph->mark[i] = (graph->grad[i] > 0);
307  if( graph->mark[i] )
308  {
309  k++;
310  if( Is_term(graph->term[i]) )
311  nterms++;
312  }
313  }
314 
315  /* not more than two terminals? */
316  if( nterms <= 2 )
317  goto TERMINATE;
318 
319  /* number of runs should not exceed number of connected vertices */
320  runs = MIN(k, DEFAULT_HEURRUNS);
321 
322  /* neither PC, MW, RPC nor HC? */
323  if( !rpc && heursources != NULL )
324  {
325  /* choose starting points for TM heuristic */
326  starts = heursources;
327  compTMstarts(graph, starts, &seed, runs);
328  }
329  else
330  {
331  starts = NULL;
332  }
333 
334  /* get TM heuristic data */
335  assert(SCIPfindHeur(scip, "TM") != NULL);
336  tmheurdata = SCIPheurGetData(SCIPfindHeur(scip, "TM"));
337 
338  for( e = 0; e < nedges; e++ )
339  {
340  cost[e] = graph->cost[e];
341  result[e] = UNKNOWN;
342  costrev[e] = graph->cost[flipedge(e)];
343 
344  if( graph->stp_type == STP_HOP_CONS && SCIPisLT(scip, graph->cost[e], BLOCKED) && SCIPisGT(scip, graph->cost[e], maxcost) )
345  maxcost = graph->cost[e];
346  }
347 
348  /* RPC? Then restore transformed graph */
349  if( rpc )
350  SCIP_CALL( pcgraphtrans(scip, graph) );
351 
352  SCIP_CALL( SCIPheurComputeSteinerTree(scip, tmheurdata, graph, starts, &best_start, result, runs, root, cost, costrev, &hopfactor, NULL, maxcost, &success) );
353 
354  /* RPC? Then restore original graph */
355  if( rpc )
356  {
357  SCIP_CALL( extendSteinerTreePcMw(scip, graph, vnoi, costrev, vbase, result, nodearrchar, &e) );
358  SCIP_CALL( pcgraphorg(scip, graph) );
359  }
360 
361  /* no feasible solution found? */
362  if( !success )
363  goto TERMINATE;
364 
365  /* calculate objective value of solution */
366  upperbound = 0.0;
367  for( e = 0; e < nedges; e++ )
368  if( result[e] == CONNECT )
369  upperbound += graph->cost[e];
370 
371  /* 2. step: repeatedly compute lower bound and reduced costs and try to eliminate */
372  for( i = 0; i < nnodes; i++ )
373  if( Is_term(graph->term[i]) )
374  assert(graph->grad[i] > 0);
375 
376  /* if not RPC, select roots for dual ascent */
377  if( !rpc )
378  {
379  assert(terms != NULL);
380  assert(termdegs != NULL);
381  k = 0;
382  for( i = 0; i < nnodes; i++ )
383  {
384  if( Is_term(graph->term[i]) && (graph->grad[i] > 0) )
385  {
386  termdegs[k] = graph->grad[i];
387  terms[k++] = i;
388  }
389  }
390  nruns = MIN(nterms, DEFAULT_DARUNS);
391  SCIPsortIntInt(termdegs, terms, nterms);
392  }
393  else
394  {
395  nruns = 1;
396  SCIP_CALL( pcgraphtrans(scip, graph) );
397  }
398 
399  if( graph->stp_type == STP_HOP_CONS )
400  nruns = 1;
401 
402  for( run = 0; run < nruns; run++ )
403  {
404  /* graph vanished? */
405  if( graph->grad[graph->source[0]] == 0 )
406  break;
407 
408  if( !rpc && graph->stp_type != STP_HOP_CONS )
409  {
410  assert(terms != NULL);
411  root = terms[nterms - run - 1];
412  }
413 
414  SCIP_CALL( SCIPdualAscentStp(scip, graph, cost, &lpobjval, FALSE, gnodearr, edgearrint, state, root, 1, NULL, nodearrchar) );
415 
416  /* the required reduced path cost to be surpassed */
417  minpathcost = upperbound - lpobjval;
418  SCIPdebugMessage("da: upperbound %f, lpobjval %f\n", upperbound, lpobjval);
419 
420  for( e = 0; e < nedges; e++ )
421  {
422  marked[e] = FALSE;
423  costrev[e] = cost[flipedge(e)];
424  }
425 
426  for( k = 0; k < nnodes; k++ )
427  graph->mark[k] = (graph->grad[k] > 0);
428 
429  /* distance from root to all nodes */
430  graph_path_execX(scip, graph, root, cost, pathdist, pathedge);
431 
432  /* no paths should go back to the root */
433  for( e = graph->outbeg[root]; e != EAT_LAST; e = graph->oeat[e] )
434  costrev[e] = FARAWAY;
435 
436  /* build voronoi diagram */
437  getnext4terms(scip, graph, costrev, costrev, vnoi, vbase, graph->path_heap, state);
438 
439  for( k = 0; k < nnodes; k++ )
440  if( !Is_term(graph->term[k]) )
441  assert(vbase[k + nnodes] != root );
442 
443  /* RPC? If yes, restore original graph */
444  if( rpc )
445  {
446  SCIP_CALL( pcgraphorg(scip, graph) );
447  graph->mark[root] = FALSE;
448  }
449 
450  for( k = 0; k < nnodes; k++ )
451  {
452  if( !graph->mark[k] )
453  continue;
454 
455  if( !Is_term(graph->term[k]) && SCIPisGT(scip, pathdist[k] + vnoi[k].dist, minpathcost) )
456  {
457  while( graph->outbeg[k] != EAT_LAST )
458  {
459  graph_edge_del(scip, graph, graph->outbeg[k], TRUE);
460  nfixed++;
461  }
462  }
463  else
464  {
465  e = graph->outbeg[k];
466  while( e != EAT_LAST )
467  {
468  etmp = graph->oeat[e];
469 
470  /* for rpc not artificial terminal arcs should be deleted */
471  if( rpc && !graph->mark[graph->head[e]] )
472  {
473  e = etmp;
474  continue;
475  }
476 
477  if( SCIPisGT(scip, pathdist[k] + cost[e] + vnoi[graph->head[e]].dist, minpathcost) )
478  {
479  if( marked[flipedge(e)] )
480  {
481  graph_edge_del(scip, graph, e, TRUE);
482  nfixed++;
483  }
484  else
485  {
486  marked[e] = TRUE;
487  }
488  }
489  e = etmp;
490  }
491  }
492  }
493 
494  for( k = 0; k < nnodes; k++ )
495  {
496  if( !graph->mark[k] || Is_term(graph->term[k]) )
497  continue;
498  if( graph->grad[k] == 3 )
499  {
500 
501  if( SCIPisGT(scip,pathdist[k] + vnoi[k].dist + vnoi[k + nnodes].dist, minpathcost) )
502  {
503  int i2;
504 
505  SCIPdebugMessage("DA eliminates 3-Vertex: %d %f min: %f \n", k, pathdist[k] + vnoi[k].dist + vnoi[k + nnodes].dist, minpathcost);
506  nfixed++;
507  i = 0;
508 
509  for( e = graph->outbeg[k]; e != EAT_LAST; e = graph->oeat[e] )
510  {
511  incedge[i] = e;
512  ecost[i] = graph->cost[e];
513  adjvert[i++] = graph->head[e];
514  assert(i <= 4);
515  }
516 
517  /* save ancestors */
518  for( i = 0; i < 3; i++ )
519  {
520  SCIPintListNodeFree(scip, &(ancestors[i]));
521  SCIPintListNodeFree(scip, &(revancestors[i]));
522  SCIP_CALL( SCIPintListNodeAppendCopy(scip, &(ancestors[i]), graph->ancestors[incedge[i]]) );
523  SCIP_CALL( SCIPintListNodeAppendCopy(scip, &(revancestors[i]), graph->ancestors[Edge_anti(incedge[i])]) );
524  }
525 
526  for( i = 0; i < 3; i++ )
527  {
528  i2 = (i + 1) % 3;
529  SCIP_CALL( graph_edge_reinsert(scip, graph, incedge[i], adjvert[i], adjvert[i2], ecost[i] + ecost[i2], ancestors[i], ancestors[i2], revancestors[i], revancestors[i2]) );
530  }
531  }
532  }
533  /* @todo */
534  if( graph->grad[k] == 4 )
535  {
536 
537  if( SCIPisGT(scip,pathdist[k] + vnoi[k].dist + vnoi[k + nnodes].dist + vnoi[k + 2 * nnodes].dist, minpathcost) )
538  {
539  SCIPdebugMessage("DA could eliminate 4-Vertex: %d %f min: %f \n", k, pathdist[k] + vnoi[k].dist + vnoi[k + nnodes].dist, minpathcost);
540  }
541  }
542  }
543  SCIPdebugMessage("deleted by da: %d \n", nfixed );
544 
545  if( rpc )
546  graph->mark[root] = TRUE;
547 
548  } /* root loop */
549 
550  TERMINATE:
551  *nelims = nfixed;
552 
553  /* free memory */
554  for( k = 0; k < 4; k++ )
555  {
556  SCIPintListNodeFree(scip, &(ancestors[k]));
557  SCIPintListNodeFree(scip, &(revancestors[k]));
558  }
559 
560  SCIPfreeBufferArray(scip, &incedge);
561  SCIPfreeBufferArray(scip, &reinsert);
562  SCIPfreeBufferArray(scip, &adjvert);
563  SCIPfreeBufferArray(scip, &ecost);
564  SCIPfreeBufferArray(scip, &revancestors);
565  SCIPfreeBufferArray(scip, &ancestors);
566  SCIPfreeBufferArray(scip, &sd);
567  SCIPfreeBufferArrayNull(scip, &termdegs);
568  SCIPfreeBufferArrayNull(scip, &terms);
569  SCIPfreeBufferArray(scip, &marked);
570  SCIPfreeBufferArray(scip, &result);
571 
572  return SCIP_OKAY;
573 }
574 
575 
576 /** dual ascent based reductions for PCSPG and MWCSP */
577 SCIP_RETCODE daPc_reduce(
578  SCIP* scip, /**< SCIP data structure */
579  GRAPH* graph, /**< graph data structure */
580  PATH* vnoi, /**< Voronoi data structure array */
581  GNODE** gnodearr, /**< GNODE* terminals array for internal computations or NULL */
582  SCIP_Real* cost, /**< edge costs */
583  SCIP_Real* costrev, /**< reverse edge costs */
584  SCIP_Real* pathdist, /**< distance array for shortest path calculations */
585  int* vbase, /**< Voronoi base array */
586  int* pathedge, /**< shorest path incoming edge array for shortest path calculations */
587  int* edgearrint, /**< int edges array for internal computations or NULL */
588  int* state, /**< int 4 * vertices array */
589  char* nodearrchar, /**< char node array for internal computations */
590  int* nelims /**< pointer to store number of reduced edges */
591  )
592 {
593  SCIP_HEURDATA* tmheurdata;
594  IDX** ancestors;
595  IDX** revancestors;
596  GRAPH* transgraph;
597  SCIP_Real* sd;
598  SCIP_Real* ecost;
599  SCIP_Real lpobjval;
600  SCIP_Real upperbound;
601  SCIP_Real minpathcost;
602  SCIP_Bool success;
603  SCIP_Real offset;
604  SCIP_Real hopfactor;
605  int* result;
606  int* adjvert;
607  int* incedge;
608  int* reinsert;
609  int i;
610  int k;
611  int e;
612  int run;
613  int etmp;
614  int runs;
615  int root;
616  int nruns;
617  int nterms;
618  int nedges;
619  int nnodes;
620  int nfixed;
621  int best_start;
622  int transnnodes;
623  int transnedges;
624  char* marked;
625 
626  assert(scip != NULL);
627  assert(graph != NULL);
628  assert(nelims != NULL);
629  assert(nodearrchar != NULL);
630 
631  root = graph->source[0];
632  nfixed = 0;
633  nnodes = graph->knots;
634  nedges = graph->edges;
635  hopfactor = DEFAULT_HOPFACTOR;
636  upperbound = 0.0;
637 
638  /* allocate memory */
639  if( edgearrint == NULL )
640  {
641  SCIP_CALL( SCIPallocBufferArray(scip, &result, nedges) );
642  }
643  else
644  {
645  result = edgearrint;
646  }
647  SCIP_CALL( SCIPallocBufferArray(scip, &marked, nedges + 2 * (graph->terms - 1)) );
648 
649  /* allocate length-4 buffer memory */
650  SCIP_CALL( SCIPallocBufferArray(scip, &sd, 4) );
651  SCIP_CALL( SCIPallocBufferArray(scip, &ancestors, 4) );
652  SCIP_CALL( SCIPallocBufferArray(scip, &revancestors, 4) );
653  SCIP_CALL( SCIPallocBufferArray(scip, &ecost, 4) );
654  SCIP_CALL( SCIPallocBufferArray(scip, &adjvert, 4) );
655  SCIP_CALL( SCIPallocBufferArray(scip, &reinsert, 4) );
656  SCIP_CALL( SCIPallocBufferArray(scip, &incedge, 4) );
657 
658  for( i = 0; i < 4; i++ )
659  {
660  sd[i] = 0.0;
661  ancestors[i] = NULL;
662  revancestors[i] = NULL;
663  }
664 
665  /* 1. step: compute upper bound */
666 
667  /* initialize */
668  k = 0;
669  nterms = 0;
670  for( i = 0; i < nnodes; i++ )
671  {
672  if( graph->mark[i] )
673  {
674  k++;
675  if( Is_term(graph->term[i]) )
676  nterms++;
677  }
678  }
679 
680  /* not more than two terminals? */
681  if( nterms <= 2 )
682  goto TERMINATE;
683 
684  /* number of runs should not exceed number of connected vertices */
685  runs = MIN(k, DEFAULT_HEURRUNS);
686 
687  /* get TM heuristic data */
688  assert(SCIPfindHeur(scip, "TM") != NULL);
689  tmheurdata = SCIPheurGetData(SCIPfindHeur(scip, "TM"));
690 
691  for( e = 0; e < nedges; e++ )
692  {
693  result[e] = UNKNOWN;
694  cost[e] = graph->cost[e];
695  costrev[e] = graph->cost[flipedge(e)];
696  }
697 
698  /* restore transformed graph */
699  SCIP_CALL( pcgraphtrans(scip, graph) );
700 
701  /* compute Steiner tree to obtain upper bound */
702  SCIP_CALL( SCIPheurComputeSteinerTree(scip, tmheurdata, graph, NULL, &best_start, result, runs, root, cost, costrev, &hopfactor, NULL, 0.0, &success) );
703 
704  SCIP_CALL( extendSteinerTreePcMw(scip, graph, vnoi, costrev, vbase, result, nodearrchar, &e) );
705 
706  /* restore oringinal graph */
707  SCIP_CALL( pcgraphorg(scip, graph) );
708 
709  /* no feasible solution found? */
710  if( !success )
711  goto TERMINATE;
712 
713  /* calculate objective value of solution */
714  for( e = 0; e < nedges; e++ )
715  if( result[e] == CONNECT )
716  upperbound += graph->cost[e];
717 
718  /* 2. step: compute lower bound and reduced costs and try to eliminate */
719 
720  SCIP_CALL( pcgraphtrans(scip, graph) );
721 
722  /* @todo: vary */
723  nruns = 1;
724 
725  for( run = 0; run < nruns; run++ )
726  {
727  offset = 0.0;
728  SCIP_CALL( graph_PcSapCopy(scip, graph, &transgraph, &offset) );
729  transnnodes = transgraph->knots;
730  transnedges = transgraph->edges;
731 
732  SCIP_CALL( SCIPdualAscentStp(scip, transgraph, cost, &lpobjval, FALSE, gnodearr, edgearrint, state, root, 1, marked, nodearrchar) );
733 
734  lpobjval += offset;
735 
736  /* the required reduced path cost to be surpassed */
737  minpathcost = upperbound - lpobjval;
738  SCIPdebugMessage("xupperbound %f, lpobjval %f\n", upperbound, lpobjval);
739 
740  for( e = 0; e < transnedges; e++ )
741  {
742  costrev[e] = cost[flipedge(e)];
743  marked[e] = FALSE;
744  }
745 
746  for( k = 0; k < transnnodes; k++ )
747  transgraph->mark[k] = (transgraph->grad[k] > 0);
748 
749  /* init data structures for shortest paths and history */
750  SCIP_CALL( graph_path_init(scip, transgraph) );
751  SCIP_CALL( graph_init_history(scip, transgraph ) );
752 
753  /* distance from root to all nodes */
754  graph_path_execX(scip, transgraph, root, cost, pathdist, pathedge);
755 
756  for( i = 0; i < transnnodes; i++ )
757  if( Is_term(transgraph->term[i]) )
758  assert(SCIPisEQ(scip, pathdist[i], 0.0));
759 
760  /* no paths should go back to the root */
761  for( e = transgraph->outbeg[root]; e != EAT_LAST; e = transgraph->oeat[e] )
762  costrev[e] = FARAWAY;
763 
764  /* build voronoi diagram */
765  voronoi_terms(scip, transgraph, costrev, vnoi, vbase, transgraph->path_heap, transgraph->path_state);
766 
767  /* restore original transgraph */
768  SCIP_CALL( pcgraphorg(scip, graph) );
769 
770  /* try to eliminate vertices and edges */
771  for( k = 0; k < nnodes; k++ )
772  {
773  if( !graph->mark[k] || Is_gterm(graph->term[k]) )
774  continue;
775 
776  if( SCIPisGT(scip, pathdist[k] + vnoi[k].dist, minpathcost) )
777  {
778  while( transgraph->outbeg[k] != EAT_LAST )
779  {
780  e = transgraph->outbeg[k];
781  graph_edge_del(scip, transgraph, e, FALSE);
782  graph_edge_del(scip, graph, e, TRUE);
783  nfixed++;
784  }
785  assert(graph->outbeg[k] == EAT_LAST);
786  }
787  else
788  {
789  e = transgraph->outbeg[k];
790  while( e != EAT_LAST )
791  {
792  etmp = transgraph->oeat[e];
793 
794  if( SCIPisGT(scip, pathdist[k] + cost[e] + vnoi[transgraph->head[e]].dist, minpathcost) )
795  {
796  if( marked[flipedge(e)] )
797  {
798  graph_edge_del(scip, graph, e, TRUE);
799  graph_edge_del(scip, transgraph, e, FALSE);
800  nfixed++;
801  }
802  else
803  {
804  marked[e] = TRUE;
805  }
806  }
807  e = etmp;
808  }
809  }
810  }
811 
812  SCIPdebugMessage("fixed by da: %d \n", nfixed );
813 
814  graph_path_exit(scip, transgraph);
815  graph_free(scip, transgraph, TRUE);
816  } /* root loop */
817 
818  TERMINATE:
819  *nelims = nfixed;
820 
821  /* free memory */
822  for( k = 0; k < 4; k++ )
823  {
824  SCIPintListNodeFree(scip, &(ancestors[k]));
825  SCIPintListNodeFree(scip, &(revancestors[k]));
826  }
827 
828  SCIPfreeBufferArray(scip, &incedge);
829  SCIPfreeBufferArray(scip, &reinsert);
830  SCIPfreeBufferArray(scip, &adjvert);
831  SCIPfreeBufferArray(scip, &ecost);
832  SCIPfreeBufferArray(scip, &revancestors);
833  SCIPfreeBufferArray(scip, &ancestors);
834  SCIPfreeBufferArray(scip, &sd);
835  SCIPfreeBufferArray(scip, &marked);
836 
837  if( edgearrint == NULL )
838  SCIPfreeBufferArray(scip, &result);
839 
840  return SCIP_OKAY;
841 }
842 
843 
844 /** bound-based reductions for the (R)PCSTP, the MWCSP and the STP */
845 SCIP_RETCODE bound_reduce(
846  SCIP* scip,
847  GRAPH* graph,
848  PATH* vnoi,
849  SCIP_Real* cost,
850  SCIP_Real* prize,
851  SCIP_Real* radius,
852  SCIP_Real* costrev,
853  SCIP_Real* offset,
854  SCIP_Real* upperbound,
855  int* heap,
856  int* state,
857  int* vbase,
858  int* nelims
859  )
860 {
861  SCIP_HEURDATA* tmheurdata;
862  GRAPH* adjgraph;
863  PATH* mst;
864  SCIP_Real r;
865  SCIP_Real obj;
866  SCIP_Real max;
867  SCIP_Real radii;
868  SCIP_Real bound;
869  SCIP_Real tmpcost;
870  SCIP_Real mstobj;
871  SCIP_Real mstobj2;
872  SCIP_Real maxcost;
873  SCIP_Real radiim2;
874 #if 1
875  SCIP_Real* cost3;
876  SCIP_Real radiim3;
877  IDX** ancestors;
878  IDX** revancestors;
879  int* edges3;
880  int* nodes3;
881 #endif
882  int* perm;
883  int* result;
884  int* starts;
885  int e;
886  int k;
887  int l;
888  int head;
889  int tail;
890  int runs;
891  int root;
892  int etemp;
893  int nterms;
894  int nnodes;
895  int nedges;
896  int best_start;
897  unsigned int seed;
898  char* stnode;
899  SCIP_Bool ub;
900  SCIP_Bool pc;
901  SCIP_Bool mw;
902  SCIP_Bool pcmw;
903  SCIP_Bool success;
904 
905  assert(scip != NULL);
906  assert(graph != NULL);
907  assert(vnoi != NULL);
908  assert(cost != NULL);
909  assert(radius != NULL);
910  assert(costrev != NULL);
911  assert(heap != NULL);
912  assert(state != NULL);
913  assert(vbase != NULL);
914  assert(nelims != NULL);
915  assert(graph->source[0] >= 0);
916  assert(upperbound != NULL);
917 
918  mst = NULL;
919  obj = DEFAULT_HOPFACTOR;
920  seed = 0;
921  perm = NULL;
922  root = graph->source[0];
923  nedges = graph->edges;
924  nnodes = graph->knots;
925  mstobj = 0.0;
926  *nelims = 0;
927  mstobj2 = 0.0;
928  best_start = 0;
929  ub = SCIPisGT(scip, *upperbound, 0.0);
930  mw = (graph->stp_type == STP_MAX_NODE_WEIGHT);
931  pc = (graph->stp_type == STP_ROOTED_PRIZE_COLLECTING) || (graph->stp_type == STP_PRIZE_COLLECTING);
932  pcmw = pc || mw;
933  success = TRUE;
934 #if 1
935  cost3 = NULL;
936  edges3 = NULL;
937  nodes3 = NULL;
938  ancestors = NULL;
939  revancestors = NULL;
940 #endif
941 
942  /* no upper bound provided? */
943  if( !ub )
944  {
945  /* allocate memory */
946  SCIP_CALL( SCIPallocBufferArray(scip, &result, nedges) );
947  SCIP_CALL( SCIPallocBufferArray(scip, &stnode, nnodes) );
948  }
949  else
950  {
951  result = NULL;
952  stnode = NULL;
953  }
954 
955  /* initialize */
956  e = 0;
957  nterms = 0;
958  for( k = 0; k < nnodes; k++ )
959  {
960  if( !ub )
961  {
962  assert(stnode != NULL);
963  stnode[k] = FALSE;
964  }
965  if( !pcmw )
966  graph->mark[k] = (graph->grad[k] > 0);
967  if( graph->mark[k] )
968  {
969  e++;
970  if( Is_term(graph->term[k]) )
971  nterms++;
972  }
973  }
974 
975  /* not more than two terminals? */
976  if( nterms <= 2 )
977  {
978  /* free memory and return */
979  SCIPfreeBufferArrayNull(scip, &stnode);
980  SCIPfreeBufferArrayNull(scip, &result);
981  return SCIP_OKAY;
982  }
983 
984  assert(nterms == (graph->terms - ((graph->stp_type == STP_PRIZE_COLLECTING || mw)? 1 : 0)));
985 
986  runs = MIN(e, 100);
987 
988  /* neither PC, MW, RPC nor HC? */
989  if( !pcmw && graph->stp_type != STP_HOP_CONS )
990  {
991  /* choose starting points for TM heuristic */
992 
993  SCIP_CALL( SCIPallocBufferArray(scip, &starts, nnodes) );
994 
995  compTMstarts(graph, starts, &seed, runs);
996 #if 0
997  int randval;
998 
999  r = 0;
1000  if( graph->mark[root] )
1001  starts[r++] = root;
1002  randval = SCIPgetRandomInt(0, nnodes - 1, &seed);
1003 
1004  /* use non-isolated terminals as starting points for TM heuristic */
1005  for( k = 0; k < nnodes; k++ )
1006  {
1007  if( r >= runs || r >= nterms )
1008  break;
1009 
1010  l = (k + randval) % nnodes;
1011  if( Is_term(graph->term[l]) && graph->mark[l] && l != root )
1012  starts[r++] = l;
1013  }
1014 
1015  /* still empty slots in start array? */
1016 
1017  /* fill empty slots with terminal neighbours */
1018  for( k = 0; k < r && r < runs; k++ )
1019  {
1020  for( e = graph->outbeg[starts[k]]; e != EAT_LAST && r < runs; e = graph->oeat[e] )
1021  {
1022  l = graph->head[e];
1023  if( !Is_term(graph->term[l]) && graph->mark[l] )
1024  starts[r++] = l;
1025  }
1026  }
1027 
1028  /* fill empty slots randomly */
1029  for( k = 0; k < nnodes && r < runs; k++ )
1030  {
1031  l = (k + randval) % nnodes;
1032  if( !Is_term(graph->term[l]) && graph->mark[l] )
1033  starts[r++] = l;
1034  }
1035 #endif
1036  }
1037  else
1038  {
1039  starts = NULL;
1040  }
1041 
1042  /* initialise cost and costrev array */
1043  maxcost = 0.0;
1044  for( e = 0; e < nedges; e++ )
1045  {
1046  if( !ub )
1047  {
1048  assert(result != NULL);
1049  result[e] = UNKNOWN;
1050  }
1051  cost[e] = graph->cost[e];
1052  costrev[e] = graph->cost[flipedge(e)];
1053 
1054  assert(SCIPisGE(scip, cost[e], 0.0));
1055 
1056  if( graph->stp_type == STP_HOP_CONS && SCIPisLT(scip, graph->cost[e], BLOCKED) && SCIPisGT(scip, graph->cost[e], maxcost) )
1057  maxcost = graph->cost[e];
1058  }
1059 
1060  /* init auxiliary graph */
1061  if( !mw )
1062  {
1063  SCIP_CALL( graph_init(scip, &adjgraph, nterms, MIN(nedges, (nterms - 1) * nterms), 1, 0) );
1064  }
1065  else
1066  {
1067  adjgraph = NULL;
1068  }
1069 
1070  /* build voronoi regions, concomitantly building adjgraph and computing radii values*/
1071  SCIP_CALL( voronoi_radius(scip, graph, adjgraph, vnoi, radius, cost, costrev, vbase, heap, state) );
1072 
1073  /* get 2nd next terminals to all non-terminal nodes */
1074  get2next(scip, graph, cost, costrev, vnoi, vbase, heap, state);
1075 
1076  /* get 3th next terminals to all non-terminal nodes */
1077  get3next(scip, graph, cost, costrev, vnoi, vbase, heap, state);
1078 
1079  /* for (rooted) prize collecting get 4th next terminals to all non-terminal nodes */
1080  if( pc )
1081  get4next(scip, graph, cost, costrev, vnoi, vbase, heap, state);
1082 
1083  /* no MWCS problem? */
1084  if( !mw )
1085  {
1086  assert(adjgraph != NULL);
1087  graph_knot_chg(adjgraph, 0, 0);
1088  adjgraph->source[0] = 0;
1089 
1090  /* compute MST on adjgraph */
1091  SCIP_CALL( SCIPallocBufferArray(scip, &mst, nterms) );
1092  SCIP_CALL( graph_path_init(scip, adjgraph) );
1093  graph_path_exec(scip, adjgraph, MST_MODE, 0, adjgraph->cost, mst);
1094 
1095  max = -1.0;
1096  r = -1.0;
1097  for( k = 1; k < nterms; k++ )
1098  {
1099  assert(adjgraph->path_state[k] == CONNECT);
1100  e = mst[k].edge;
1101  assert(e >= 0);
1102  tmpcost = adjgraph->cost[e];
1103  mstobj += tmpcost;
1104  if( SCIPisGT(scip, tmpcost, max) )
1105  max = tmpcost;
1106  else if( SCIPisGT(scip, tmpcost, r) )
1107  r = tmpcost;
1108  }
1109  mstobj -= max;
1110  mstobj2 = mstobj - r;
1111  }
1112 
1113  /* for (rooted) prize collecting an maximum weight problems: correct radius values */
1114  if( graph->stp_type == STP_ROOTED_PRIZE_COLLECTING )
1115  {
1116  assert(graph->mark[graph->source[0]]);
1117  for( k = 0; k < nnodes; k++ )
1118  {
1119  if( !Is_term(graph->term[k]) || !graph->mark[k] )
1120  continue;
1121 
1122  if( SCIPisGT(scip, radius[k], prize[k]) && k != graph->source[0] )
1123  radius[k] = prize[k];
1124  }
1125  }
1126  else if( graph->stp_type == STP_PRIZE_COLLECTING )
1127  {
1128  for( k = 0; k < nnodes; k++ )
1129  {
1130  if( !graph->mark[k] )
1131  continue;
1132 
1133  if( Is_term(graph->term[k]) && SCIPisGT(scip, radius[k], prize[k]) )
1134  radius[k] = prize[k];
1135  }
1136  }
1137  else if( graph->stp_type == STP_MAX_NODE_WEIGHT )
1138  {
1139  max = 0.0;
1140  for( k = 0; k < nnodes; k++ )
1141  {
1142  if( !Is_term(graph->term[k]) || !graph->mark[k] )
1143  continue;
1144 
1145  assert(SCIPisGE(scip, prize[k], 0.0));
1146  if( SCIPisGT(scip, prize[k], max) )
1147  max = prize[k];
1148 
1149  if( SCIPisGE(scip, radius[k], 0.0 ) )
1150  radius[k] = 0.0;
1151  else
1152  radius[k] = -radius[k];
1153  }
1154  }
1155 
1156  /* sort radius values */
1157  if( pc )
1158  {
1159  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nnodes) );
1160  for( k = 0; k < nnodes; k++ )
1161  perm[k] = k;
1162  SCIPsortRealInt(radius, perm, nnodes);
1163  }
1164  else
1165  {
1166  SCIPsortReal(radius, nnodes);
1167  }
1168 
1169  radiim2 = 0.0;
1170 
1171  /* sum all but two radius values of highest/lowest value */
1172  if( mw )
1173  {
1174  for( k = 2; k < nterms; k++ )
1175  {
1176  assert( SCIPisGT(scip, FARAWAY, radius[k]) );
1177  radiim2 += radius[k];
1178  }
1179  }
1180  else
1181  {
1182  for( k = 0; k < nterms - 2; k++ )
1183  {
1184  assert( SCIPisGT(scip, FARAWAY, radius[k]) );
1185  radiim2 += radius[k];
1186  }
1187  }
1188  radii = radiim2 + radius[nterms - 2] + radius[nterms - 1];
1189 #if 1
1190  if( nterms >= 3 )
1191  radiim3 = radiim2 - radius[nterms - 3];
1192  else
1193  radiim3 = 0;
1194 #endif
1195  /* get TM heuristic data */
1196  assert(SCIPfindHeur(scip, "TM") != NULL);
1197  tmheurdata = SCIPheurGetData(SCIPfindHeur(scip, "TM"));
1198 
1199  /* no upper bound available? */
1200  if( !ub )
1201  {
1202  assert(stnode != NULL);
1203  assert(result != NULL);
1204 
1205  /* PC or RPC? Then restore transformed graph */
1206  if( pcmw )
1207  SCIP_CALL( pcgraphtrans(scip, graph) );
1208 
1209  SCIP_CALL( SCIPheurComputeSteinerTree(scip, tmheurdata, graph, starts, &best_start, result, runs, root, cost, costrev, &obj, NULL, maxcost, &success) );
1210 
1211  /* PC or RPC? Then restore oringinal graph */
1212  if( pcmw )
1213  SCIP_CALL( pcgraphorg(scip, graph) );
1214 
1215  /* no feasible solution found? */
1216  if( !success )
1217  {
1218  /* free memory and return */
1219  if( !mw )
1220  {
1221  graph_path_exit(scip, adjgraph);
1222  graph_free(scip, adjgraph, TRUE);
1223  }
1224  SCIPfreeBufferArrayNull(scip, &mst);
1225  SCIPfreeBufferArrayNull(scip, &starts);
1226  SCIPfreeBufferArray(scip, &result);
1227  SCIPfreeBufferArray(scip, &stnode);
1228  return SCIP_OKAY;
1229  }
1230 
1231  /* calculate objective value of solution */
1232  obj = 0.0;
1233  for( e = 0; e < nedges; e++ )
1234  {
1235  if( result[e] == CONNECT )
1236  {
1237  head = graph->head[e];
1238  if( mw )
1239  {
1240  if( graph->mark[head] )
1241  {
1242  assert(stnode[head] == FALSE);
1243  obj += prize[head];
1244  }
1245  }
1246  else
1247  {
1248  obj += graph->cost[e];
1249  stnode[head] = TRUE;
1250  stnode[graph->tail[e]] = TRUE;
1251  }
1252  }
1253  }
1254  *upperbound = obj + *offset;
1255  }
1256  else
1257  {
1258  obj = *upperbound - *offset;
1259  assert(SCIPisGE(scip, obj, 0.0));
1260  }
1261 #if 0
1262  printf("radiim2: %f \n", radiim2);
1263  printf("mstobj: %f \n", mstobj);
1264  printf("totalobj: %f \n", obj);
1265 #endif
1266  if( SCIPisGT(scip, radiim2, mstobj) )
1267  bound = radiim2;
1268  else
1269  bound = mstobj;
1270 
1271  /* traverse all node, try to eliminate each node or incident edges */
1272  for( k = 0; k < nnodes; k++ )
1273  {
1274  if( (!graph->mark[k] && (pcmw)) || graph->grad[k] == 0 )
1275  continue;
1276 
1277  if( mw )
1278  {
1279  tmpcost = -vnoi[k].dist - vnoi[k + nnodes].dist + bound - graph->prize[k];
1280 
1281  if( !Is_term(graph->term[k]) && (SCIPisLT(scip, tmpcost, obj)) )
1282  {
1283  while( graph->outbeg[k] != EAT_LAST )
1284  {
1285  (*nelims)++;
1286  graph_edge_del(scip, graph, graph->outbeg[k], TRUE);
1287  }
1288  }
1289  else
1290  {
1291  e = graph->outbeg[k];
1292  while( e != EAT_LAST )
1293  {
1294  etemp = graph->oeat[e];
1295  tail = graph->tail[e];
1296  head = graph->head[e];
1297  if( !graph->mark[head] )
1298  {
1299  e = etemp;
1300  continue;
1301  }
1302  tmpcost = bound - graph->prize[k];
1303  if( vbase[tail] != vbase[head] )
1304  {
1305  tmpcost -= vnoi[head].dist + vnoi[tail].dist;
1306  }
1307  else
1308  {
1309  if( SCIPisGT(scip, vnoi[tail].dist + vnoi[head + nnodes].dist, vnoi[tail + nnodes].dist + vnoi[head].dist) )
1310  tmpcost -= vnoi[tail + nnodes].dist + vnoi[head].dist;
1311  else
1312  tmpcost -= vnoi[tail].dist + vnoi[head + nnodes].dist;
1313  }
1314  if( (SCIPisLT(scip, tmpcost, obj)) )
1315  {
1316  (*nelims)++;
1317  graph_edge_del(scip, graph, e, TRUE);
1318  }
1319  e = etemp;
1320  }
1321  }
1322  continue;
1323  }
1324 
1325  tmpcost = vnoi[k].dist + vnoi[k + nnodes].dist + bound;
1326 
1327  /* can node k be deleted? */
1328  if( !Is_term(graph->term[k]) && (SCIPisGT(scip, tmpcost, obj)
1329  || (((stnode != NULL) ? !stnode[k] : 0) && SCIPisGE(scip, tmpcost, obj))) )
1330  {
1331  SCIPdebugMessage("delete vertex: %d of degree: %d\n", k, graph->grad[k]);
1332  /* delete all incident edges */
1333  while( graph->outbeg[k] != EAT_LAST )
1334  {
1335  e = graph->outbeg[k];
1336  (*nelims)++;
1337  assert(!pc || graph->tail[e] != root);
1338  assert(!pc || graph->mark[graph->head[e]]);
1339  assert(!Is_pterm(graph->term[graph->head[e]]));
1340  assert(!Is_pterm(graph->term[graph->tail[e]]));
1341 
1342  graph_edge_del(scip, graph, e, TRUE);
1343  }
1344  }
1345  else
1346  {
1347  e = graph->outbeg[k];
1348  while( e != EAT_LAST )
1349  {
1350  etemp = graph->oeat[e];
1351  tail = graph->tail[e];
1352  head = graph->head[e];
1353  tmpcost = graph->cost[e] + bound;
1354 
1355  if( vbase[tail] != vbase[head] )
1356  {
1357  tmpcost += vnoi[head].dist + vnoi[tail].dist;
1358  }
1359  else
1360  {
1361  if( SCIPisGT(scip, vnoi[tail].dist + vnoi[head + nnodes].dist, vnoi[tail + nnodes].dist + vnoi[head].dist) )
1362  tmpcost += vnoi[tail + nnodes].dist + vnoi[head].dist;
1363  else
1364  tmpcost += vnoi[tail].dist + vnoi[head + nnodes].dist;
1365  assert(SCIPisGE(scip, tmpcost, vnoi[head].dist + vnoi[tail].dist + graph->cost[e] + bound));
1366  }
1367  /* can edge e or arc e be deleted? */
1368  if( (SCIPisGT(scip, tmpcost, obj) || (((result != NULL) ? (result[e] != CONNECT) : 0) && result[flipedge(e)] != CONNECT && SCIPisGE(scip, tmpcost, obj)))
1369  && SCIPisLT(scip, graph->cost[e], FARAWAY) && (!(pc || mw) || graph->mark[head]) )
1370  {
1371  SCIPdebugMessage("delete edge: %d->%d \n", graph->tail[e], graph->head[e]);
1372  if( graph->stp_type == STP_HOP_CONS && SCIPisGT(scip, graph->cost[e], graph->cost[flipedge(e)]) )
1373  {
1374  graph->cost[e] = FARAWAY;
1375  (*nelims)++;
1376  }
1377  else
1378  {
1379  assert(!Is_pterm(graph->term[head]));
1380  assert(!Is_pterm(graph->term[tail]));
1381  graph_edge_del(scip, graph, e, TRUE);
1382  (*nelims)++;
1383  }
1384  }
1385  e = etemp;
1386  }
1387  }
1388  }
1389 #if 1
1390  /* traverse all node, try to eliminate 3 degree nodes */
1391  if( !mw )
1392  {
1393  for( k = 0; k < nnodes; k++ )
1394  {
1395  if( (!graph->mark[k] && pc) || graph->grad[k] == 0 )
1396  continue;
1397 
1398  if( graph->grad[k] == 3 && !Is_term(graph->term[k]) )
1399  {
1400  tmpcost = vnoi[k].dist + vnoi[k + nnodes].dist + vnoi[k + 2 * nnodes].dist + radiim3;
1401  if( SCIPisGT(scip, tmpcost, obj) )
1402  {
1403  /* first 3-node elimination? */
1404  if( ancestors == NULL )
1405  {
1406  SCIP_CALL( SCIPallocBufferArray(scip, &cost3, 3) );
1407  SCIP_CALL( SCIPallocBufferArray(scip, &edges3, 3) );
1408  SCIP_CALL( SCIPallocBufferArray(scip, &nodes3, 3) );
1409  SCIP_CALL( SCIPallocBufferArray(scip, &ancestors, 3) );
1410  SCIP_CALL( SCIPallocBufferArray(scip, &revancestors, 3) );
1411  for( l = 0; l < 3; l++ )
1412  {
1413  ancestors[l] = NULL;
1414  revancestors[l] = NULL;
1415  }
1416  }
1417 
1418  assert(cost3 != NULL);
1419  assert(edges3 != NULL);
1420  assert(nodes3 != NULL);
1421  assert(ancestors != NULL);
1422  assert(revancestors != NULL);
1423  SCIPdebugMessage("eliminated 3 knot %d\n", k);
1424  /* get incident edges, cost and adjacent nodes */
1425  l = 0;
1426  for( e = graph->outbeg[k]; e != EAT_LAST; e = graph->oeat[e] )
1427  {
1428  assert(l < 3);
1429  edges3[l] = e;
1430  nodes3[l] = graph->head[e];
1431  cost3[l++] = graph->cost[e];
1432  }
1433 
1434  /* clear */
1435  for( l = 0; l < 3; l++ )
1436  {
1437  SCIPintListNodeFree(scip, &(ancestors[l]));
1438  SCIPintListNodeFree(scip, &(revancestors[l]));
1439  }
1440 
1441  /* store ancestors of incident edges */
1442  SCIP_CALL( SCIPintListNodeAppendCopy(scip, &(ancestors[0]), graph->ancestors[edges3[0]]) );
1443  SCIP_CALL( SCIPintListNodeAppendCopy(scip, &(revancestors[0]), graph->ancestors[Edge_anti(edges3[0])]) );
1444 
1445  SCIP_CALL( SCIPintListNodeAppendCopy(scip, &(ancestors[1]), graph->ancestors[edges3[1]]) );
1446  SCIP_CALL( SCIPintListNodeAppendCopy(scip, &(revancestors[1]), graph->ancestors[Edge_anti(edges3[1])]) );
1447 
1448  SCIP_CALL( SCIPintListNodeAppendCopy(scip, &(ancestors[2]), graph->ancestors[edges3[2]]) );
1449  SCIP_CALL( SCIPintListNodeAppendCopy(scip, &(revancestors[2]), graph->ancestors[Edge_anti(edges3[2])]) );
1450 
1451  SCIP_CALL( graph_edge_reinsert(scip, graph, edges3[0], nodes3[0], nodes3[1], cost3[0] + cost3[1], ancestors[0], ancestors[1], revancestors[0], revancestors[1]) );
1452  SCIP_CALL( graph_edge_reinsert(scip, graph, edges3[1], nodes3[1], nodes3[2], cost3[1] + cost3[2], ancestors[1], ancestors[2], revancestors[1], revancestors[2]) );
1453  SCIP_CALL( graph_edge_reinsert(scip, graph, edges3[2], nodes3[2], nodes3[0], cost3[2] + cost3[0], ancestors[2], ancestors[0], revancestors[2], revancestors[0]) );
1454 
1455  assert(graph->grad[k] == 0);
1456  }
1457  }
1458  }
1459 
1460  if( ancestors != NULL )
1461  {
1462  assert(revancestors != NULL);
1463  for( k = 0; k < 3; k++ )
1464  {
1465  SCIPintListNodeFree(scip, &(ancestors[k]));
1466  SCIPintListNodeFree(scip, &(revancestors[k]));
1467  }
1468  SCIPfreeBufferArray(scip, &revancestors);
1469  SCIPfreeBufferArray(scip, &ancestors);
1470  SCIPfreeBufferArray(scip, &nodes3);
1471  SCIPfreeBufferArray(scip, &edges3);
1472  SCIPfreeBufferArray(scip, &cost3);
1473  }
1474  }
1475 #endif
1476 
1477  /* for(R)PC: try to eliminate terminals */
1478  if( pc )
1479  {
1480  getnext4tterms(scip, graph, cost, costrev, vnoi, vbase, heap, state);
1481 
1482  for( k = 0; k < nnodes; k++ )
1483  {
1484  /* is k a terminal other than the root? */
1485  if( Is_term(graph->term[k]) && graph->mark[k] && graph->grad[k] > 2 && k != graph->source[0] )
1486  {
1487  assert(perm != NULL);
1488  for( l = 0; l < nterms; l++ )
1489  if( perm[l] == k )
1490  break;
1491 
1492  tmpcost = vnoi[k].dist + radii - radius[l];
1493 
1494  if( l == nterms - 1 )
1495  tmpcost -= radius[nterms - 2];
1496  else
1497  tmpcost -= radius[nterms - 1];
1498 
1499 
1500  if( SCIPisGT(scip, tmpcost, obj) )
1501  {
1502  SCIPdebugMessage("alternative bnd elimination!!! \n\n");
1503  (*nelims) += deleteterm(scip, graph, k);
1504  (*offset) += graph->prize[k];
1505  }
1506  else
1507  {
1508  tmpcost += vnoi[k + nnodes].dist;
1509  if( l >= nterms - 2 )
1510  tmpcost -= radius[nterms - 3];
1511  else
1512  tmpcost -= radius[nterms - 2];
1513  if( SCIPisGT(scip, tmpcost, obj) || SCIPisGT(scip, mstobj2 + vnoi[k].dist + vnoi[k + nnodes].dist, obj) )
1514  {
1515  for( e = graph->outbeg[k]; e != EAT_LAST; e = graph->oeat[e] )
1516  if( graph->mark[graph->head[e]] && SCIPisLT(scip, graph->cost[e], graph->prize[k]) )
1517  break;
1518 
1519  if( e == EAT_LAST )
1520  {
1521  SCIPdebugMessage("second elimination!!! prize: %f \n\n", graph->prize[k]);
1522  (*offset) += graph->prize[k];
1523  (*nelims) += deleteterm(scip, graph, k);
1524  }
1525  }
1526  }
1527  }
1528  }
1529  }
1530 
1531  SCIPdebugMessage("nelims (edges) in bound reduce: %d,\n", *nelims);
1532 
1533  /* free adjgraph */
1534  if( !mw )
1535  {
1536  graph_path_exit(scip, adjgraph);
1537  graph_free(scip, adjgraph, TRUE);
1538  }
1539 
1540  /* free memory*/
1541  SCIPfreeBufferArrayNull(scip, &perm);
1542  SCIPfreeBufferArrayNull(scip, &mst);
1543  SCIPfreeBufferArrayNull(scip, &starts);
1544  SCIPfreeBufferArrayNull(scip, &stnode);
1545  SCIPfreeBufferArrayNull(scip, &result);
1546 
1547  return SCIP_OKAY;
1548 }
1549 
1550 
1551 /** bound-based reduction test for the HCDSTP */
1552 SCIP_RETCODE hopbound_reduce(
1553  SCIP* scip,
1554  GRAPH* graph,
1555  PATH* vnoi,
1556  SCIP_Real* cost,
1557  SCIP_Real* radius,
1558  SCIP_Real* costrev,
1559  int* heap,
1560  int* state,
1561  int* vbase,
1562  int* nelims
1563  )
1564 {
1565  SCIP_Real max;
1566  SCIP_Real tmpcost;
1567  SCIP_Real bound;
1568  SCIP_Real mstobj;
1569  SCIP_Real radiim2;
1570 
1571  GRAPH* adjgraph;
1572  PATH* mst;
1573  int e;
1574  int k;
1575  int tail;
1576  int head;
1577  int etemp;
1578  int nnodes;
1579  int nedges;
1580  int nterms;
1581  SCIP_Real hoplimit;
1582 
1583  assert(scip != NULL);
1584  assert(graph != NULL);
1585  assert(vnoi != NULL);
1586  assert(cost != NULL);
1587  assert(radius != NULL);
1588  assert(costrev != NULL);
1589  assert(heap != NULL);
1590  assert(state != NULL);
1591  assert(vbase != NULL);
1592  assert(nelims != NULL);
1593 
1594  *nelims = 0;
1595  nterms = 0;
1596  nedges = graph->edges;
1597  nnodes = graph->knots;
1598 
1599  for( k = 0; k < nnodes; k++ )
1600  {
1601  graph->mark[k] = (graph->grad[k] > 0);
1602  if( graph->mark[k] && Is_term(graph->term[k]) )
1603  nterms++;
1604  }
1605 
1606  for( e = 0; e < nedges; e++ )
1607  {
1608  if( SCIPisLT(scip, graph->cost[e], FARAWAY) )
1609  cost[e] = 1.0;
1610  else
1611  cost[e] = FARAWAY;
1612  if( SCIPisLT(scip, graph->cost[flipedge(e)], FARAWAY) )
1613  costrev[e] = 1.0;
1614  else
1615  costrev[e] = FARAWAY;
1616  }
1617 
1618  /* init auxiliary graph */
1619  SCIP_CALL( graph_init(scip, &adjgraph, nterms, MIN(nedges, (nterms - 1) * nterms), 1, 0) );
1620 
1621  SCIP_CALL( voronoi_radius(scip, graph, adjgraph, vnoi, radius, cost, costrev, vbase, heap, state) );
1622 
1623  /* get 2nd next terminals to all nodes */
1624  get2next(scip, graph, cost, costrev, vnoi, vbase, heap, state);
1625 
1626  /* compute MST on adjgraph */
1627  graph_knot_chg(adjgraph, 0, 0);
1628  adjgraph->source[0] = 0;
1629  assert(graph_valid(adjgraph));
1630  SCIP_CALL( SCIPallocBufferArray(scip, &mst, nterms) );
1631  SCIP_CALL( graph_path_init(scip, adjgraph) );
1632  graph_path_exec(scip, adjgraph, MST_MODE, 0, adjgraph->cost, mst);
1633 
1634  max = -1;
1635  assert(mst[0].edge == -1);
1636  mstobj = 0.0;
1637 
1638  /* compute MST cost ...*/
1639  for( k = 1; k < nterms; k++ )
1640  {
1641  e = mst[k].edge;
1642  assert(adjgraph->path_state[k] == CONNECT);
1643  assert(e >= 0);
1644  tmpcost = adjgraph->cost[e];
1645  mstobj += tmpcost;
1646  if( SCIPisGT(scip, tmpcost, max) )
1647  max = tmpcost;
1648  }
1649  /* ...minus longest edge */
1650  mstobj -= max;
1651 
1652  SCIPsortReal(radius, nnodes);
1653  radiim2 = 0.0;
1654 
1655  for( e = 0; e < nterms - 2; e++ )
1656  {
1657  assert( SCIPisGT(scip, FARAWAY, radius[e]) );
1658  radiim2 += radius[e];
1659  }
1660 
1661  hoplimit = (SCIP_Real) graph->hoplimit;
1662 #if 0
1663  printf("radiim2: %f \n", radiim2);
1664  printf("mstobj: %f \n", mstobj);
1665  printf("hoplimit: %f \n", hoplimit);
1666 #endif
1667  if( SCIPisGT(scip, radiim2, mstobj) )
1668  bound = radiim2;
1669  else
1670  bound = mstobj;
1671 
1672  /* traverse all node, try to eliminate first the node and then all incident edges */
1673  for( k = 0; k < nnodes; k++ )
1674  {
1675  /* can node k be deleted? */
1676  if( !Is_term(graph->term[k]) && SCIPisGT(scip, vnoi[k].dist + vnoi[k + nnodes].dist + bound, hoplimit) )
1677  {
1678  e = graph->outbeg[k];
1679 
1680  /* delete incident edges */
1681  while( e != EAT_LAST )
1682  {
1683  assert(e >= 0);
1684  (*nelims)++;
1685  etemp = graph->oeat[e];
1686  graph_edge_del(scip, graph, e, TRUE);
1687  e = etemp;
1688  }
1689  }
1690  else
1691  {
1692  e = graph->outbeg[k];
1693  while( e != EAT_LAST )
1694  {
1695  assert(e >= 0);
1696  tail = graph->tail[e];
1697  head = graph->head[e];
1698  tmpcost = 1.0 + bound;
1699  if( vbase[tail] != vbase[head] )
1700  {
1701  tmpcost += vnoi[head].dist + vnoi[tail].dist;
1702  }
1703  else
1704  {
1705  if( SCIPisGT(scip, vnoi[tail].dist + vnoi[head + nnodes].dist, vnoi[tail + nnodes].dist + vnoi[head].dist) )
1706  tmpcost += vnoi[tail + nnodes].dist + vnoi[head].dist;
1707  else
1708  tmpcost += vnoi[tail].dist + vnoi[head + nnodes].dist;
1709  assert(SCIPisGE(scip, tmpcost, vnoi[head].dist + vnoi[tail].dist + 1.0 + bound));
1710  }
1711 
1712  /* can edge e (i.e. both arc e and its reverse arc) or arc e be deleted? */
1713  if( SCIPisGT(scip, tmpcost, hoplimit) && SCIPisLT(scip, graph->cost[e], FARAWAY) )
1714  {
1715  etemp = graph->oeat[e];
1716  if( SCIPisGT(scip, graph->cost[e], graph->cost[flipedge(e)]) )
1717  {
1718  graph->cost[e] = FARAWAY;
1719  (*nelims)++;
1720  }
1721  else
1722  {
1723  graph_edge_del(scip, graph, e, TRUE);
1724  (*nelims)++;
1725  }
1726  e = etemp;
1727  }
1728  else
1729  {
1730  e = graph->oeat[e];
1731  }
1732  }
1733  }
1734  }
1735 
1736  SCIPdebugMessage("nelimsX (edges) in hop bound reduce: %d,\n", *nelims);
1737 
1738  /* free adjgraph */
1739  graph_path_exit(scip, adjgraph);
1740  graph_free(scip, adjgraph, TRUE);
1741 
1742  /* free memory*/
1743  SCIPfreeBufferArray(scip, &mst);
1744  assert(graph_valid(graph));
1745 
1746  return SCIP_OKAY;
1747 }
1748 
1749 /** hop bound-based reduction test for the HCDSTP */
1750 SCIP_RETCODE hcrbound_reduce(
1751  SCIP* scip,
1752  GRAPH* graph,
1753  PATH* vnoi,
1754  SCIP_Real* cost,
1755  SCIP_Real* costrev,
1756  SCIP_Real* pathdist,
1757  int* heap,
1758  int* state,
1759  int* vbase,
1760  int* nelims,
1761  int* pathedge
1762  )
1763 {
1764  SCIP_Real tmpcost;
1765  int e;
1766  int k;
1767  int root;
1768  int head;
1769  int etemp;
1770  int bound;
1771  int nnodes;
1772  int nedges;
1773  int nterms;
1774  int hoplimit;
1775 
1776  assert(scip != NULL);
1777  assert(graph != NULL);
1778  assert(vnoi != NULL);
1779  assert(cost != NULL);
1780  assert(costrev != NULL);
1781  assert(heap != NULL);
1782  assert(state != NULL);
1783  assert(vbase != NULL);
1784  assert(nelims != NULL);
1785 
1786  *nelims = 0;
1787  nterms = 0;
1788  root = graph->source[0];
1789  nedges = graph->edges;
1790  nnodes = graph->knots;
1791  hoplimit = graph->hoplimit;
1792 
1793  for( k = 0; k < nnodes; k++ )
1794  {
1795  graph->mark[k] = (graph->grad[k] > 0);
1796  if( graph->mark[k] && Is_term(graph->term[k]) )
1797  nterms++;
1798  }
1799  bound = nterms - 2;
1800  for( e = 0; e < nedges; e++ )
1801  {
1802  if( SCIPisLT(scip, graph->cost[e], FARAWAY) )
1803  cost[e] = 1.0;
1804  else
1805  cost[e] = graph->cost[e];
1806  if( SCIPisLT(scip, graph->cost[flipedge(e)], FARAWAY) )
1807  costrev[e] = 1.0;
1808  else
1809  costrev[e] = graph->cost[flipedge(e)];
1810  }
1811 
1812  /* distance from root to all nodes */
1813  graph_path_execX(scip, graph, root, cost, pathdist, pathedge);
1814 
1815  /* no paths should go back to the root */
1816  for( e = graph->outbeg[root]; e != EAT_LAST; e = graph->oeat[e] )
1817  costrev[e] = FARAWAY;
1818 
1819  /* build voronoi diagram */
1820  voronoi_terms(scip, graph, costrev, vnoi, vbase, heap, state);
1821 
1822  /* traverse all node, try to eliminate first the node and then all incident edges */
1823  for( k = 0; k < nnodes; k++ )
1824  {
1825  /* can node k be deleted? */
1826  if( !Is_term(graph->term[k]) && SCIPisGT(scip, vnoi[k].dist + pathdist[k] + (double) bound, (double) hoplimit) )
1827  {
1828  e = graph->outbeg[k];
1829 
1830  /* delete incident edges */
1831  while( e != EAT_LAST )
1832  {
1833  assert(e >= 0);
1834  (*nelims)++;
1835  etemp = graph->oeat[e];
1836  graph_edge_del(scip, graph, e, TRUE);
1837  e = etemp;
1838  }
1839  }
1840  else
1841  {
1842  e = graph->outbeg[k];
1843  while( e != EAT_LAST )
1844  {
1845  assert(e >= 0);
1846  head = graph->head[e];
1847  tmpcost = pathdist[k] + 1.0 + vnoi[head].dist + bound;
1848 
1849  etemp = graph->oeat[e];
1850  /* can edge e (i.e. both arc e and its reverse arc) or arc e be deleted? */
1851  if( SCIPisGT(scip, tmpcost, (double) hoplimit) && SCIPisLT(scip, graph->cost[e], FARAWAY) )
1852  {
1853 
1854  if( SCIPisGT(scip, FARAWAY, graph->cost[flipedge(e)]) )
1855  {
1856  graph->cost[e] = FARAWAY;
1857  (*nelims)++;
1858  }
1859  else
1860  {
1861  graph_edge_del(scip, graph, e, TRUE);
1862  (*nelims)++;
1863  }
1864  }
1865  e = etemp;
1866  }
1867  }
1868  }
1869 
1870  SCIPdebugMessage("eliminated (edges) in hcr bound reduce: %d,\n", *nelims);
1871 
1872  assert(graph_valid(graph));
1873 
1874  return SCIP_OKAY;
1875 }
1876 
1877 /* reduction method for HCSTP */
1878 SCIP_RETCODE hcrcbound_reduce(
1879  SCIP* scip,
1880  GRAPH* graph,
1881  PATH* vnoi,
1882  SCIP_Real* cost,
1883  SCIP_Real* costrev,
1884  SCIP_Real* pathdist,
1885  SCIP_Real objval,
1886  int* heap,
1887  int* state,
1888  int* vbase,
1889  int* nelims,
1890  int* pathedge,
1891  SCIP_Bool fix
1892  )
1893 {
1894  SCIP_VAR** vars;
1895  SCIP_HEURDATA* tmheurdata;
1896  SCIP_Real min;
1897  SCIP_Real bound;
1898  SCIP_Real maxmin;
1899  SCIP_Real maxcost;
1900  SCIP_Real tmpcost;
1901  SCIP_Real hopfactor;
1902  int* result;
1903  int e;
1904  int k;
1905  int root;
1906  int head;
1907  int etemp;
1908  int nnodes;
1909  int nedges;
1910  int best_start;
1911  SCIP_Bool success;
1912 
1913  assert(scip != NULL);
1914  assert(graph != NULL);
1915  assert(vnoi != NULL);
1916  assert(cost != NULL);
1917  assert(costrev != NULL);
1918  assert(heap != NULL);
1919  assert(state != NULL);
1920  assert(vbase != NULL);
1921  assert(nelims != NULL);
1922 
1923  hopfactor = DEFAULT_HOPFACTOR;
1924  bound = 0.0;
1925  *nelims = 0;
1926  best_start = 0;
1927  success = TRUE;
1928  vars = NULL;
1929  root = graph->source[0];
1930  nedges = graph->edges;
1931  nnodes = graph->knots;
1932 
1933  SCIP_CALL( SCIPallocBufferArray(scip, &result, nedges) );
1934  maxcost = 0.0;
1935  if( fix )
1936  {
1937  vars = SCIPprobdataGetVars(scip);
1938  assert(vars != NULL);
1939  for( e = 0; e < nedges; e += 2 )
1940  {
1941  result[e] = UNKNOWN;
1942  result[e + 1] = UNKNOWN;
1943 
1944  if( SCIPvarGetUbLocal(vars[e + 1]) < 0.5 )
1945  {
1946  costrev[e] = BLOCKED;
1947  }
1948  else
1949  {
1950  costrev[e] = graph->cost[e + 1];
1951 
1952  if( SCIPisGT(scip, costrev[e], maxcost) && SCIPisLT(scip, costrev[e], BLOCKED) )
1953  maxcost = costrev[e];
1954  }
1955  cost[e + 1] = costrev[e];
1956  if( SCIPvarGetUbLocal(vars[e]) < 0.5 )
1957  {
1958  costrev[e + 1] = BLOCKED;
1959  }
1960  else
1961  {
1962  costrev[e + 1] = graph->cost[e];
1963 
1964  if( SCIPisGT(scip, graph->cost[e], maxcost) && SCIPisLT(scip, costrev[e + 1], BLOCKED) )
1965  maxcost = graph->cost[e];
1966  }
1967  cost[e] = costrev[e + 1];
1968  }
1969  }
1970  else
1971  {
1972  for( e = 0; e < nedges; e++ )
1973  {
1974  result[e] = UNKNOWN;
1975  cost[e] = graph->cost[e];
1976  costrev[e] = graph->cost[flipedge(e)];
1977  if( SCIPisGT(scip, graph->cost[e], maxcost) )
1978  maxcost = graph->cost[e];
1979  }
1980  }
1981 
1982  maxmin = -1.0;
1983  for( k = 0; k < nnodes; k++ )
1984  {
1985  graph->mark[k] = (graph->grad[k] > 0);
1986  if( graph->mark[k] && Is_term(graph->term[k]) )
1987  {
1988  if( k != root )
1989  {
1990  min = FARAWAY;
1991  for( e = graph->inpbeg[k]; e != EAT_LAST; e = graph->ieat[e] )
1992  if( SCIPisLT(scip, cost[e], min) )
1993  min = cost[e];
1994  assert(SCIPisGT(scip, BLOCKED, min));
1995  if( SCIPisGT(scip, min, maxmin) )
1996  maxmin = min;
1997  bound += min;
1998  }
1999  }
2000  }
2001  bound -= maxmin;
2002 
2003 
2004  /* distance from root to all nodes */
2005  graph_path_execX(scip, graph, root, cost, pathdist, pathedge);
2006 
2007  /* no paths should go back to the root */
2008  for( e = graph->outbeg[root]; e != EAT_LAST; e = graph->oeat[e] )
2009  costrev[e] = FARAWAY;
2010 
2011  /* build voronoi diagram */
2012  voronoi_terms(scip, graph, costrev, vnoi, vbase, heap, state);
2013 
2014  if( SCIPisLT(scip, objval, 0.0) )
2015  {
2016  /* get TM heuristic data */
2017  assert(SCIPfindHeur(scip, "TM") != NULL);
2018  tmheurdata = SCIPheurGetData(SCIPfindHeur(scip, "TM"));
2019 
2020  /* compute UB */
2021  SCIP_CALL( SCIPheurComputeSteinerTree(scip, tmheurdata, graph, NULL, &best_start, result, 50, root, cost, costrev, &hopfactor, NULL, maxcost, &success) );
2022 
2023  objval = 0.0;
2024  for( e = 0; e < nedges; e++ )
2025  if( result[e] == CONNECT )
2026  objval += graph->cost[e];
2027  }
2028  else
2029  {
2030  /* objval = objval - fixed; */
2031  objval = SCIPgetCutoffbound(scip);
2032  assert(SCIPisGT(scip, objval, 0.0));
2033  }
2034 
2035  /* traverse all node, try to eliminate first the node and then all incident edges */
2036  for( k = 0; k < nnodes; k++ )
2037  {
2038  if( Is_term(graph->term[k]) )
2039  continue;
2040  /* can node k be deleted? */
2041  if( SCIPisGT(scip, vnoi[k].dist + pathdist[k] + bound, objval) )
2042  {
2043  e = graph->outbeg[k];
2044 
2045  /* delete incident edges */
2046  while( e != EAT_LAST )
2047  {
2048  assert(e >= 0);
2049 
2050  etemp = graph->oeat[e];
2051  if( fix )
2052  {
2053  assert(vars != NULL);
2054  /* try to fix edge */
2055  SCIP_CALL( fixedgevar(scip, vars[e], nelims) );
2056 
2057  /* try to fix reversed edge */
2058  SCIP_CALL( fixedgevar(scip, vars[flipedge(e)], nelims) );
2059  }
2060  else
2061  {
2062  graph_edge_del(scip, graph, e, TRUE);
2063  (*nelims)++;
2064  }
2065  e = etemp;
2066  }
2067  }
2068  else
2069  {
2070  e = graph->outbeg[k];
2071  while( e != EAT_LAST )
2072  {
2073  assert(e >= 0);
2074  head = graph->head[e];
2075  tmpcost = pathdist[k] + graph->cost[e] + vnoi[head].dist + bound;
2076 
2077  etemp = graph->oeat[e];
2078  /* can edge e (i.e. both arc e and its reverse arc) or arc e be deleted? */
2079  if( SCIPisGT(scip, tmpcost, objval) && SCIPisLT(scip, graph->cost[e], FARAWAY) )
2080  {
2081  if( fix )
2082  {
2083  assert(vars != NULL);
2084 
2085  /* try to fix edge */
2086  SCIP_CALL( fixedgevar(scip, vars[e], nelims) );
2087  }
2088  else
2089  {
2090  if( SCIPisGT(scip, FARAWAY, graph->cost[flipedge(e)]) )
2091  {
2092  graph->cost[e] = FARAWAY;
2093  (*nelims)++;
2094  }
2095  else
2096  {
2097  graph_edge_del(scip, graph, e, TRUE);
2098  (*nelims)++;
2099  }
2100  }
2101  }
2102  e = etemp;
2103  }
2104  }
2105  }
2106 
2107  SCIPdebugMessage("CCC eliminated (edges) in hcrc bound reduce: %d,\n", *nelims);
2108  /* free memory */
2109  SCIPfreeBufferArray(scip, &result);
2110 
2111  assert(graph_valid(graph));
2112 
2113  return SCIP_OKAY;
2114 }
SCIP_RETCODE graph_path_init(SCIP *, GRAPH *)
Definition: grphpath.c:407
#define Is_term(a)
Definition: grph.h:158
void get3next(SCIP *, const GRAPH *, SCIP_Real *, SCIP_Real *, PATH *, int *, int *, int *)
Definition: grphpath.c:1310
static void compTMstarts(GRAPH *graph, int *starts, unsigned int *seed, int runs)
Definition: reduce_bnd.c:140
int graph_valid(const GRAPH *)
Definition: grphbase.c:2532
SCIP_RETCODE SCIPdualAscentStp(SCIP *scip, GRAPH *g, SCIP_Real *redcost, SCIP_Real *objval, SCIP_Bool addcuts, GNODE **gnodearrterms, int *edgearrint, int *nodearrint, int root, int nruns, char *edgearrchar, char *nodearrchar)
Definition: cons_stp.c:1161
Definition: grph.h:55
#define TRUE
Definition: portab.h:34
SCIP_RETCODE fixedgevar(SCIP *scip, SCIP_VAR *edgevar, int *nfixed)
Definition: prop_stp.c:76
Constraint handler for Steiner problems.
signed int edge
Definition: grph.h:140
#define DEFAULT_HOPFACTOR
Definition: heur_tm.h:37
void getnext4tterms(SCIP *, const GRAPH *, SCIP_Real *, SCIP_Real *, PATH *, int *, int *, int *)
Definition: grphpath.c:1603
#define MST_MODE
Definition: grph.h:152
SCIP_RETCODE da_reduce(SCIP *scip, GRAPH *graph, PATH *vnoi, GNODE **gnodearr, SCIP_Real *cost, SCIP_Real *costrev, SCIP_Real *pathdist, int *edgearrint, int *vbase, int *pathedge, int *state, int *heursources, char *nodearrchar, int *nelims)
Definition: reduce_bnd.c:202
int * path_heap
Definition: grph.h:114
int terms
Definition: grph.h:63
SCIP_VAR ** SCIPprobdataGetVars(SCIP *scip)
SCIP_RETCODE graph_PcSapCopy(SCIP *, GRAPH *, GRAPH **, SCIP_Real *)
Definition: grphbase.c:792
#define DEFAULT_HEURRUNS
Definition: reduce_bnd.c:42
SCIP_RETCODE graph_init_history(SCIP *, GRAPH *)
Definition: grphbase.c:128
void get4next(SCIP *, const GRAPH *, SCIP_Real *, SCIP_Real *, PATH *, int *, int *, int *)
Definition: grphpath.c:1417
SCIP_RETCODE graph_edge_reinsert(SCIP *, GRAPH *, int, int, int, SCIP_Real, IDX *, IDX *, IDX *, IDX *)
Definition: grphbase.c:1846
#define STP_HOP_CONS
Definition: grph.h:48
#define EAT_LAST
Definition: grph.h:31
#define Edge_anti(a)
Definition: grph.h:161
SCIP_RETCODE pcgraphtrans(SCIP *, GRAPH *)
Definition: grphbase.c:2142
#define BLOCKED
Definition: grph.h:150
int * path_state
Definition: grph.h:115
Problem data for stp problem.
void graph_path_exit(SCIP *, GRAPH *)
Definition: grphpath.c:429
static SCIP_RETCODE probdataPrintGraph(GRAPH *graph, const char *filename, SCIP_Bool *edgemark)
Definition: probdata_stp.c:427
int * oeat
Definition: grph.h:100
void get2next(SCIP *, const GRAPH *, SCIP_Real *, SCIP_Real *, PATH *, int *, int *, int *)
Definition: grphpath.c:1214
void graph_free(SCIP *, GRAPH *, SCIP_Bool)
Definition: grphbase.c:1137
void graph_knot_chg(GRAPH *, int, int)
Definition: grphbase.c:1386
int * head
Definition: grph.h:94
int deleteterm(SCIP *, GRAPH *, int)
#define FALSE
Definition: portab.h:37
void SCIPintListNodeFree(SCIP *scip, IDX **node)
Definition: misc_stp.c:140
SCIP_RETCODE pcgraphorg(SCIP *, GRAPH *)
Definition: grphbase.c:2104
int * mark
Definition: grph.h:71
void graph_path_execX(SCIP *, const GRAPH *, int, SCIP_Real *, SCIP_Real *, int *)
Definition: grphpath.c:639
#define CONNECT
Definition: grph.h:147
miscellaneous methods used for solving Steiner problems
int stp_type
Definition: grph.h:123
IDX ** ancestors
Definition: grph.h:83
int * outbeg
Definition: grph.h:77
#define Is_pterm(a)
Definition: grph.h:159
SCIP_Real * prize
Definition: grph.h:92
SCIP_RETCODE voronoi_radius(SCIP *scip, const GRAPH *, GRAPH *, PATH *, SCIP_Real *, SCIP_Real *, SCIP_Real *, int *, int *, int *)
Definition: grphpath.c:1912
int * tail
Definition: grph.h:93
SCIP_RETCODE SCIPheurComputeSteinerTree(SCIP *scip, SCIP_HEURDATA *heurdata, const GRAPH *graph, int *starts, int *bestnewstart, int *best_result, int runs, int bestincstart, SCIP_Real *cost, SCIP_Real *costrev, SCIP_Real *hopfactor, SCIP_Real *nodepriority, SCIP_Real maxcost, SCIP_Bool *success)
Definition: heur_tm.c:1419
int * term
Definition: grph.h:69
int knots
Definition: grph.h:61
#define STP_MAX_NODE_WEIGHT
Definition: grph.h:47
void voronoi_terms(SCIP *, const GRAPH *, SCIP_Real *, PATH *, int *, int *, int *)
Definition: grphpath.c:1679
void getnext4terms(SCIP *, const GRAPH *, SCIP_Real *, SCIP_Real *, PATH *, int *, int *, int *)
Definition: grphpath.c:1562
Improvement heuristic for Steiner problems.
#define Is_gterm(a)
Definition: grph.h:160
int * inpbeg
Definition: grph.h:75
#define FARAWAY
Definition: grph.h:149
propagator for Steiner tree problems, using the LP reduced costs
SCIP_RETCODE hcrcbound_reduce(SCIP *scip, GRAPH *graph, PATH *vnoi, SCIP_Real *cost, SCIP_Real *costrev, SCIP_Real *pathdist, SCIP_Real objval, int *heap, int *state, int *vbase, int *nelims, int *pathedge, SCIP_Bool fix)
Definition: reduce_bnd.c:1878
#define DEFAULT_DARUNS
Definition: reduce_bnd.c:43
SCIP_RETCODE SCIPintListNodeAppendCopy(SCIP *scip, IDX **node1, IDX *node2)
Definition: misc_stp.c:76
#define UNKNOWN
Definition: grph.h:148
#define STP_PRIZE_COLLECTING
Definition: grph.h:40
SCIP_RETCODE graph_init(SCIP *, GRAPH **, int, int, int, int)
Definition: grphbase.c:44
void graph_edge_del(SCIP *, GRAPH *, int, SCIP_Bool)
Definition: grphbase.c:1965
includes various files containing graph methods used for Steiner problems
SCIP_RETCODE hopbound_reduce(SCIP *scip, GRAPH *graph, PATH *vnoi, SCIP_Real *cost, SCIP_Real *radius, SCIP_Real *costrev, int *heap, int *state, int *vbase, int *nelims)
Definition: reduce_bnd.c:1552
SCIP_RETCODE bound_reduce(SCIP *scip, GRAPH *graph, PATH *vnoi, SCIP_Real *cost, SCIP_Real *prize, SCIP_Real *radius, SCIP_Real *costrev, SCIP_Real *offset, SCIP_Real *upperbound, int *heap, int *state, int *vbase, int *nelims)
Definition: reduce_bnd.c:845
int * grad
Definition: grph.h:74
SCIP_Real * cost
Definition: grph.h:91
SCIP_RETCODE hcrbound_reduce(SCIP *scip, GRAPH *graph, PATH *vnoi, SCIP_Real *cost, SCIP_Real *costrev, SCIP_Real *pathdist, int *heap, int *state, int *vbase, int *nelims, int *pathedge)
Definition: reduce_bnd.c:1750
SCIP_RETCODE extendSteinerTreePcMw(SCIP *scip, const GRAPH *graph, PATH *vnoi, SCIP_Real *costrev, int *vbase, int *stedge, char *stvertex, int *adds)
Definition: heur_local.c:1941
#define STP_ROOTED_PRIZE_COLLECTING
Definition: grph.h:41
int * source
Definition: grph.h:67
SCIP_RETCODE daPc_reduce(SCIP *scip, GRAPH *graph, PATH *vnoi, GNODE **gnodearr, SCIP_Real *cost, SCIP_Real *costrev, SCIP_Real *pathdist, int *vbase, int *pathedge, int *edgearrint, int *state, char *nodearrchar, int *nelims)
Definition: reduce_bnd.c:577
shortest paths based primal heuristics for Steiner problems
int edges
Definition: grph.h:89
#define flipedge(edge)
Definition: grph.h:143
int * ieat
Definition: grph.h:99
int hoplimit
Definition: grph.h:86
double dist
Definition: grph.h:139
void graph_path_exec(SCIP *, const GRAPH *, int, int, SCIP_Real *, PATH *)
Definition: grphpath.c:453