Scippy

SCIP

Solving Constraint Integer Programs

extreduce_bottleneck.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-2022 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 visit scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file extreduce_bottleneck.c
17  * @brief extended-reduction specific tree bottleneck algorithms for Steiner tree problems
18  * @author Daniel Rehfeldt
19  *
20  * This file implements tree bottleneck algorithms for extended reduction techniques for Steiner problems.
21  *
22  * A list of all interface methods can be found in extreduce.h.
23  *
24  */
25 
26 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
27 // #define SCIP_DEBUG
28 //#define STP_DEBUG_EXT
29 
30 #include <stdio.h>
31 #include <assert.h>
32 #include "graph.h"
33 #include "portab.h"
34 #include "extreduce.h"
35 #include "extreducedefs.h"
36 
37 
38 
39 /**@name Local methods
40  *
41  * @{
42  */
43 
44 
45 /** computes the tree bottleneck between vertices in the current tree,
46  * for which vertex_pathmarked root path has been marked already */
47 static
49  const GRAPH* graph, /**< graph data structure */
50  const EXTDATA* extdata, /**< extension data */
51 #ifndef NDEBUG
52  int vertex_pathmarked, /**< vertex with marked rootpath */
53 #endif
54  int vertex_unmarked /**< second vertex */
55  )
56 {
57  const SCIP_Real* const bottleneckDist_node = extdata->tree_bottleneckDistNode;
58  const SCIP_Real* const parentEdgeCost = extdata->tree_parentEdgeCost;
59  const int* const parentNode = extdata->tree_parentNode;
60  int* const tree_deg = extdata->tree_deg;
61  SCIP_Real bottleneck;
62  const int tree_root = extdata->tree_root;
63  int currentNode;
64 
65  assert(bottleneckDist_node && parentEdgeCost && parentNode);
66  assert(bottleneckDist_node[vertex_pathmarked] == -1.0 || vertex_pathmarked == tree_root);
67  assert(bottleneckDist_node[vertex_unmarked] == -1.0 || vertex_unmarked == tree_root || tree_deg[vertex_unmarked] > 1);
68  assert(bottleneckDist_node[tree_root] >= 0.0);
69  assert(vertex_pathmarked != vertex_unmarked);
70 
71  /* go down from vertex_unmarked up to lowest common ancestor with vertex_pathmarked */
72  bottleneck = 0.0;
73 
74  if( vertex_unmarked == tree_root )
75  {
76  currentNode = vertex_unmarked;
77  }
78  else
79  {
80  SCIP_Real bottleneck_local = 0.0;
81  const SCIP_Bool isPc = graph_pc_isPc(graph);
82 
83  assert(parentNode[vertex_unmarked] >= 0);
84 
85  for( currentNode = vertex_unmarked; bottleneckDist_node[currentNode] < -0.5; currentNode = parentNode[currentNode] )
86  {
87  assert(tree_deg[currentNode] >= 0 && parentEdgeCost[currentNode] >= 0.0);
88  assert(bottleneckDist_node[currentNode] == -1.0);
89  assert(currentNode != vertex_pathmarked);
90 
91  if( tree_deg[currentNode] == 2 )
92  {
93  bottleneck_local += parentEdgeCost[currentNode];
94  if( isPc && Is_term(graph->term[currentNode]) )
95  {
96  assert(graph_pc_termIsNonLeafTerm(graph, currentNode) && graph->prize[currentNode] > 0.0);
97  bottleneck_local -= graph->prize[currentNode];
98  }
99  }
100  else
101  bottleneck_local = parentEdgeCost[currentNode];
102 
103  if( bottleneck < bottleneck_local )
104  bottleneck = bottleneck_local;
105 
106  assert(parentNode[currentNode] >= 0 && parentNode[currentNode] != vertex_unmarked);
107  }
108  }
109 
110  bottleneck = MAX(bottleneck, bottleneckDist_node[currentNode]);
111 
112  return bottleneck;
113 }
114 
115 
116 /** helper */
117 static inline
119  SCIP* scip, /**< SCIP */
120  const GRAPH* graph, /**< graph data structure */
121  int path_start, /**< vertex to start from */
122  int path_end, /**< vertex to end at */
123  EXTDATA* extdata /**< extension data */
124 )
125 {
126  SCIP_Bool* const edges_isEqForbidden = extdata->sdeq_edgesIsForbidden;
127  const int* const parentNode = extdata->tree_parentNode;
128 
129  assert(edges_isEqForbidden);
130  assert(path_start != path_end);
131  assert(graph_knot_isInRange(graph, path_start));
132  assert(graph_knot_isInRange(graph, path_end));
133 
134  for( int currentNode = path_start; currentNode != path_end; currentNode = parentNode[currentNode] )
135  {
136  int e;
137  const int parent = parentNode[currentNode];
138 
139  assert(graph_knot_isInRange(graph, parent));
140 
141  for( e = graph->outbeg[parent]; e != EAT_LAST; e = graph->oeat[e] )
142  {
143  if( graph->head[e] == currentNode )
144  {
145  assert(EQ(graph->cost[e], extdata->tree_parentEdgeCost[currentNode]));
146  if( !edges_isEqForbidden[e / 2] )
147  {
148 #ifdef SCIP_DEBUG
149  SCIPdebugMessage("forbid equality edge: ");
150  graph_edge_printInfo(graph, e);
151 #endif
152  edges_isEqForbidden[e / 2] = TRUE;
153  extdata->sdeq_hasForbiddenEdges = TRUE;
154  StpVecPushBack(scip, extdata->sdeq_resetStack, e / 2);
155  }
156  break;
157  }
158  }
159 
160  assert(e != EAT_LAST);
161  }
162 }
163 
164 
165 /** markes bottleneck edges used for equality rule-out */
166 static inline
168  SCIP* scip, /**< SCIP */
169  const GRAPH* graph, /**< graph data structure */
170  SCIP_Real dist_eq, /**< distance that was used for equality rule-out */
171  int vertex_pathmarked, /**< vertex with marked rootpath */
172  int vertex_unmarked, /**< second vertex */
173  EXTDATA* extdata /**< extension data */
174 )
175 {
176  const SCIP_Real* const bottleneckDist_node = extdata->tree_bottleneckDistNode;
177  const SCIP_Real* const parentEdgeCost = extdata->tree_parentEdgeCost;
178  const int* const parentNode = extdata->tree_parentNode;
179  int* const tree_deg = extdata->tree_deg;
180  SCIP_Real bottleneck_local;
181  const int tree_root = extdata->tree_root;
182  int ancestor = UNKNOWN;
183  int bottleneck_start;
184  const SCIP_Bool isPc = graph_pc_isPc(graph);
185 
186  assert(bottleneckDist_node && parentEdgeCost && parentNode);
187  assert(bottleneckDist_node[vertex_pathmarked] == -1.0 || vertex_pathmarked == tree_root);
188  assert(bottleneckDist_node[vertex_unmarked] == -1.0 || vertex_unmarked == tree_root || tree_deg[vertex_unmarked] > 1);
189  assert(bottleneckDist_node[tree_root] >= 0.0);
190  assert(vertex_pathmarked != vertex_unmarked);
191 
192  /* 1. go down from vertex_unmarked to lowest common ancestor with vertex_pathmarked */
193 
194  if( vertex_unmarked == tree_root )
195  {
196  ancestor = vertex_unmarked;
197  }
198  else
199  {
200  int currentNode;
201  assert(parentNode[vertex_unmarked] >= 0);
202  bottleneck_start = UNKNOWN;
203  bottleneck_local = 0.0;
204 
205  for( currentNode = vertex_unmarked; bottleneckDist_node[currentNode] < -0.5; currentNode = parentNode[currentNode] )
206  {
207  assert(tree_deg[currentNode] >= 0 && parentEdgeCost[currentNode] >= 0.0);
208  assert(EQ(bottleneckDist_node[currentNode], -1.0));
209  assert(currentNode != vertex_pathmarked);
210 
211  if( tree_deg[currentNode] == 2 )
212  {
213  bottleneck_local += parentEdgeCost[currentNode];
214  if( isPc && Is_term(graph->term[currentNode]) )
215  {
216  assert(graph_pc_termIsNonLeafTerm(graph, currentNode) && graph->prize[currentNode] > 0.0);
217  bottleneck_local -= graph->prize[currentNode];
218  }
219  }
220  else
221  {
222  bottleneck_start = currentNode;
223  bottleneck_local = parentEdgeCost[currentNode];
224  }
225 
226  if( EQ(bottleneck_local, dist_eq) )
227  {
228  assert(parentNode[currentNode] >= 0);
229  bottleneckMarkEqualityPath(scip, graph, bottleneck_start, parentNode[currentNode], extdata);
230 
231  return;
232  }
233 
234  assert(parentNode[currentNode] >= 0 && parentNode[currentNode] != vertex_unmarked);
235  }
236 
237  ancestor = currentNode;
238  assert(GE(bottleneckDist_node[ancestor], 0.0));
239  }
240 
241 
242  /* 2. go down from vertex_marked to ancestor */
243 
244  assert(parentNode[vertex_pathmarked] >= 0);
245  assert(ancestor != UNKNOWN);
246  bottleneck_start = UNKNOWN;
247  bottleneck_local = 0.0;
248 
249  for( int currentNode = vertex_pathmarked; currentNode != ancestor; currentNode = parentNode[currentNode] )
250  {
251  assert(tree_deg[currentNode] >= 0 && parentEdgeCost[currentNode] >= 0.0);
252  assert(currentNode != vertex_unmarked);
253 
254  if( tree_deg[currentNode] == 2 )
255  {
256  bottleneck_local += parentEdgeCost[currentNode];
257  if( isPc && Is_term(graph->term[currentNode]) )
258  {
259  assert(graph_pc_termIsNonLeafTerm(graph, currentNode) && graph->prize[currentNode] > 0.0);
260  bottleneck_local -= graph->prize[currentNode];
261  }
262  }
263  else
264  {
265  bottleneck_start = currentNode;
266  bottleneck_local = parentEdgeCost[currentNode];
267  }
268 
269  if( EQ(bottleneck_local, dist_eq) )
270  {
271  // todo not quite sure whether this is correct
272  if( bottleneck_start == UNKNOWN )
273  {
274  assert(extIsAtInitialGenStar(extdata));
275  bottleneck_start = vertex_pathmarked;
276  }
277 
278  assert(parentNode[currentNode] >= 0);
279  bottleneckMarkEqualityPath(scip, graph, bottleneck_start, parentNode[currentNode], extdata);
280 
281  return;
282  }
283 
284  assert(parentNode[currentNode] >= 0 && parentNode[currentNode] != vertex_unmarked);
285  }
286 
287  assert(0 && "should never arrive here!");
288 }
289 
290 
291 /** markes single bottleneck edge used for equality rule-out */
292 static inline
294  SCIP* scip, /**< SCIP */
295  const GRAPH* g, /**< graph data structure */
296  int edge, /**< the edge to mark */
297  EXTDATA* extdata /**< extension data */
298 )
299 {
300  SCIP_Bool* const edges_isEqForbidden = extdata->sdeq_edgesIsForbidden;
301 
302  assert(edges_isEqForbidden);
303  assert(graph_edge_isInRange(g, edge));
304 
305  if( !edges_isEqForbidden[edge / 2] )
306  {
307  edges_isEqForbidden[edge / 2] = TRUE;
308  extdata->sdeq_hasForbiddenEdges = TRUE;
309  StpVecPushBack(scip, extdata->sdeq_resetStack, edge / 2);
310  }
311 }
312 
313 
314 /** helper to check the case of quality */
315 static inline
317  SCIP* scip, /**< SCIP */
318  const GRAPH* g, /**< graph data structure */
319  SCIP_Real dist_eq, /**< critical distance */
320  int edge_forbidden, /**< forbidden edge */
321  int vertex1, /**< first vertex */
322  int vertex2, /**< second vertex */
323  EXTDATA* extdata /**< extension data */
324 )
325 {
326  const SCIP_Real sd_eq = extreduce_distDataGetSdDoubleForbiddenEq(scip, g, dist_eq,
327  edge_forbidden, vertex1, vertex2, extdata);
328 
329  if( sd_eq < -0.5 )
330  return FALSE;
331 
332  assert(GE(sd_eq, dist_eq));
333 
334  if( LE(sd_eq, dist_eq) )
335  {
336  assert(EQ(sd_eq, dist_eq));
337  return TRUE;
338  }
339 
340  return FALSE;
341 }
342 
343 
344 /**@} */
345 
346 /**@name Interface methods
347  *
348  * @{
349  */
350 
351 
352 
353 /** marks bottleneck array on path to tree root */
355  const GRAPH* graph, /**< graph data structure */
356  int vertex, /**< vertex to start from */
357  EXTDATA* extdata /**< extension data */
358  )
359 {
360  SCIP_Real* const bottleneckDist_node = extdata->tree_bottleneckDistNode;
361  const SCIP_Real* const parentEdgeCost = extdata->tree_parentEdgeCost;
362  const int* const parentNode = extdata->tree_parentNode;
363  const int* const tree_deg = extdata->tree_deg;
364  const int tree_root = extdata->tree_root;
365 
366  assert(bottleneckDist_node && parentEdgeCost && parentNode && tree_deg);
367  assert(vertex >= 0 && vertex < graph->knots);
368  assert(bottleneckDist_node[vertex] == -1.0);
369  assert(bottleneckDist_node[tree_root] == -1.0);
370 
371  if( vertex == tree_root )
372  {
373  bottleneckDist_node[vertex] = 0.0;
374  }
375  else
376  {
377  /* go down from vertex */
378 
379  SCIP_Real bottleneck = 0.0;
380  SCIP_Real bottleneck_local = 0.0;
381  int childNode = vertex;
382  int currentNode = parentNode[vertex];
383  const SCIP_Bool isPc = graph_pc_isPc(graph);
384 
385  assert(currentNode != -1);
386  assert(!extInitialCompIsEdge(extdata) || tree_deg[childNode] == 1);
387  assert(childNode == extdata->tree_starcenter || extInitialCompIsGenStar(extdata) || tree_deg[childNode] == 1);
388 
389  while( currentNode != -1 )
390  {
391  assert(currentNode >= 0 && tree_deg[currentNode] >= 0);
392  assert(parentEdgeCost[childNode] >= 0.0 && bottleneckDist_node[currentNode] == -1.0);
393  assert(currentNode != vertex);
394  assert(!isPc || !graph_pc_knotIsDummyTerm(graph, currentNode));
395 
396  if( tree_deg[childNode] == 2 )
397  {
398  bottleneck_local += parentEdgeCost[childNode];
399  if( isPc && Is_term(graph->term[childNode]) )
400  {
401  assert(graph_pc_termIsNonLeafTerm(graph, childNode) && graph->prize[childNode] > 0.0);
402  bottleneck_local -= graph->prize[childNode];
403  }
404  }
405  else
406  bottleneck_local = parentEdgeCost[childNode];
407 
408  if( bottleneck < bottleneck_local )
409  bottleneck = bottleneck_local;
410 
411  bottleneckDist_node[currentNode] = bottleneck;
412  childNode = currentNode;
413  currentNode = parentNode[currentNode];
414  }
415 
416  assert(childNode == tree_root);
417  }
418 }
419 
420 
421 /** unmarks bottleneck array on path to tree root */
423  const GRAPH* graph, /**< graph data structure */
424  int vertex, /**< vertex to start from */
425  EXTDATA* extdata /**< extension data */
426  )
427 {
428  SCIP_Real* const bottleneckDist_node = extdata->tree_bottleneckDistNode;
429  const int* const parentNode = extdata->tree_parentNode;
430  const int tree_root = extdata->tree_root;
431 
432  assert(extdata && bottleneckDist_node && parentNode);
433  assert(bottleneckDist_node[vertex] == -1.0 || vertex == tree_root);
434  assert(bottleneckDist_node[tree_root] >= 0.0);
435 
436  if( vertex == tree_root )
437  {
438  bottleneckDist_node[vertex] = -1.0;
439  assert(parentNode[vertex] == -1);
440  }
441  else
442  {
443  assert(parentNode[vertex] >= 0);
444  }
445 
446  /* go down from vertex and reset bottleneckDist_node */
447  for( int currentNode = parentNode[vertex]; currentNode != -1; currentNode = parentNode[currentNode] )
448  {
449  assert(currentNode >= 0);
450  assert(extdata->tree_deg[currentNode] >= 0);
451  assert(bottleneckDist_node[currentNode] >= 0.0);
452 
453  bottleneckDist_node[currentNode] = -1.0;
454  }
455 
456  assert(bottleneckDist_node[tree_root] == -1.0);
457 }
458 
459 
460 
461 /** Does a special distance approximation dominate the tree bottleneck distance between
462  * vertex_pathmarked and vertex_unmarked in the current tree.
463  * NOTE: makes additional checks in case of equality */
465  SCIP* scip, /**< SCIP */
466  const GRAPH* graph, /**< graph data structure */
467  int vertex_pathmarked, /**< vertex for which bottleneck path to root has been marked */
468  int vertex_unmarked, /**< second vertex */
469  SCIP_Real specialDist, /**< best computed special distance approximation (-1.0 if unknown) */
470  int edge_forbidden, /**< forbidden edge */
471  EXTDATA* extdata /**< extension data */
472  )
473 {
474  SCIP_Real bottleneckDist;
475  const SCIP_Bool hasSpecialDist = extSdIsNonTrivial(specialDist);
476 
477  assert(graph_knot_isInRange(graph, vertex_pathmarked));
478  assert(graph_knot_isInRange(graph, vertex_unmarked));
479 
480  if( !hasSpecialDist || vertex_pathmarked == vertex_unmarked )
481  {
482  return FALSE;
483  }
484 
485 #ifndef NDEBUG
486  bottleneckDist = bottleneckGetDist(graph, extdata, vertex_pathmarked, vertex_unmarked);
487 #else
488  bottleneckDist = bottleneckGetDist(graph, extdata, vertex_unmarked);
489 #endif
490 
491  SCIPdebugMessage("domination test %d->%d: sd=%f bottleneck=%f \n", vertex_pathmarked, vertex_unmarked, specialDist, bottleneckDist);
492 
493  if( LT(specialDist, bottleneckDist) )
494  {
495  return TRUE;
496  }
497  else if( LE(specialDist, bottleneckDist) )
498  {
499 #ifdef EXT_DOUBLESD_ALWAYS
500  assert(EQ(extreduce_extGetSdDouble(scip, graph, vertex_pathmarked, vertex_unmarked, extdata), specialDist));
501 #else
502  assert(LE(extreduce_extGetSdDouble(scip, graph, vertex_pathmarked, vertex_unmarked, extdata), specialDist));
503 #endif
504 
505  if( bottleneckIsEqualityDominated(scip, graph, specialDist, edge_forbidden,
506  vertex_pathmarked, vertex_unmarked, extdata) )
507  {
508  SCIPdebugMessage("...ruled out with equality! \n");
509  bottleneckMarkEqualityEdges(scip, graph, specialDist, vertex_pathmarked, vertex_unmarked, extdata);
510 
511  return TRUE;
512  }
513  }
514 
515  return FALSE;
516 }
517 
518 
519 /** As above, but for biased special distance */
521  SCIP* scip, /**< SCIP */
522  const GRAPH* graph, /**< graph data structure */
523  int vertex_pathmarked, /**< vertex for which bottleneck path to root has been marked */
524  int vertex_unmarked, /**< second vertex */
525  SCIP_Real specialDistBiased, /**< best computed special distance approximation (-1.0 if unknown) */
526  EXTDATA* extdata /**< extension data */
527  )
528 {
529  SCIP_Real bottleneckDist;
530  const SCIP_Bool hasSpecialDist = extSdIsNonTrivial(specialDistBiased);
531 
532  assert(graph_knot_isInRange(graph, vertex_pathmarked));
533  assert(graph_knot_isInRange(graph, vertex_unmarked));
534 
535  if( !hasSpecialDist || vertex_pathmarked == vertex_unmarked )
536  {
537  return FALSE;
538  }
539 
540 #ifndef NDEBUG
541  bottleneckDist = bottleneckGetDist(graph, extdata, vertex_pathmarked, vertex_unmarked);
542 #else
543  bottleneckDist = bottleneckGetDist(graph, extdata, vertex_unmarked);
544 #endif
545 
546  SCIPdebugMessage("biased domination test %d->%d: sd=%f bottleneck=%f \n", vertex_pathmarked, vertex_unmarked, specialDistBiased, bottleneckDist);
547 
548  if( LT(specialDistBiased, bottleneckDist) )
549  {
550  return TRUE;
551  }
552 
553  return FALSE;
554 }
555 
556 
557 /** Does a special distance approximation dominate the tree bottleneck distance of
558  * extension edge (i.e. its edge cost) or bottleneck distance between vertex_pathmarked
559  * and vertex_unmarked in the current tree.
560  * NOTE: makes additional checks in case of equality */
562  SCIP* scip, /**< SCIP */
563  const GRAPH* graph, /**< graph data structure */
564  int extedge, /**< edge along which we want to extend the tree */
565  int vertex_pathmarked, /**< vertex for which bottleneck path to root has been marked */
566  int vertex_unmarked, /**< second vertex */
567  SCIP_Real specialDist, /**< best computed special distance approximation (-1.0 if unknown) */
568  EXTDATA* extdata /**< extension data */
569  )
570 {
571  SCIP_Real bottleneckDist;
572  const SCIP_Bool hasSpecialDist = extSdIsNonTrivial(specialDist);
573 
574  assert(graph_edge_isInRange(graph, extedge));
575  assert(vertex_pathmarked == graph->tail[extedge]);
576 
577  if( !hasSpecialDist )
578  return FALSE;
579 
580  if( LT(specialDist, graph->cost[extedge]) )
581  {
582  return TRUE;
583  }
584  else if( LE(specialDist, graph->cost[extedge]) )
585  {
586  const int vertex1 = graph->head[extedge];
587 
588  if( bottleneckIsEqualityDominated(scip, graph, specialDist, extedge,
589  vertex1, vertex_unmarked, extdata) )
590  {
591  bottleneckMarkEqualityEdge(scip, graph, extedge, extdata);
592  SCIPdebugMessage("...ruled out with equality by single edge ! \n");
593 
594  return TRUE;
595  }
596  }
597 
598  if( vertex_pathmarked == vertex_unmarked )
599  return FALSE;
600 
601 #ifndef NDEBUG
602  bottleneckDist = bottleneckGetDist(graph, extdata, vertex_pathmarked, vertex_unmarked);
603 #else
604  bottleneckDist = bottleneckGetDist(graph, extdata, vertex_unmarked);
605 #endif
606 
607  SCIPdebugMessage("extedge domination test %d->%d: sd=%f bottleneck=%f \n", vertex_pathmarked, vertex_unmarked, specialDist, bottleneckDist);
608 
609  if( LT(specialDist, bottleneckDist) )
610  {
611  return TRUE;
612  }
613  else if( LE(specialDist, bottleneckDist) )
614  {
615  const int vertex1 = graph->head[extedge];
616 
617  assert(vertex1 != vertex_unmarked);
618  assert(vertex1 != vertex_pathmarked);
619 #ifdef EXT_DOUBLESD_ALWAYS
620  assert(EQ(extreduce_extGetSdDouble(scip, graph, vertex1, vertex_unmarked, extdata), specialDist));
621 #else
622  assert(LE(extreduce_extGetSdDouble(scip, graph, vertex1, vertex_unmarked, extdata), specialDist));
623 #endif
624 
625  if( bottleneckIsEqualityDominated(scip, graph, specialDist, extedge,
626  vertex1, vertex_unmarked, extdata) )
627  {
628  bottleneckMarkEqualityEdges(scip, graph, specialDist, vertex_pathmarked, vertex_unmarked, extdata);
629  SCIPdebugMessage("...ruled out with equality! \n");
630 
631  return TRUE;
632  }
633  }
634 
635  return FALSE;
636 }
637 
638 
639 /** as above, but for biased special distance */
641  SCIP* scip, /**< SCIP */
642  const GRAPH* graph, /**< graph data structure */
643  int extedge, /**< edge along which we want to extend the tree */
644  int vertex_pathmarked, /**< vertex for which bottleneck path to root has been marked */
645  int vertex_unmarked, /**< second vertex */
646  SCIP_Real specialDistBiased, /**< best computed biased special distance approximation (-1.0 if unknown) */
647  EXTDATA* extdata /**< extension data */
648  )
649 {
650  SCIP_Real bottleneckDist;
651  const SCIP_Bool hasSpecialDist = extSdIsNonTrivial(specialDistBiased);
652 
653  assert(graph_edge_isInRange(graph, extedge));
654  assert(vertex_pathmarked == graph->tail[extedge]);
655 
656  if( !hasSpecialDist )
657  return FALSE;
658 
659  if( LT(specialDistBiased, graph->cost[extedge]) )
660  return TRUE;
661 
662  if( vertex_pathmarked == vertex_unmarked )
663  return FALSE;
664 
665 #ifndef NDEBUG
666  bottleneckDist = bottleneckGetDist(graph, extdata, vertex_pathmarked, vertex_unmarked);
667 #else
668  bottleneckDist = bottleneckGetDist(graph, extdata, vertex_unmarked);
669 #endif
670 
671  SCIPdebugMessage("extedge biased domination test %d->%d: sd=%f bottleneck=%f \n", vertex_pathmarked, vertex_unmarked, specialDistBiased, bottleneckDist);
672 
673  if( LT(specialDistBiased, bottleneckDist) )
674  return TRUE;
675 
676  return FALSE;
677 }
678 
679 
680 /** Does a special distance approximation dominate the tree bottleneck distance between
681  * vertex_pathmarked and vertex_unmarked in the current tree?
682  * NOTE: makes additional checks in case of equality */
684  SCIP* scip, /**< SCIP */
685  const GRAPH* graph, /**< graph data structure */
686  int extedge, /**< edge for extension */
687  int edge2sibling, /**< edge to sibling of extedge head */
688  SCIP_Real specialDist, /**< best computed special distance approximation (FARAWAY if unknown) */
689  EXTDATA* extdata /**< extension data */
690 )
691 {
692  const SCIP_Bool hasSpecialDist = LT(specialDist, FARAWAY);
693 
694  assert(specialDist >= 0.0);
695  assert(extedge >= 0 && edge2sibling >= 0);
696  assert(extedge != edge2sibling);
697  assert(graph->tail[extedge] == graph->tail[edge2sibling]);
698 
699  if( !hasSpecialDist )
700  {
701  return FALSE;
702  }
703  else
704  {
705  const SCIP_Real* const edgecost = graph->cost;
706 
707  assert(GE(specialDist, 0.0));
708 
709  if( LT(specialDist, edgecost[edge2sibling]) )
710  return TRUE;
711 
712  if( LT(specialDist, edgecost[extedge]) )
713  return TRUE;
714 
715  if( LE(specialDist, edgecost[edge2sibling]) )
716  {
717  const int vertex1 = graph->head[edge2sibling];
718  const int vertex2 = graph->head[extedge];
719 
720  if( bottleneckIsEqualityDominated(scip, graph, specialDist, edge2sibling,
721  vertex1, vertex2, extdata) )
722  {
723  bottleneckMarkEqualityEdge(scip, graph, edge2sibling, extdata);
724  SCIPdebugMessage("...ruled out edge1 with equality! \n");
725 
726  return TRUE;
727  }
728  }
729 
730  if( LE(specialDist, edgecost[extedge]) )
731  {
732  const int vertex1 = graph->head[edge2sibling];
733  const int vertex2 = graph->head[extedge];
734 
735  if( bottleneckIsEqualityDominated(scip, graph, specialDist, extedge,
736  vertex1, vertex2, extdata) )
737  {
738  bottleneckMarkEqualityEdge(scip, graph, extedge, extdata);
739  SCIPdebugMessage("...ruled out edge2 with equality! \n");
740 
741  return TRUE;
742  }
743  }
744  }
745 
746  return FALSE;
747 }
748 
749 
750 /** as above, but for biased special distance */
752  SCIP* scip, /**< SCIP */
753  const GRAPH* graph, /**< graph data structure */
754  int extedge, /**< edge for extension */
755  int edge2sibling, /**< edge to sibling of extedge head */
756  SCIP_Real specialDistBiased, /**< best computed special distance approximation (FARAWAY if unknown) */
757  EXTDATA* extdata /**< extension data */
758 )
759 {
760  const SCIP_Bool hasSpecialDist = LT(specialDistBiased, FARAWAY);
761 
762  assert(GE(specialDistBiased, 0.0));
763  assert(extedge >= 0 && edge2sibling >= 0);
764  assert(extedge != edge2sibling);
765  assert(graph->tail[extedge] == graph->tail[edge2sibling]);
766 
767  if( !hasSpecialDist )
768  {
769  return FALSE;
770  }
771  else
772  {
773  const SCIP_Real* const edgecost = graph->cost;
774 
775  if( LT(specialDistBiased, edgecost[edge2sibling]) )
776  return TRUE;
777 
778  if( LT(specialDistBiased, edgecost[extedge]) )
779  return TRUE;
780  }
781 
782  return FALSE;
783 }
784 
785 
786 /** checks tree bottleneck distances to non-leaves of the tree that were marked before */
788  SCIP* scip, /**< SCIP */
789  const GRAPH* graph, /**< graph data structure */
790  int edge2neighbor, /**< the edge from the tree to the neighbor */
791  EXTDATA* extdata, /**< extension data */
792  SCIP_Bool* ruledOut /**< could the extension be ruled out */
793 )
794 {
795  const PCDATA* const pcdata = extdata->pcdata;
796  const int* const pcSdCands = pcdata->pcSdCands;
797  const int* const tree_deg = extdata->tree_deg;
798  const int nPcSdCands = pcdata->nPcSdCands;
799  const int neighbor = graph->head[edge2neighbor];
800  const int neighbor_base = graph->tail[edge2neighbor];
801 
802  assert(pcSdCands);
803  assert(ruledOut);
804  assert(!(*ruledOut));
805  assert(nPcSdCands >= 0);
806 
807  /* also check non-leaves */
808  for( int c = 0; c < nPcSdCands; c++ )
809  {
810  SCIP_Real specialDist;
811  const int cand = pcSdCands[c];
812 
813  assert(cand >= 0 && cand < graph->knots);
814 
815  /* leaf, or not contained? */
816  if( tree_deg[cand] <= 1 )
817  continue;
818 
819  specialDist = extreduce_extGetSd(scip, graph, neighbor, cand, extdata);
820 
821  if( extreduce_bottleneckWithExtedgeIsDominated(scip, graph, edge2neighbor, neighbor_base, cand, specialDist, extdata) )
822  {
823  SCIPdebugMessage("---non-leaf bottleneck rule-out---\n");
824  *ruledOut = TRUE;
825 
826  return;
827  }
828  }
829 }
830 
831 
832 /** checks tree bottleneck distances to non-leaves of the tree */
834  SCIP* scip, /**< SCIP */
835  const GRAPH* graph, /**< graph data structure */
836  int edge2neighbor, /**< the edge from the tree to the neighbor */
837  EXTDATA* extdata, /**< extension data */
838  SCIP_Bool* ruledOut /**< could the extension be ruled out */
839 )
840 {
841  const int* const innerNodes = extdata->tree_innerNodes;
842  const int nInnerNodes = extdata->tree_ninnerNodes;
843  const int neighbor = graph->head[edge2neighbor];
844  const int neighbor_base = graph->tail[edge2neighbor];
845 
846  assert(ruledOut);
847  assert(!(*ruledOut));
848 
849  /* also check non-leaves */
850  for( int i = 0; i < nInnerNodes; i++ )
851  {
852  SCIP_Real specialDist;
853  const int node = innerNodes[i];
854  assert(graph_knot_isInRange(graph, node));
855  assert(extdata->tree_deg[node] > 1);
856  assert(node != neighbor_base);
857 
858  specialDist = extreduce_extGetSd(scip, graph, neighbor, node, extdata);
859 
860  if( extreduce_bottleneckWithExtedgeIsDominated(scip, graph, edge2neighbor, neighbor_base, node, specialDist, extdata) )
861  {
862  SCIPdebugMessage("---non-leaf bottleneck rule-out---\n");
863  *ruledOut = TRUE;
864  return;
865  }
866  }
867 }
868 
869 /**@} */
SCIP_Bool extreduce_bottleneckWithExtedgeIsDominated(SCIP *scip, const GRAPH *graph, int extedge, int vertex_pathmarked, int vertex_unmarked, SCIP_Real specialDist, EXTDATA *extdata)
void extreduce_bottleneckMarkRootPath(const GRAPH *graph, int vertex, EXTDATA *extdata)
static SCIP_Bool extInitialCompIsGenStar(const EXTDATA *extdata)
int *RESTRICT head
Definition: graphdefs.h:224
#define Is_term(a)
Definition: graphdefs.h:102
int *const pcSdCands
void extreduce_bottleneckCheckNonLeaves(SCIP *scip, const GRAPH *graph, int edge2neighbor, EXTDATA *extdata, SCIP_Bool *ruledOut)
SCIP_Bool extreduce_bottleneckIsDominatedBiased(SCIP *scip, const GRAPH *graph, int vertex_pathmarked, int vertex_unmarked, SCIP_Real specialDistBiased, EXTDATA *extdata)
#define FALSE
Definition: def.h:87
#define TRUE
Definition: def.h:86
includes various files containing graph methods used for Steiner tree problems
static SCIP_Bool extInitialCompIsEdge(const EXTDATA *extdata)
void extreduce_bottleneckUnmarkRootPath(const GRAPH *graph, int vertex, EXTDATA *extdata)
static SCIP_Real bottleneckGetDist(const GRAPH *graph, const EXTDATA *extdata, int vertex_pathmarked, int vertex_unmarked)
#define EAT_LAST
Definition: graphdefs.h:58
#define SCIPdebugMessage
Definition: pub_message.h:87
#define FARAWAY
Definition: graphdefs.h:89
static void bottleneckMarkEqualityPath(SCIP *scip, const GRAPH *graph, int path_start, int path_end, EXTDATA *extdata)
SCIP_Bool extreduce_bottleneckToSiblingIsDominatedBiased(SCIP *scip, const GRAPH *graph, int extedge, int edge2sibling, SCIP_Real specialDistBiased, EXTDATA *extdata)
SCIP_Real extreduce_distDataGetSdDoubleForbiddenEq(SCIP *, const GRAPH *, SCIP_Real, int, int, int, EXTDATA *)
SCIP_Bool graph_pc_termIsNonLeafTerm(const GRAPH *, int)
int *RESTRICT oeat
Definition: graphdefs.h:231
This file implements extended reduction techniques for several Steiner problems.
#define LE(a, b)
Definition: portab.h:83
#define GE(a, b)
Definition: portab.h:85
static SCIP_Real extSdIsNonTrivial(SCIP_Real specialDist)
int *const tree_parentNode
int *const tree_innerNodes
SCIP_Real * prize
Definition: graphdefs.h:210
SCIP_Real extreduce_extGetSdDouble(SCIP *, const GRAPH *, int, int, EXTDATA *)
SCIP_Real extreduce_extGetSd(SCIP *, const GRAPH *, int, int, EXTDATA *)
#define EQ(a, b)
Definition: portab.h:79
static void bottleneckMarkEqualityEdge(SCIP *scip, const GRAPH *g, int edge, EXTDATA *extdata)
#define LT(a, b)
Definition: portab.h:81
SCIP_Bool extreduce_bottleneckIsDominated(SCIP *scip, const GRAPH *graph, int vertex_pathmarked, int vertex_unmarked, SCIP_Real specialDist, int edge_forbidden, EXTDATA *extdata)
SCIP_Bool extreduce_bottleneckWithExtedgeIsDominatedBiased(SCIP *scip, const GRAPH *graph, int extedge, int vertex_pathmarked, int vertex_unmarked, SCIP_Real specialDistBiased, EXTDATA *extdata)
#define SCIP_Bool
Definition: def.h:84
includes extended reductions definitions and inline methods used for Steiner tree problems ...
SCIP_Bool *const sdeq_edgesIsForbidden
int *RESTRICT tail
Definition: graphdefs.h:223
#define MAX(x, y)
Definition: tclique_def.h:83
static void bottleneckMarkEqualityEdges(SCIP *scip, const GRAPH *graph, SCIP_Real dist_eq, int vertex_pathmarked, int vertex_unmarked, EXTDATA *extdata)
SCIP_Real *const tree_bottleneckDistNode
int *RESTRICT term
Definition: graphdefs.h:196
PCDATA *const pcdata
void graph_edge_printInfo(const GRAPH *, int)
Definition: graph_stats.c:133
SCIP_Bool graph_pc_isPc(const GRAPH *)
Portable definitions.
SCIP_Bool sdeq_hasForbiddenEdges
SCIP_Bool graph_pc_knotIsDummyTerm(const GRAPH *, int)
SCIP_Real * cost
Definition: graphdefs.h:221
SCIP_Bool graph_edge_isInRange(const GRAPH *, int)
Definition: graph_stats.c:110
static SCIP_Bool ruledOut(SCIP *scip, const GRAPH *graph, EXTDATA *extdata)
static SCIP_Bool extIsAtInitialGenStar(const EXTDATA *extdata)
static SCIP_Bool bottleneckIsEqualityDominated(SCIP *scip, const GRAPH *g, SCIP_Real dist_eq, int edge_forbidden, int vertex1, int vertex2, EXTDATA *extdata)
#define SCIP_Real
Definition: def.h:177
int *RESTRICT outbeg
Definition: graphdefs.h:204
SCIP_Bool graph_knot_isInRange(const GRAPH *, int)
Definition: graph_node.c:52
#define UNKNOWN
Definition: sepa_mcf.c:4095
int *const tree_deg
#define StpVecPushBack(scip, vec, value)
Definition: stpvector.h:167
SCIP_Bool extreduce_bottleneckToSiblingIsDominated(SCIP *scip, const GRAPH *graph, int extedge, int edge2sibling, SCIP_Real specialDist, EXTDATA *extdata)
void extreduce_bottleneckCheckNonLeaves_pc(SCIP *scip, const GRAPH *graph, int edge2neighbor, EXTDATA *extdata, SCIP_Bool *ruledOut)
SCIP_Real *const tree_parentEdgeCost