Scippy

SCIP

Solving Constraint Integer Programs

reduce_sd.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 reduce_sd.c
17  * @brief special distance (bottleneck distance) reduction methods for Steiner problems
18  * @author Daniel Rehfeldt
19  *
20  * This file encompasses various special distance (aka bottleneck distance) based reduction methods
21  * for Steiner problems.
22  *
23  * A list of all interface methods can be found in reduce.h.
24  *
25  *
26  */
27 
28 //#define SCIP_DEBUG
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <assert.h>
34 #include "graph.h"
35 #include "reduce.h"
36 #include "misc_stp.h"
37 #include "probdata_stp.h"
38 #include "scip/scip.h"
39 #include "portab.h"
40 
41 
42 #define STP_BD_MAXDEGREE 4
43 #define STP_BD_MAXDNEDGES 6
44 #define STP_SDWALK_MAXNPREVS 8
45 
46 
47 /*
48  * local methods
49  */
50 
51 /** initializes data needed for SD star tests */
52 static
54  SCIP* scip, /**< SCIP data structure */
55  const GRAPH* g, /**< graph data structure */
56  int edgelimit, /**< limit */
57  DIJK** dijkdata, /**< data to be allocated */
58  int*RESTRICT* star_base, /**< data to be allocated */
59  SCIP_Bool*RESTRICT* edge_deletable /**< data to be allocated */
60 )
61 {
62  const int nnodes = graph_get_nNodes(g);
63  const int nedges = graph_get_nEdges(g);
64  int* RESTRICT star_base_d;
65  SCIP_Bool* RESTRICT edge_deletable_d;
66 
67  assert(!graph_pc_isPcMw(g) || !g->extended);
68 
69  SCIP_CALL( graph_dijkLimited_init(scip, g, dijkdata) );
70  (*dijkdata)->edgelimit = edgelimit;
71 
72 #ifndef NDEBUG
73  {
74  SCIP_Real* dist = (*dijkdata)->node_distance;
75  STP_Bool* visited = (*dijkdata)->node_visited;
76  assert(graph_heap_isClean((*dijkdata)->dheap));
77 
78  for( int i = 0; i < nnodes; i++ )
79  {
80  assert(!visited[i]);
81  assert(EQ(dist[i], FARAWAY));
82  }
83  }
84 #endif
85 
86  SCIP_CALL( SCIPallocBufferArray(scip, star_base, nnodes) );
87  SCIP_CALL( SCIPallocBufferArray(scip, edge_deletable, nedges / 2) );
88 
89  edge_deletable_d = *edge_deletable;
90  for( int e = 0; e < nedges / 2; e++ )
91  edge_deletable_d[e] = FALSE;
92 
93  star_base_d = *star_base;
94  for( int i = 0; i < nnodes; i++ )
95  star_base_d[i] = SDSTAR_BASE_UNSET;
96 
97  return SCIP_OKAY;
98 }
99 
100 
101 /** finalizes SD star tests */
102 static
104  SCIP* scip, /**< SCIP data structure */
105  GRAPH* g, /**< graph data structure */
106  DIJK** dijkdata, /**< data to be freed */
107  int*RESTRICT* star_base, /**< data to be freed */
108  SCIP_Bool*RESTRICT* edge_deletable /**< data to be freed */
109 )
110 {
111 #ifndef NDEBUG
112  const int nedges = graph_get_nEdges(g);
113  DCSR* dcsr = g->dcsr_storage;
114  SCIP_Bool* RESTRICT edge_deletable_d = *edge_deletable;
115 
116  for( int e = 0; e < nedges / 2; e++ )
117  {
118  if( edge_deletable_d[e] )
119  assert(dcsr->id2csredge[e * 2] == -1);
120  else if( g->oeat[e * 2] != EAT_FREE )
121  assert(dcsr->id2csredge[e * 2] != -1 || !g->mark[g->tail[e * 2]] || !g->mark[g->head[e * 2]]);
122  }
123 #endif
124 
125  graph_edge_delBlocked(scip, g, *edge_deletable, TRUE);
126  SCIPfreeBufferArray(scip, edge_deletable);
127  SCIPfreeBufferArray(scip, star_base);
128 
129  graph_dijkLimited_free(scip, dijkdata);
130 }
131 
132 
133 /** resets data needed for SD star tests */
134 static inline
136  int nnodes, /**< number of nodes */
137  int nvisits, /**< number of visits */
138  const int* visitlist, /**< array of visited nodes */
139  int* RESTRICT star_base, /**< star-bases */
140  SCIP_Real* RESTRICT dist, /**< node distances */
141  STP_Bool* RESTRICT visited, /**< visit mark */
142  DHEAP* RESTRICT dheap /**< Dijkstra heap */
143 )
144 {
145  int* const state = dheap->position;
146 
147  for( int k = 0; k < nvisits; k++ )
148  {
149  const int node = visitlist[k];
150  visited[node] = FALSE;
151  dist[node] = FARAWAY;
152  state[node] = UNKNOWN;
153  star_base[node] = SDSTAR_BASE_UNSET;
154  }
155 
156  graph_heap_clean(FALSE, dheap);
157 
158 #ifndef NDEBUG
159  for( int k = 0; k < nnodes; k++ )
160  {
161  assert(star_base[k] == SDSTAR_BASE_UNSET);
162  assert(visited[k] == FALSE);
163  assert(state[k] == UNKNOWN);
164  assert(dist[k] == FARAWAY);
165  }
166 #endif
167 }
168 
169 
170 /** checks node */
171 static
173  SCIP* scip, /**< SCIP data structure */
174  int node, /**< node to process */
175  SCIP_Bool usestrongreds, /**< allow strong reductions? */
176  const SDPROFIT* sdprofit, /**< SD profit */
177  GRAPH* g, /**< graph data structure */
178  DIJK* dijkdata, /**< data */
179  int* RESTRICT star_base, /**< data to be freed */
180  SCIP_Bool *RESTRICT edge_deletable, /**< data to be freed */
181  int* nelims /**< point to store number of deleted edges */
182 )
183 {
184  const int nnodes = graph_get_nNodes(g);
185  SCIP_Bool runloop = TRUE;
186  DCSR *dcsr;
187  RANGE *RESTRICT range_csr;
188  int *RESTRICT head_csr;
189  int *RESTRICT edgeid_csr;
190 
191  dcsr = g->dcsr_storage;
192  range_csr = dcsr->range;
193  head_csr = dcsr->head;
194  edgeid_csr = dcsr->edgeid;
195 
196  assert(g->mark[node]);
197 
198  while( runloop )
199  {
200  SCIP_Bool success;
201  const int start = range_csr[node].start;
202 
203  /* not more than one edge? */
204  if( range_csr[node].end - start <= 1 )
205  break;
206 
207  runloop = FALSE;
208 
209  /* do the actual star run */
210  SCIP_CALL( graph_sdStarBiased(scip, g, sdprofit, node, star_base, dijkdata, &success) );
211 
212  if( success )
213  {
214  int enext;
215 
216  /* check all star nodes (neighbors of i) */
217  for( int e = start; e < range_csr[node].end; e = enext )
218  {
219  const int starnode = head_csr[e];
220  const int starbase = star_base[starnode];
221  assert(star_base[starnode] >= 0);
222  assert(SCIPisLE(scip, dijkdata->node_distance[starnode], dcsr->cost[e]));
223  assert(star_base[starnode] == starnode || star_base[starnode] >= 0);
224 
225  enext = e + 1;
226 
227  /* shorter path to current star node found? */
228  if( starnode != starbase )
229  {
230  assert(star_base[starbase] != SDSTAR_BASE_UNSET);
231 
232  if( !usestrongreds && SCIPisEQ(scip, dijkdata->node_distance[starnode], dcsr->cost[e]) )
233  continue;
234 
235  star_base[starnode] = SDSTAR_BASE_KILLED;
236  edge_deletable[edgeid_csr[e] / 2] = TRUE;
237  graph_dcsr_deleteEdgeBi(scip, dcsr, e);
238 
239  (*nelims)++;
240  enext--;
241  }
242  } /* traverse star nodes */
243  } /* if success */
244 
245  sdStarReset(nnodes, dijkdata->nvisits, dijkdata->visitlist, star_base, dijkdata->node_distance, dijkdata->node_visited, dijkdata->dheap);
246  }
247 
248  return SCIP_OKAY;
249 }
250 
251 /** resets data needed for SD walk tests */
252 static inline
254  int nnodes,
255  int nvisits,
256  const int* visitlist,
257  SCIP_Real* RESTRICT dist,
258  int* RESTRICT state,
259  STP_Bool* RESTRICT visited
260 )
261 {
262  for( int k = 0; k < nvisits; k++ )
263  {
264  const int node = visitlist[k];
265  visited[node] = FALSE;
266  dist[node] = FARAWAY;
267  state[node] = UNKNOWN;
268  }
269 
270 #ifndef NDEBUG
271  for( int k = 0; k < nnodes; k++ )
272  {
273  assert(visited[k] == FALSE);
274  assert(state[k] == UNKNOWN);
275  assert(dist[k] == FARAWAY);
276  }
277 #endif
278 }
279 
280 static inline
282  int nnodes,
283  int nvisits,
284  const int* visitlist,
285  SCIP_Real* RESTRICT dist,
286  int* RESTRICT nprevterms,
287  int* RESTRICT state,
288  STP_Bool* RESTRICT visited
289 )
290 {
291  for( int k = 0; k < nvisits; k++ )
292  {
293  const int node = visitlist[k];
294  visited[node] = FALSE;
295  dist[node] = FARAWAY;
296  state[node] = UNKNOWN;
297  nprevterms[node] = 0;
298  }
299 
300 #ifndef NDEBUG
301  for( int k = 0; k < nnodes; k++ )
302  {
303  assert(visited[k] == FALSE);
304  assert(state[k] == UNKNOWN);
305  assert(dist[k] == FARAWAY);
306  assert(nprevterms[k] == 0);
307  }
308 #endif
309 }
310 
311 static inline
313  int nnodes,
314  int nvisits,
315  const int* visitlist,
316  SCIP_Real* dist,
317  int* nprevterms,
318  int* nprevNPterms,
319  int* nprevedges,
320  int* state,
321  STP_Bool* visited
322 )
323 {
324  for( int k = 0; k < nvisits; k++ )
325  {
326  const int node = visitlist[k];
327  visited[node] = FALSE;
328  dist[node] = FARAWAY;
329  state[node] = UNKNOWN;
330  nprevterms[node] = 0;
331  nprevNPterms[node] = 0;
332  nprevedges[node] = 0;
333  }
334 
335 #ifndef NDEBUG
336  for( int k = 0; k < nnodes; k++ )
337  {
338  assert(visited[k] == FALSE);
339  assert(state[k] == UNKNOWN);
340  assert(dist[k] == FARAWAY);
341  assert(nprevterms[k] == 0);
342  assert(nprevNPterms[k] == 0);
343  assert(nprevedges[k] == 0);
344  }
345 #endif
346 }
347 
348 
349 /* can edge be deleted in SD test in case of equality? If so, 'forbidden' array is adapted */
350 static
352  SCIP* scip,
353  GRAPH* g,
354  PATH* path,
355  int* vbase,
356  int* forbidden,
357  int tpos,
358  int hpos,
359  int tail,
360  int head,
361  int edge,
362  int nnodes
363  )
364 {
365  int e;
366 
367  assert(g != NULL);
368  assert(path != NULL);
369  assert(scip != NULL);
370  assert(vbase != NULL);
371  assert(forbidden != NULL);
372 
373  assert(tpos >= 0);
374  assert(hpos >= 0);
375  assert(tail >= 0);
376  assert(head >= 0);
377  assert(edge >= 0);
378  assert(nnodes >= 0);
379 
380  /* edge between non-terminals */
381  if( !Is_term(g->term[tail]) && !Is_term(g->term[head]) )
382  return TRUE;
383 
384  /* has edge been marked as forbidden? */
385  if( forbidden[edge] )
386  return FALSE;
387 
388  /* edge between a terminal and a non terminal */
389  if( !Is_term(g->term[tail]) || !Is_term(g->term[head]) )
390  {
391 
392  /* check whether edge is used in shortest path */
393 
394  if( !Is_term(g->term[tail]) && Is_term(g->term[head]) )
395  {
396  e = path[tail + tpos * nnodes].edge;
397 
398  if( g->ieat[e] == EAT_FREE )
399  return TRUE;
400 
401  assert(g->head[e] == tail);
402 
403  if( g->tail[e] == head )
404  return FALSE;
405  }
406  else if( Is_term(g->term[tail]) && !Is_term(g->term[head]) )
407  {
408  e = path[head + hpos * nnodes].edge;
409 
410  if( g->ieat[e] == EAT_FREE )
411  return TRUE;
412 
413  assert(g->head[e] == head);
414 
415  if( g->tail[e] == tail )
416  return FALSE;
417  }
418  }
419 
420  /* update forbidden edges todo check bottleneck distance between terminals, and don't delete if distance is higher than ecost */
421 
422  if( Is_term(g->term[head]) )
423  {
424  SCIP_Real ecost = g->cost[edge];
425  for( e = g->outbeg[tail]; e != EAT_LAST; e = g->oeat[e] )
426  {
427  assert(e >= 0);
428 
429  if( SCIPisEQ(scip, g->cost[e], ecost) )
430  {
431  if( !(forbidden[e]) && Is_term(g->term[g->head[e]]) )
432  {
433  forbidden[e] = TRUE;
434  forbidden[flipedge(e)] = TRUE;
435  }
436  }
437  }
438  }
439 
440  if( Is_term(g->term[tail]) )
441  {
442  SCIP_Real ecost = g->cost[edge];
443  for( e = g->outbeg[head]; e != EAT_LAST; e = g->oeat[e] )
444  {
445  assert(e >= 0);
446 
447  if( SCIPisEQ(scip, g->cost[e], ecost) )
448  {
449  if( !(forbidden[e]) && Is_term(g->term[g->head[e]]) )
450  {
451  forbidden[e] = TRUE;
452  forbidden[flipedge(e)] = TRUE;
453  }
454  }
455  }
456  }
457 
458  return TRUE;
459 }
460 
461 
462 /** gets distances to close terminals */
463 static
465  SCIP* scip,
466  const PATH* vnoi,
467  SCIP_Real* termdist,
468  SCIP_Real ecost,
469  const int* vbase,
470  int* neighbterms,
471  int i,
472  int nnodes
473  )
474 {
475  int k;
476  int pos = i;
477  int nnterms = 0;
478 
479  assert(scip != NULL);
480  assert(vnoi != NULL);
481  assert(vbase != NULL);
482  assert(termdist != NULL);
483  assert(neighbterms != NULL);
484 
485  for( k = 0; k < 4; k++ )
486  {
487  if( SCIPisLT(scip, vnoi[pos].dist, ecost) )
488  {
489  neighbterms[nnterms] = vbase[pos];
490  termdist[nnterms++] = vnoi[pos].dist;
491  }
492  else
493  {
494  break;
495  }
496  pos += nnodes;
497  }
498 
499  return nnterms;
500 }
501 
502 static
504  SCIP* scip,
505  const GRAPH* g,
506  const GRAPH* netgraph,
507  SCIP_Real* termdist,
508  SCIP_Real ecost,
509  int* neighbterms,
510  int* nodesid,
511  int* nodesorg,
512  int i
513 )
514 {
515  int nnterms = 0;
516 
517  for( int k = 0; k < 4; k++ )
518  neighbterms[k] = UNKNOWN;
519 
520  /* get three nearest terms */
521  for( int ne = netgraph->outbeg[nodesid[i]]; ne != EAT_LAST; ne = netgraph->oeat[ne] )
522  {
523  if( SCIPisLT(scip, netgraph->cost[ne], ecost) )
524  {
525  const SCIP_Real necost = netgraph->cost[ne];
526  int j = nodesorg[netgraph->head[ne]];
527 
528  assert(Is_term(g->term[j]));
529  assert(j != i);
530 
531  if( nnterms < 4 )
532  nnterms++;
533  for( int k = 0; k < 4; k++ )
534  {
535  if( neighbterms[k] == UNKNOWN || SCIPisGT(scip, termdist[k], necost) )
536  {
537  for( int l = 3; l > k; l-- )
538  {
539  neighbterms[l] = neighbterms[l - 1];
540  termdist[l] = termdist[l - 1];
541  }
542  neighbterms[k] = j;
543  termdist[k] = necost;
544  break;
545  }
546  }
547  }
548  }
549 
550  return nnterms;
551 }
552 
553 static
555  SCIP* scip,
556  PATH* vnoi,
557  SCIP_Real* termdist,
558  SCIP_Real ecost,
559  int* vbase,
560  int* neighbterms,
561  int i,
562  int nnodes
563  )
564 {
565  int k;
566  int pos = i;
567  int nnterms = 0;
568 
569  assert(scip != NULL);
570  assert(vnoi != NULL);
571  assert(vbase != NULL);
572  assert(termdist != NULL);
573  assert(neighbterms != NULL);
574 
575  for( k = 0; k < 4; k++ )
576  {
577  if( SCIPisLE(scip, vnoi[pos].dist, ecost) )
578  {
579  neighbterms[nnterms] = vbase[pos];
580  termdist[nnterms++] = vnoi[pos].dist;
581  }
582  else
583  {
584  break;
585  }
586  pos += nnodes;
587  }
588 
589  return nnterms;
590 }
591 
592 
593 /** bias DCSR costs for PCMW */
594 static
596  SCIP* scip, /**< SCIP data structure */
597  const GRAPH* g, /**< graph data structure */
598  SCIP_Bool biasreversed, /**< bias reversed */
599  SCIP_Real* costbiased, /**< biased edge cost */
600  SCIP_Real* mincost_in /**< vertex distances */
601  )
602 {
603  DCSR* dcsr;
604  RANGE* range_csr;
605  int* head_csr;
606  SCIP_Real* cost_csr;
607  const int nnodes = g->knots;
608 
609  assert(g && scip && g->dcsr_storage);
610  assert(graph_pc_isPcMw(g) && !g->extended);
611 
612  dcsr = g->dcsr_storage;
613  range_csr = dcsr->range;
614  head_csr = dcsr->head;
615  cost_csr = dcsr->cost;
616 
617  assert(g->edges >= dcsr->nedges);
618 
619  BMScopyMemoryArray(costbiased, cost_csr, dcsr->nedges);
620 
621  /* compute minimum incident edge cost per vertex */
622 
623  for( int k = 0; k < nnodes; k++ )
624  {
625  if( Is_term(g->term[k]) && g->mark[k] )
626  mincost_in[k] = g->prize[k];
627  else
628  mincost_in[k] = 0.0;
629  }
630 
631  for( int k = 0; k < nnodes; k++ )
632  {
633  if( g->mark[k] )
634  {
635  const int end = range_csr[k].end;
636 
637  for( int e = range_csr[k].start; e < end; e++ )
638  {
639  const int head = head_csr[e];
640 
641  if( Is_term(g->term[head]) )
642  {
643  assert(g->mark[head]);
644 
645  assert(LT(costbiased[e], FARAWAY) && costbiased[e] > 0.0);
646 
647  if( costbiased[e] < mincost_in[head] )
648  mincost_in[head] = costbiased[e];
649  }
650  }
651  }
652  }
653 
654  /* change edge costs */
655 
656  if( biasreversed )
657  {
658  for( int k = 0; k < nnodes; k++ )
659  {
660  if( g->mark[k] && Is_term(g->term[k]) )
661  {
662  const int end = range_csr[k].end;
663 
664  for( int e = range_csr[k].start; e < end; e++ )
665  {
666  assert(g->mark[head_csr[e]]);
667  costbiased[e] -= mincost_in[k];
668 
669  assert(!SCIPisNegative(scip, costbiased[e]));
670 
671  }
672  }
673  }
674  }
675  else
676  {
677  for( int k = 0; k < nnodes; k++ )
678  {
679  if( g->mark[k] )
680  {
681  const int end = range_csr[k].end;
682 
683  for( int e = range_csr[k].start; e < end; e++ )
684  {
685  const int head = head_csr[e];
686 
687  if( Is_term(g->term[head]) )
688  {
689  assert(g->mark[head]);
690  costbiased[e] -= mincost_in[head];
691 
692  assert(!SCIPisNegative(scip, costbiased[e]));
693  }
694  }
695  }
696  }
697  }
698 }
699 
700 
701 /** get special distance to a single edge */
702 static
704  SCIP* scip, /**< SCIP data structure */
705  GRAPH* g, /**< graph structure */
706  SDGRAPH* sdgraph, /**< special distance graph */
707  PATH* vnoi, /**< path structure */
708  SCIP_Real sd_initial, /**< initial sd or -1.0 */
709  int* vbase, /**< bases for nearest terminals */
710  int i, /**< first vertex */
711  int i2, /**< second vertex */
712  int limit /**< limit for incident edges to consider */
713  )
714 {
715  SCIP_Real sd;
716  int nnterms1;
717  int nnterms2;
718  SCIP_Real termdist1[4];
719  SCIP_Real termdist2[4];
720  int neighbterms1[4];
721  int neighbterms2[4];
722  const int nnodes = graph_get_nNodes(g);
723 
724  assert(scip != NULL);
725  assert(g != NULL);
726 
727  if( sd_initial >= 0.0 )
728  sd = sd_initial;
729  else
730  sd = FARAWAY;
731 
732  /* compare restricted sd with edge cost (if existing) */
733  for( int e = g->outbeg[i], l = 0; (l <= limit) && (e != EAT_LAST); e = g->oeat[e], l++ )
734  {
735  if( g->head[e] == i2 )
736  {
737  if( g->cost[e] < sd )
738  sd = g->cost[e];
739  break;
740  }
741  }
742 
743  /* is i a terminal? If not, get three closest terminals of distance smaller sd */
744  if( Is_term(g->term[i]) )
745  {
746  nnterms1 = 1;
747  termdist1[0] = 0.0;
748  neighbterms1[0] = i;
749  }
750  else
751  {
752  nnterms1 = getcloseterms(scip, vnoi, termdist1, sd, vbase, neighbterms1, i, nnodes);
753 
754  if( nnterms1 == 0 )
755  return sd;
756  }
757 
758  /* is i2 a terminal? If not, get three closest terminals of distance smaller sd */
759  if( Is_term(g->term[i2]) )
760  {
761  nnterms2 = 1;
762  termdist2[0] = 0.0;
763  neighbterms2[0] = i2;
764  }
765  else
766  {
767  /* get closest terminals of distance smaller sd */
768  nnterms2 = getcloseterms(scip, vnoi, termdist2, sd, vbase, neighbterms2, i2, nnodes);
769 
770  if( nnterms2 == 0 )
771  return sd;
772  }
773 
774  for( int j = 0; j < nnterms1; j++ )
775  {
776  const int tj = neighbterms1[j];
777  assert(tj >= 0);
778 
779  for( int k = 0; k < nnterms2; k++ )
780  {
781  SCIP_Real maxdist;
782  const int tk = neighbterms2[k];
783 
784  assert(Is_term(g->term[tk]));
785  assert(Is_term(g->term[tj]));
786  assert(tk >= 0);
787 
788  maxdist = MAX(termdist1[j], termdist2[k]);
789 
790  if( tj != tk )
791  {
792  SCIP_Real dist;
793 
794  if( GE(maxdist, sd) )
795  continue;
796 
797  dist = reduce_sdgraphGetSd(tj, tk, sdgraph);
798 
799  assert(SCIPisGT(scip, dist, 0.0));
800  if( GT(dist, maxdist) )
801  maxdist = dist;
802  }
803 
804  if( LT(maxdist, sd) )
805  sd = maxdist;
806  } /* k < nnterms2 */
807  } /* j < nnterms1 */
808 
809  return sd;
810 }
811 
812 
813 /** gets special distance to a pair of nodes */
814 static inline
816  const GRAPH* g, /**< graph structure */
817  int i, /**< first vertex */
818  int i2, /**< second vertex */
819  SCIP_Real sd_upper, /**< upper bound on special distance that is accepted (can be FARAWAY) */
820  SCIP_Real sd_sufficient, /**< bound below which to terminate (can be 0.0) */
821  SCIP_Bool onlyIntermedTerms, /**< allow only paths with intermediate terms */
822  SD* sddata /**< SD */
823  )
824 {
825  SCIP_Real termdist1[4];
826  SCIP_Real termdist2[4];
827  int neighbterms1[4];
828  int neighbterms2[4];
829  SDGRAPH* sdgraph;
830  SCIP_Real sd = sd_upper;
831  int nnterms1;
832  int nnterms2;
833  const SCIP_Bool terminateEarly = GT(sd_sufficient, 0.0);
834 
835  assert(g && sddata);
836  assert(i != i2);
837 
838  sdgraph = sddata->sdgraph;
839  assert(sdgraph);
840 
841 #ifndef NDEBUG
842  if( onlyIntermedTerms )
843  assert(!(Is_term(g->term[i]) && Is_term(g->term[i2])));
844 #endif
845 
846  /* get closest terminals of distance strictly smaller than 'sd' */
847  graph_tpathsGet4CloseTerms(g, sddata->terminalpaths, i, sd, neighbterms1, NULL, termdist1, &nnterms1);
848  if( nnterms1 == 0 )
849  return sd;
850 
851  graph_tpathsGet4CloseTerms(g, sddata->terminalpaths, i2, sd, neighbterms2, NULL, termdist2, &nnterms2);
852  if( nnterms2 == 0 )
853  return sd;
854 
855  for( int j = 0; j < nnterms1; j++ )
856  {
857  const int tj = neighbterms1[j];
858  assert(tj >= 0);
859 
860  for( int k = 0; k < nnterms2; k++ )
861  {
862  SCIP_Real sd_jk = MAX(termdist1[j], termdist2[k]);
863  const int tk = neighbterms2[k];
864 
865  assert(Is_term(g->term[tk]));
866  assert(Is_term(g->term[tj]));
867  assert(tk >= 0);
868 
869  if( GE(sd_jk, sd) )
870  {
871  continue;
872  }
873 
874  if( onlyIntermedTerms )
875  {
876  if( tj == i2 || tk == i )
877  {
878  assert(tj == tk);
879  assert(EQ(termdist1[j], 0.0) || EQ(termdist2[k], 0.0));
880  assert(Is_term(g->term[i]) || Is_term(g->term[i2]));
881 
882  continue;
883  }
884  }
885 
886  if( tj != tk)
887  {
888  /* get terminal-to-terminal special distance */
889  const SCIP_Real sdt_jk = reduce_sdgraphGetSd(tj, tk, sdgraph);
890 
891  if( sdt_jk > sd_jk )
892  sd_jk = sdt_jk;
893  }
894 
895  if( sd_jk < sd )
896  sd = sd_jk;
897 
898  if( terminateEarly && LT(sd, sd_sufficient) )
899  {
900  return sd;
901  }
902  } /* k < nnterms2 */
903  } /* j < nnterms1 */
904 
905  return sd;
906 }
907 
908 
909 
910 /** gets special distance to a pair of nodes */
911 static
913  const GRAPH* g, /**< graph structure */
914  int i, /**< first vertex */
915  int i2, /**< second vertex */
916  SCIP_Real sd_upper, /**< upper bound on special distance that is accepted (can be FARAWAY) */
917  SCIP_Real sd_sufficient, /**< bound below which to terminate (can be 0.0) */
918  SD* sddata /**< SD */
919  )
920 {
921  SCIP_Real termdist1[4];
922  SCIP_Real termdist2[4];
923  int neighbterms1[4];
924  int neighbterms2[4];
925  SDGRAPH* sdgraph;
926  SDN* sdneighbors;
927  SCIP_Real sd = sd_upper;
928  int nnterms1;
929  int nnterms2;
930  const SCIP_Bool terminateEarly = GT(sd_sufficient, 0.0);
931 
932  assert(g && sddata);
933  assert(i != i2);
934 
935  sdgraph = sddata->sdgraph;
936  sdneighbors = sddata->sdneighbors;
937  assert(sdgraph && sdneighbors);
938 
939  /* get closest terminals of distance strictly smaller than 'sd' */
940  reduce_sdneighborGetCloseTerms(g, sdneighbors, i, sd, neighbterms1, termdist1, &nnterms1);
941  if( nnterms1 == 0 )
942  return sd;
943 
944  reduce_sdneighborGetCloseTerms(g, sdneighbors, i2, sd, neighbterms2, termdist2, &nnterms2);
945  if( nnterms2 == 0 )
946  return sd;
947 
948  assert(nnterms1 <= 4 && nnterms2 <= 4);
949 
950  for( int j = 0; j < nnterms1; j++ )
951  {
952  const int tj = neighbterms1[j];
953  assert(tj >= 0);
954 
955  for( int k = 0; k < nnterms2; k++ )
956  {
957  SCIP_Real sd_jk = MAX(termdist1[j], termdist2[k]);
958  const int tk = neighbterms2[k];
959 
960  assert(Is_term(g->term[tk]));
961  assert(Is_term(g->term[tj]));
962  assert(tk >= 0);
963 
964  if( tj != tk)
965  {
966  /* get terminal-to-terminal special distance */
967  const SCIP_Real sdt_jk = reduce_sdgraphGetSd(tj, tk, sdgraph);
968 
969  if( sdt_jk > sd_jk )
970  sd_jk = sdt_jk;
971  }
972 
973  if( sd_jk < sd )
974  sd = sd_jk;
975 
976  if( terminateEarly && LT(sd, sd_sufficient) )
977  {
978  return sd;
979  }
980  } /* k < nnterms2 */
981  } /* j < nnterms1 */
982 
983  return sd;
984 }
985 
986 
987 /** is node of degree 3 pseudo-deletable? */
988 static inline
990  SCIP* scip, /**< SCIP data structure */
991  const GRAPH* g, /**< graph structure */
992  const SCIP_Real* sdsK3, /**< (unordered) special distances of K3 */
993  const int* edgesK3, /**< (unordered) edges of K3 */
994  SCIP_Real costK3, /**< total edge cost */
995  SCIP_Bool allowEquality /**< allow equality? */
996 )
997 {
998  assert(scip && g && sdsK3 && edgesK3);
999  assert(costK3 >= 0.0);
1000 
1001  if( allowEquality )
1002  {
1003  if( SCIPisLE(scip, sdsK3[0] + sdsK3[1], costK3) )
1004  return TRUE;
1005 
1006  if( SCIPisLE(scip, sdsK3[0] + sdsK3[2], costK3) )
1007  return TRUE;
1008 
1009  if( SCIPisLE(scip, sdsK3[1] + sdsK3[2], costK3) )
1010  return TRUE;
1011  }
1012  else
1013  {
1014  if( SCIPisLT(scip, sdsK3[0] + sdsK3[1], costK3) )
1015  return TRUE;
1016 
1017  if( SCIPisLT(scip, sdsK3[0] + sdsK3[2], costK3) )
1018  return TRUE;
1019 
1020  if( SCIPisLT(scip, sdsK3[1] + sdsK3[2], costK3) )
1021  return TRUE;
1022  }
1023 
1024  if( graph_pseudoAncestors_edgesInConflict(scip, g, edgesK3, 3) )
1025  return TRUE;
1026 
1027  return FALSE;
1028 }
1029 
1030 
1031 /** is given graph not part of at least one optimal solution? */
1032 static
1034  SCIP* scip, /**< SCIP data structure */
1035  const GRAPH* g, /**< graph structure */
1036  const GRAPH* auxg, /**< auxiliary graph structure */
1037  const SCIP_Real* ecost, /**< adjacent edges costs */
1038  const int* edges, /**< adjacent edges of node */
1039  int degree /**< degree of the node to be checked */
1040 )
1041 {
1042  SCIP_Bool success = TRUE;
1043  const SCIP_Real costsum = ecost[0] + ecost[1] + ecost[2] + ecost[3];
1044  SCIP_Real mstcost = 0.0;
1045  PATH mst[STP_BD_MAXDEGREE];
1046 
1047 #ifndef NDEBUG
1048  for( int l = 0; l < STP_BD_MAXDEGREE; l++ )
1049  mst[l].dist = UNKNOWN;
1050 #endif
1051 
1052  assert(graph_isMarked(auxg));
1053  assert(degree == 4);
1054 
1055  /* compute MST on all neighbors */
1056  graph_path_exec(scip, auxg, MST_MODE, 0, auxg->cost, mst);
1057 
1058 #ifndef NDEBUG
1059  for( int l = 1; l < STP_BD_MAXDEGREE; l++ )
1060  assert(!EQ(mst[l].dist, UNKNOWN));
1061 #endif
1062 
1063  for( int l = 1; l < STP_BD_MAXDEGREE; l++ )
1064  mstcost += mst[l].dist;
1065 
1066  if( SCIPisGT(scip, mstcost, costsum) )
1067  {
1068  success = FALSE;
1069 
1070  if( graph_pseudoAncestors_edgesInConflict(scip, g, edges, degree) )
1071  success = TRUE;
1072  }
1073 
1074 #ifndef NDEBUG
1075  {
1076  /* check all 3-subsets of neighbors */
1077  for( int k = 0; k < 4; k++ )
1078  {
1079  const int auxvertex1 = (k + 1) % 4;
1080  const int auxvertex2 = (k + 2) % 4;
1081  const int auxvertex3 = (k + 3) % 4;
1082  const int edgesK3[] = { edges[auxvertex1], edges[auxvertex2], edges[auxvertex3] };
1083  SCIP_Real sdK3[3];
1084  int sdcount = 0;
1085  SCIP_Bool success_debug;
1086 
1087  assert(auxvertex1 != k && auxvertex2 != k && auxvertex3 != k);
1088 
1089  for( int e = auxg->outbeg[auxvertex1]; e != EAT_LAST; e = auxg->oeat[e] )
1090  {
1091  if( auxg->head[e] != k )
1092  {
1093  assert(sdcount < 2);
1094  sdK3[sdcount++] = auxg->cost[e];
1095  }
1096  }
1097 
1098  assert(sdcount == 2);
1099 
1100  for( int e = auxg->outbeg[auxvertex2]; e != EAT_LAST; e = auxg->oeat[e] )
1101  {
1102  if( auxg->head[e] == auxvertex3 )
1103  {
1104  sdK3[sdcount++] = auxg->cost[e];
1105  break;
1106  }
1107  }
1108 
1109  assert(sdcount == 3);
1110  success_debug = isPseudoDeletableDeg3(scip, g, sdK3, edgesK3, costsum - ecost[k], TRUE);
1111  assert(success_debug);
1112  }
1113  }
1114 #endif
1115 
1116  return success;
1117 }
1118 
1119 
1120 /** initializes data */
1121 static inline
1123  SCIP* scip, /**< SCIP */
1124  const GRAPH* g, /**< the graph */
1125  int centernode, /**< center node or - 1 */
1126  const GRAPH* cliquegraph, /**< clique graph */
1127  const int* cliqueNodeMap, /**< maps clique graph vertices to original ones */
1128  DIJK* dijkdata, /**< data for repeated path computations */
1129  SDCLIQUE* sdclique /**< clique */
1130 )
1131 {
1132  SCIP_Real* sds_buffer;
1133  int* cliquenodes;
1134  const int nnodes_cliquegraph = graph_get_nNodes(cliquegraph);
1135  const int* const nodemark = cliquegraph->mark;
1136  int nnodes_clique = 0;
1137 
1138  /* NOTE: might be too big, but slightly better for cache reuse */
1139  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes_cliquegraph) );
1140  SCIP_CALL( SCIPallocBufferArray(scip, &sds_buffer, cliquegraph->edges / 2) );
1141 
1142  for( int i = 0; i < nnodes_cliquegraph; ++i )
1143  {
1144  if( nodemark[i] )
1145  cliquenodes[nnodes_clique++] = cliqueNodeMap[i];
1146  }
1147 
1148 #ifndef NDEBUG
1149  for( int i = nnodes_clique; i < nnodes_cliquegraph; ++i )
1150  cliquenodes[i] = -1;
1151 #endif
1152 
1153  sdclique->centernode = centernode;
1154  sdclique->cliqueToNodeMap = cliqueNodeMap;
1155  sdclique->ncliquenodes = nnodes_clique;
1156  sdclique->sds = sds_buffer;
1157  sdclique->cliquenodes = cliquenodes;
1158  sdclique->dijkdata = dijkdata;
1159 
1160  return SCIP_OKAY;
1161 }
1162 
1163 
1164 /** frees data */
1165 static inline
1167  SCIP* scip, /**< SCIP */
1168  SDCLIQUE* sdclique /**< clique */
1169 )
1170 {
1171  SCIPfreeBufferArray(scip, &(sdclique->sds));
1172  SCIPfreeBufferArray(scip, &(sdclique->cliquenodes));
1173 }
1174 
1175 
1176 /** tries to improve SDs of clique-graph
1177  * by using the star SD clique algorithm */
1178 static inline
1180  SCIP* scip, /**< SCIP */
1181  const GRAPH* g, /**< the graph */
1182  const SDPROFIT* sdprofit, /**< profit or NULL */
1183  GRAPH* cliquegraph, /**< clique graph */
1184  SDCLIQUE* sdclique /**< clique */
1185 )
1186 {
1187  const SCIP_Real* sds_buffer;
1188  const int* const nodemark = cliquegraph->mark;
1189  const int nnodes_cliquegraph = graph_get_nNodes(cliquegraph);
1190  int nsds = 0;
1191 
1192  SCIP_CALL( graph_sdComputeCliqueStar(scip, g, sdprofit, sdclique) );
1193  sds_buffer = sdclique->sds;
1194 
1195  for( int k1 = 0; k1 < nnodes_cliquegraph; k1++ )
1196  {
1197  if( !nodemark[k1] )
1198  continue;
1199 
1200  for( int e = cliquegraph->outbeg[k1]; e != EAT_LAST; e = cliquegraph->oeat[e] )
1201  {
1202  const int k2 = cliquegraph->head[e];
1203 
1204  if( !nodemark[k2] )
1205  continue;
1206 
1207  if( k2 > k1 )
1208  {
1209 #ifndef NDEBUG
1210  const int* cliqueNodeMap = sdclique->cliqueToNodeMap;
1211  const int v1 = cliqueNodeMap[k1];
1212  const int v2 = cliqueNodeMap[k2];
1213  assert(0 <= v1 && v1 < g->knots);
1214 
1215  assert(0 <= v2 && v2 < g->knots);
1216  assert(v1 != v2);
1217 #endif
1218 
1219  assert(GT(sds_buffer[nsds], 0.0));
1220  assert(LE(sds_buffer[nsds], cliquegraph->cost[e]));
1221  assert(EQ(cliquegraph->cost[e], cliquegraph->cost[flipedge(e)]));
1222 
1223  if( sds_buffer[nsds] < cliquegraph->cost[e] )
1224  {
1225  cliquegraph->cost[e] = sds_buffer[nsds];
1226  cliquegraph->cost[flipedge(e)] = sds_buffer[nsds];
1227  }
1228 
1229  nsds++;
1230  assert(nsds <= cliquegraph->edges / 2);
1231  }
1232  }
1233  }
1234 
1235  return SCIP_OKAY;
1236 }
1237 
1238 
1239 /** get SDs between all pairs of marked vertices of given clique graph by
1240  * using terminal-to-terminal special distances */
1241 static
1243  const GRAPH* g, /**< the graph */
1244  SD* RESTRICT sddata, /**< SD */
1245  GRAPH* RESTRICT cliquegraph, /**< clique graph to be filled */
1246  SDCLIQUE* RESTRICT sdclique /**< clique */
1247 )
1248 {
1249  const int nnodes_clique = graph_get_nNodes(cliquegraph);
1250  const SCIP_Real maxtreecost = reduce_sdgraphGetMaxCost(sddata->sdgraph);
1251  const int* const nodemark = cliquegraph->mark;
1252  const int* cliqueNodeMap = sdclique->cliqueToNodeMap;
1253  SCIP_Real* RESTRICT sds_buffer = sdclique->sds;
1254  int nsds = 0;
1255 
1256  assert(cliqueNodeMap && sddata);
1257  assert(2 <= nnodes_clique);
1258 
1259  for( int k1 = 0; k1 < nnodes_clique; k1++ )
1260  {
1261  int v1;
1262 
1263  if( !nodemark[k1] )
1264  continue;
1265 
1266  v1 = cliqueNodeMap[k1];
1267  assert(0 <= v1 && v1 < g->knots);
1268 
1269  for( int e = cliquegraph->outbeg[k1]; e != EAT_LAST; e = cliquegraph->oeat[e] )
1270  {
1271  const int k2 = cliquegraph->head[e];
1272 
1273  if( !nodemark[k2] )
1274  continue;
1275 
1276  if( k2 > k1 )
1277  {
1278  const int v2 = cliqueNodeMap[k2];
1279  assert(0 <= v2 && v2 < g->knots);
1280  assert(v1 != v2);
1281 
1282  sds_buffer[nsds] = sdGetSd(g, v1, v2, maxtreecost, 0.0, FALSE, sddata);
1283  cliquegraph->cost[e] = sds_buffer[nsds];
1284  cliquegraph->cost[flipedge(e)] = sds_buffer[nsds];
1285 
1286  nsds++;
1287  assert(nsds <= cliquegraph->edges / 2);
1288  }
1289  }
1290  }
1291 
1292 #ifndef NDEBUG
1293  for( int k = nsds; k < cliquegraph->edges / 2; k++ )
1294  sds_buffer[k] = FARAWAY;
1295 #endif
1296 }
1297 
1298 
1299 /** longest edge reduction test from T. Polzin's "Algorithms for the Steiner problem in networks" */
1300 static
1302  SCIP* scip,
1303  const GRAPH* netgraph,
1304  const PATH* mst,
1305  const int* edgeorg,
1306  const PATH* vnoi,
1307  const int* vbase,
1308  GRAPH* g,
1309  int* nelims
1310 )
1311 {
1312  SCIP_Bool* blocked;
1313  SCIP_Real maxcost;
1314  const int nedges = graph_get_nEdges(g);
1315  const int nnodes = graph_get_nNodes(g);
1316  const int netnnodes = graph_get_nNodes(netgraph);
1317 
1318  assert(*nelims == 0);
1319 
1320  SCIP_CALL( SCIPallocBufferArray(scip, &blocked, nedges / 2) );
1321 
1322  for( int e = 0; e < nedges / 2; e++ )
1323  {
1324  blocked[e] = FALSE;
1325  }
1326 
1327  maxcost = -1.0;
1328  assert(mst[0].edge == -1);
1329 
1330  for( int k = 1; k < netnnodes; k++ )
1331  {
1332  SCIP_Real cost;
1333  int ne;
1334  const int e = mst[k].edge;
1335 
1336  assert(netgraph->path_state[k] == CONNECT);
1337  assert(e >= 0);
1338  cost = netgraph->cost[e];
1339 
1340  if( SCIPisGT(scip, cost, maxcost) )
1341  maxcost = cost;
1342 
1343  ne = edgeorg[e];
1344  blocked[ne / 2] = TRUE;
1345  for( int v1 = g->head[ne]; v1 != vbase[v1]; v1 = g->tail[vnoi[v1].edge] )
1346  blocked[vnoi[v1].edge / 2] = TRUE;
1347 
1348  for( int v1 = g->tail[ne]; v1 != vbase[v1]; v1 = g->tail[vnoi[v1].edge] )
1349  blocked[vnoi[v1].edge / 2] = TRUE;
1350  }
1351 
1352  for( int k = 0; k < nnodes; k++ )
1353  {
1354  int e = g->outbeg[k];
1355  while( e != EAT_LAST )
1356  {
1357  assert(e >= 0);
1358 
1359  if( SCIPisGE(scip, g->cost[e], maxcost) && !blocked[e / 2] )
1360  {
1361  const int nextedge = g->oeat[e];
1362 
1363  (*nelims)++;
1364  graph_edge_del(scip, g, e, TRUE);
1365  e = nextedge;
1366  }
1367  else
1368  {
1369  e = g->oeat[e];
1370  }
1371  }
1372  }
1373 
1374  /* graph might have become disconnected */
1375  if( *nelims > 0 )
1376  {
1377  SCIP_CALL( reduce_unconnected(scip, g) );
1378  }
1379 
1380  SCIPfreeBufferArray(scip, &blocked);
1381 
1382  assert(graph_valid(scip, g));
1383  return SCIP_OKAY;
1384 }
1385 
1386 
1387 /*
1388  * Interface methods
1389  */
1390 
1391 
1392 
1393 /** get SDs between all pairs of marked vertices of given clique graph */
1395  SCIP* scip, /**< SCIP */
1396  const GRAPH* g, /**< the graph */
1397  int centernode, /**< center node or - 1 */
1398  const int* cliqueNodeMap, /**< maps clique graph vertices to original ones */
1399  DIJK* dijkdata, /**< data for repeated path computations */
1400  SD* sddata, /**< SD */
1401  GRAPH* cliquegraph /**< clique graph to be filled */
1402 )
1403 {
1404  SDCLIQUE sdclique;
1405 
1406  assert(scip && g && cliqueNodeMap && dijkdata && sddata && cliquegraph);
1407  assert(cliquegraph->edges == (cliquegraph->knots) * (cliquegraph->knots - 1));
1408 
1409  SCIP_CALL( sdCliqueInitData(scip, g, centernode, cliquegraph, cliqueNodeMap, dijkdata, &sdclique) );
1410 
1411  sdGetSdsCliqueTermWalks(g, sddata, cliquegraph, &sdclique);
1412  SCIP_CALL( sdCliqueUpdateGraphWithStarWalks(scip, g, sddata->sdprofit, cliquegraph, &sdclique) );
1413 
1414  sdCliqueFreeData(scip, &sdclique);
1415 
1416  return SCIP_OKAY;
1417 }
1418 
1419 
1420 /** long edge implied special distance test */
1422  SCIP* scip, /**< SCIP data structure */
1423  const int* edgestate, /**< array to store status of (directed) edge (for propagation, can otherwise be set to NULL) */
1424  GRAPH* g, /**< graph data structure */
1425  SD* sdistance, /**< special distances storage */
1426  int* nelims /**< point to store number of deleted edges */
1427 )
1428 {
1429  SDGRAPH* sdgraph = sdistance->sdgraph;
1430  const STP_Bool* edges_isBlocked;
1431  const int nnodes = graph_get_nNodes(g);
1432  const SCIP_Bool checkstate = (edgestate != NULL);
1433  const SCIP_Real maxcost = reduce_sdgraphGetMaxCost(sdgraph);
1434  int nelims_new = 0;
1435  const SCIP_Bool* nodes_isBlocked = NULL;
1436  SCIP_Bool withBlockedNodes = FALSE;
1437  SCIP_Bool allowEquality;
1438 
1439  assert(scip && nelims);
1440  assert(*nelims >= 0);
1441 
1442  if( sdistance->hasNeigborUpdate )
1443  {
1444  nodes_isBlocked = reduce_sdneighborGetBlocked(sdistance->sdneighbors);
1445  withBlockedNodes = TRUE;
1446  assert(nodes_isBlocked);
1447  }
1448 
1449  if( reduce_sdgraphHasMstHalfMark(sdgraph) )
1450  {
1451  edges_isBlocked = reduce_sdgraphGetMstHalfMark(sdgraph);
1452  allowEquality = TRUE;
1453  assert(edges_isBlocked);
1454  }
1455  else
1456  {
1457  edges_isBlocked = FALSE;
1458  allowEquality = FALSE;
1459  }
1460 
1461  for( int k = 0; k < nnodes; k++ )
1462  {
1463  int e = g->outbeg[k];
1464 
1465  if( withBlockedNodes && nodes_isBlocked[k] )
1466  continue;
1467 
1468  while( e != EAT_LAST )
1469  {
1471  const SCIP_Bool edgeIsForbidden =
1472  (checkstate && edgestate[e] == EDGE_BLOCKED) || (withBlockedNodes && nodes_isBlocked[g->head[e]]);
1473 
1474  if( edgeIsForbidden )
1475  {
1476  e = g->oeat[e];
1477  continue;
1478  }
1479 
1480  if( allowEquality )
1481  deleteEdge = SCIPisGE(scip, g->cost[e], maxcost) && !edges_isBlocked[e / 2];
1482  else
1483  deleteEdge = SCIPisGT(scip, g->cost[e], maxcost);
1484 
1485  if( deleteEdge )
1486  {
1487  const int enext = g->oeat[e];
1488  graph_edge_del(scip, g, e, TRUE);
1489  nelims_new++;
1490 
1491 #ifdef SCIP_DEBUG
1492  SCIPdebugMessage("LE implied deletes (max. MST cost=%f): ", maxcost);
1493  graph_edge_printInfo(g, e);
1494 #endif
1495  e = enext;
1496  }
1497  else
1498  {
1499  e = g->oeat[e];
1500  }
1501  }
1502  }
1503 
1504  /* graph might have become disconnected */
1505  if( nelims_new > 0 )
1506  {
1507  SCIP_CALL( reduce_unconnected(scip, g) );
1508  }
1509 
1510  *nelims += nelims_new;
1511 
1512  return SCIP_OKAY;
1513 }
1514 
1515 
1516 /** Special distance test */
1518  SCIP* scip, /**< SCIP data structure */
1519  GRAPH* g, /**< graph data structure */
1520  REDBASE* redbase, /**< reduction data */
1521  int* nelims /**< point to store number of deleted edges */
1522  )
1523 {
1524  SDGRAPH* sdgraph;
1525  GRAPH* netgraph;
1526  PATH* mst;
1527  SCIP_Real termdist1[4];
1528  SCIP_Real termdist2[4];
1529  PATH* RESTRICT vnoi = redbase->vnoi;
1530  int* RESTRICT state = redbase->state;
1531  int* RESTRICT vbase = redbase->vbase;
1532  int* RESTRICT nodesid = redbase->nodearrint;
1533  int* RESTRICT nodesorg = redbase->nodearrint2;
1534  int* RESTRICT forbidden = redbase->edgearrint;
1535  SCIP_Real ecost;
1536  SCIP_Real dist;
1537  int neighbterms1[4];
1538  int neighbterms2[4];
1539  int* RESTRICT edgepreds;
1540  int j;
1541  int nnterms1;
1542  int nnterms2;
1543  int maxnedges;
1544  const int nnodes = graph_get_nNodes(g);
1545  const int nedges = graph_get_nEdges(g);
1546  const int nterms = g->terms;
1547  const SCIP_Bool nodereplacing = redbase->redparameters->nodereplacing;
1548  const SCIP_Bool usestrongreds = redbase->redparameters->usestrongreds;
1549 
1550  assert(scip != NULL);
1551  assert(vnoi != NULL);
1552  assert(state != NULL);
1553  assert(vbase != NULL);
1554  assert(nelims != NULL);
1555  assert(nodesid != NULL);
1556  assert(nodesorg != NULL);
1557  assert(forbidden != NULL);
1558 
1559  *nelims = 0;
1560  maxnedges = MIN(nedges, (nterms - 1) * nterms);
1561 
1562  /* only one terminal left? */
1563  if( nterms == 1 )
1564  return SCIP_OKAY;
1565 
1566  SCIP_CALL( SCIPallocBufferArray(scip, &edgepreds, nedges) );
1567 
1568  /* compute nearest four terminals to all non-terminals */
1569  graph_get4nextTermPaths(g, g->cost, g->cost, vnoi, vbase, state);
1570 
1571  /* construct auxiliary graph to compute paths between terminals */
1572 
1573  /* initialize the new graph */
1574  SCIP_CALL( graph_init(scip, &netgraph, nterms, maxnedges, 1) );
1575 
1576  j = 0;
1577  for( int k = 0; k < nnodes; k++ )
1578  {
1579  if( Is_term(g->term[k]) )
1580  {
1581  assert(g->grad[k] > 0);
1582 
1583  graph_knot_add(netgraph, -1);
1584  nodesid[k] = j;
1585  netgraph->mark[j] = TRUE;
1586  nodesorg[j++] = k;
1587  }
1588  else
1589  {
1590  nodesid[k] = UNKNOWN;
1591  }
1592  }
1593 
1594  for( int k = 0; k < nedges; k++ )
1595  {
1596  forbidden[k] = FALSE;
1597  edgepreds[k] = -1;
1598  }
1599 
1600  assert(netgraph->knots == j);
1601  assert(netgraph->knots == nterms);
1602 
1603  for( int k = 0; k < nnodes; k++ )
1604  {
1605  int i;
1606  int id1;
1607  if( g->grad[k] == 0 )
1608  continue;
1609 
1610  i = vbase[k];
1611  id1 = nodesid[i];
1612 
1613  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
1614  {
1615  if( i != vbase[g->head[e]] )
1616  {
1617  int ne;
1618  const int i2 = vbase[g->head[e]];
1619  const int id2 = nodesid[i2];
1620 
1621  assert(id1 >= 0);
1622  assert(id2 >= 0);
1623  assert(Is_term(g->term[i]));
1624  assert(Is_term(g->term[i2]));
1625 
1626  for( ne = netgraph->outbeg[id1]; ne != EAT_LAST; ne = netgraph->oeat[ne] )
1627  if( netgraph->head[ne] == id2 )
1628  break;
1629 
1630  /* cost of the edge in the auxiliary graph */
1631  ecost = g->cost[e] + vnoi[g->head[e]].dist + vnoi[g->tail[e]].dist;
1632 
1633  /* does edge already exist? */
1634  if( ne != EAT_LAST )
1635  {
1636  assert(ne >= 0);
1637  assert(netgraph->tail[ne] == id1);
1638  assert(netgraph->head[ne] == id2);
1639 
1640  /* is the new edge better than the existing one? */
1641  if( GT(netgraph->cost[ne], ecost) )
1642  {
1643  netgraph->cost[ne] = ecost;
1644  netgraph->cost[flipedge(ne)] = ecost;
1645 
1646  edgepreds[ne] = e;
1647  edgepreds[flipedge(ne)] = flipedge(e);
1648 
1649  assert(ne <= maxnedges);
1650  }
1651  }
1652  else
1653  {
1654  edgepreds[netgraph->edges] = e;
1655  edgepreds[netgraph->edges + 1] = flipedge(e);
1656 
1657  graph_edge_add(scip, netgraph, id1, id2, ecost, ecost);
1658 
1659  assert(netgraph->edges <= maxnedges);
1660  }
1661  }
1662  }
1663  }
1664 
1665  /* compute MST on netgraph */
1666  graph_knot_chg(netgraph, 0, 0);
1667  netgraph->source = 0;
1668 
1669  SCIP_CALL( graph_path_init(scip, netgraph) );
1670  SCIP_CALL( SCIPallocBufferArray(scip, &mst, nterms) );
1671 
1672  graph_path_exec(scip, netgraph, MST_MODE, 0, netgraph->cost, mst);
1673 
1674  /* long edge test */
1675  ledgeFromNetgraph(scip, netgraph, mst, edgepreds, vnoi, vbase, g, nelims);
1676 
1677  SCIP_CALL( reduce_sdgraphInitFromDistGraph(scip, g, netgraph, nodesid, &sdgraph) );
1678 
1679  /* mark (original) edges of MST */
1680  for( int k = 1; k < netgraph->knots; k++ )
1681  {
1682  int e;
1683  assert(mst[k].edge != -1);
1684  assert(edgepreds[mst[k].edge] != -1);
1685  assert(edgepreds[flipedge(mst[k].edge)] != -1);
1686 
1687  e = edgepreds[mst[k].edge];
1688 
1689  assert(vbase[g->tail[e]] == nodesorg[k] || vbase[g->head[e]] == nodesorg[k]);
1690 
1691  if( Is_term(g->tail[e]) && Is_term(g->head[e]) )
1692  {
1693  forbidden[e] = TRUE;
1694  forbidden[flipedge(e)] = TRUE;
1695  }
1696  }
1697 
1698  /* traverse all edges */
1699  for( int i = 0; i < nnodes; i++ )
1700  {
1701  int enext;
1702  if( g->grad[i] == 0 )
1703  continue;
1704 
1705  nnterms1 = 1;
1706  if( Is_term(g->term[i]) )
1707  {
1708  termdist1[0] = 0.0;
1709  neighbterms1[0] = i;
1710  }
1711 
1712  enext = g->outbeg[i];
1713  while( enext != EAT_LAST )
1714  {
1715  const int e = enext;
1716  const int i2 = g->head[e];
1717  enext = g->oeat[e];
1718 
1719  if( i2 < i || !g->mark[i2] )
1720  continue;
1721 
1722  ecost = g->cost[e];
1723 
1724  /* is i a terminal? If not, get three closest terminals of distance <= ecost */
1725  if( !Is_term(g->term[i]) )
1726  {
1727  nnterms1 = getlecloseterms(scip, vnoi, termdist1, ecost, vbase, neighbterms1, i, nnodes);
1728 
1729  if( nnterms1 == 0 )
1730  continue;
1731  }
1732 
1733  if( Is_term(g->term[i2]) )
1734  {
1735  nnterms2 = 1;
1736  termdist2[0] = 0.0;
1737  neighbterms2[0] = i2;
1738  }
1739  else
1740  {
1741  /* get closest terminals of distance <= ecost */
1742  nnterms2 = getlecloseterms(scip, vnoi, termdist2, ecost, vbase, neighbterms2, i2, nnodes);
1743 
1744  if( nnterms2 == 0 )
1745  continue;
1746  }
1747 
1748  for( j = 0; j < nnterms1; j++ )
1749  {
1750  int tj;
1751 
1752  /* has edge already been deleted? */
1753  if( g->oeat[e] == EAT_FREE )
1754  break;
1755 
1756  tj = neighbterms1[j];
1757 
1758  assert(tj >= 0);
1759 
1760  for( int k = 0; k < nnterms2; k++ )
1761  {
1762  const int tk = neighbterms2[k];
1763 
1764  assert(tk >= 0);
1765  assert(Is_term(g->term[tk]));
1766  assert(Is_term(g->term[tj]));
1767 
1768  if( tj == tk )
1769  {
1770  if( GE(termdist1[j], termdist2[k] ) )
1771  dist = termdist1[j];
1772  else
1773  dist = termdist2[k];
1774 
1775  assert(SCIPisGE(scip, ecost, dist));
1776 
1777  if( SCIPisEQ(scip, dist, ecost) )
1778  {
1779  if( !usestrongreds )
1780  continue;
1781 
1782  if( !sddeltable(scip, g, vnoi, vbase, forbidden, j, k, i, i2, e, nnodes ) )
1783  continue;
1784  }
1785 
1786  graph_edge_del(scip, g, e, TRUE);
1787  (*nelims)++;
1788  break;
1789  }
1790  else
1791  {
1792  dist = reduce_sdgraphGetSd(tj, tk, sdgraph);
1793 
1794  if( LT(dist, termdist1[j]) )
1795  dist = termdist1[j];
1796 
1797  if( LT(dist, termdist2[k]) )
1798  dist = termdist2[k];
1799 
1800  if( SCIPisGE(scip, ecost, dist) )
1801  {
1802  if( SCIPisEQ(scip, ecost, dist) )
1803  {
1804  if( !usestrongreds )
1805  continue;
1806 
1807  if( !(sddeltable(scip, g, vnoi, vbase, forbidden, j, k, i, i2, e, nnodes)) )
1808  continue;
1809  }
1810 
1811  assert(SCIPisGE(scip, ecost, termdist1[j]));
1812  assert(SCIPisGE(scip, ecost, termdist2[k]));
1813 
1814  graph_edge_del(scip, g, e, TRUE);
1815  (*nelims)++;
1816  break;
1817  }
1818  } /* tj != tk (else) */
1819  } /* k < nnterms2 */
1820  } /* j < nnterms1 */
1821 
1822  } /* while( enext != EAT_LAST ) */
1823  }
1824 
1825  assert(graph_valid(scip, g));
1826 
1827  if( nodereplacing )
1828  {
1829  SCIP_CALL( reduce_bd34WithSd(scip, g, sdgraph, vnoi, vbase, nelims) );
1830  }
1831  reduce_sdgraphFreeFromDistGraph(scip, &sdgraph);
1832 
1833  /* free memory*/
1834  SCIPfreeBufferArray(scip, &mst);
1835  graph_path_exit(scip, netgraph);
1836  graph_free(scip, &netgraph, TRUE);
1837 
1838  SCIPfreeBufferArray(scip, &edgepreds);
1839 
1840  return SCIP_OKAY;
1841 }
1842 
1843 
1844 /** implied-profit special distance test */
1846  SCIP* scip, /**< SCIP data structure */
1847  SD* sdistance, /**< special distances storage */
1848  GRAPH* g, /**< graph structure */
1849  int* nelims /**< number of eliminations */
1850 )
1851 {
1852  const SDPROFIT* sdprofit = sdistance->sdprofit;
1853  const int nnodes = graph_get_nNodes(g);
1854  const SCIP_Real maxmstcost = reduce_sdgraphGetMaxCost(sdistance->sdgraph);
1855 
1856  assert(LT(maxmstcost, FARAWAY));
1857  assert(scip && nelims);
1858  assert(*nelims >= 0);
1859  assert(!sdistance->hasNeigborUpdate);
1860 
1861  graph_mark(g);
1862 
1863  SCIP_CALL( reduce_sdImpLongEdge(scip, NULL, g, sdistance, nelims) );
1864 
1865  SCIPdebugMessage("Starting SD biased... \n");
1866 
1867  /* traverse all edges */
1868  for( int i = 0; i < nnodes; i++ )
1869  {
1870  int enext;
1871 
1872  if( !g->mark[i] )
1873  continue;
1874 
1875  enext = g->outbeg[i];
1876  while( enext != EAT_LAST )
1877  {
1879  SCIP_Real sd;
1880  const int e = enext;
1881  const int i2 = g->head[e];
1882  const SCIP_Real ecost = g->cost[e];
1883 
1884  enext = g->oeat[e];
1885 
1886  if( i2 < i || !g->mark[i2] )
1887  continue;
1888 
1889  sd = sdGetSd(g, i, i2, maxmstcost, ecost, FALSE, sdistance);
1890 
1891  deleteEdge = SCIPisLT(scip, sd, ecost);
1892 
1893  if( !deleteEdge && SCIPisEQ(scip, sd, ecost) )
1894  {
1895  const SCIP_Real profit1 = reduce_sdprofitGetProfit(sdprofit, i, -1, -1);
1896  const SCIP_Real profit2 = reduce_sdprofitGetProfit(sdprofit, i2, -1, -1);
1897 
1898  if( EQ(profit1, 0.0) && EQ(profit2, 0.0) )
1899  {
1900  assert(!Is_term(g->term[i]));
1901  assert(!Is_term(g->term[i2]));
1902 
1903  deleteEdge = TRUE;
1904  }
1905  }
1906 
1907  if( deleteEdge )
1908  {
1909 #ifdef SCIP_DEBUG
1910  SCIPdebugMessage("SD biased deletes (sd=%f): ", sd);
1911  graph_edge_printInfo(g, e);
1912 #endif
1913  graph_edge_del(scip, g, e, TRUE);
1914  (*nelims)++;
1915  }
1916  }
1917  }
1918 
1919  assert(graph_valid(scip, g));
1920 
1921  return SCIP_OKAY;
1922 }
1923 
1924 
1925 /** implied-profit neighbor special distance test
1926  * NOTE: invalidates SD for other methods! */
1928  SCIP* scip, /**< SCIP data structure */
1929  SD* sdistance, /**< special distances storage */
1930  GRAPH* g, /**< graph structure */
1931  int* nelims /**< number of eliminations */
1932 )
1933 {
1934  const int nnodes = graph_get_nNodes(g);
1935  SDN* sdneighbors = sdistance->sdneighbors;
1936  const SCIP_Bool* nodes_isBlocked = reduce_sdneighborGetBlocked(sdneighbors);
1937  const SCIP_Real maxmstcost = reduce_sdgraphGetMaxCost(sdistance->sdgraph);
1938  int nupdates = 0;
1939 
1940  assert(scip && nelims);
1941  assert(sdneighbors);
1942  assert(*nelims >= 0);
1943  assert(nodes_isBlocked);
1944  graph_mark(g);
1945 
1946  SCIPdebugMessage("Starting SD neighbor biased... \n");
1947 
1948  SCIP_CALL( reduce_sdUpdateWithSdNeighbors(scip, g, sdistance, &nupdates) );
1949 
1950  if( nupdates == 0 )
1951  {
1952  SCIPdebugMessage("...no updates found, returning \n");
1953  return SCIP_OKAY;
1954  }
1955 
1956  assert(!reduce_sdgraphHasMstHalfMark(sdistance->sdgraph));
1957  assert(sdistance->hasNeigborUpdate);
1958  SCIP_CALL( reduce_sdImpLongEdge(scip, NULL, g, sdistance, nelims) );
1959 
1960  if( nupdates < (int) ((SCIP_Real) g->terms / 25.0) )
1961  {
1962  SCIPdebugMessage("...not enough updates found, returning \n");
1963  // printf("...not enough updates found, returning \n");
1964 
1965  return SCIP_OKAY;
1966  }
1967 
1968  /* traverse all edges */
1969  for( int i = 0; i < nnodes; i++ )
1970  {
1971  int enext;
1972 
1973  if( !g->mark[i] || nodes_isBlocked[i] )
1974  continue;
1975 
1976  enext = g->outbeg[i];
1977  while( enext != EAT_LAST )
1978  {
1980  SCIP_Real sd;
1981  const int e = enext;
1982  const int i2 = g->head[e];
1983  const SCIP_Real ecost = g->cost[e];
1984  enext = g->oeat[e];
1985 
1986  if( i2 < i || !g->mark[i2] || nodes_isBlocked[i2] )
1987  continue;
1988 
1989  sd = sdGetSd(g, i, i2, maxmstcost, ecost, FALSE, sdistance);
1990 
1991  deleteEdge = SCIPisLT(scip, sd, ecost);
1992 
1993  if( !deleteEdge )
1994  {
1995  sd = sdGetSdNeighbor(g, i, i2, maxmstcost, ecost, sdistance);
1996  deleteEdge = SCIPisLT(scip, sd, ecost);
1997  }
1998 
1999  if( deleteEdge )
2000  {
2001  // printf("SD biased neighbor deletes (sd=%f): ", sd);
2002  // graph_edge_printInfo(g, e);
2003 #ifdef SCIP_DEBUG
2004  SCIPdebugMessage("SD biased neighbor deletes (sd=%f): ", sd);
2005  graph_edge_printInfo(g, e);
2006 #endif
2007  graph_edge_del(scip, g, e, TRUE);
2008  (*nelims)++;
2009 
2010  break;
2011  }
2012  }
2013  }
2014 
2015  assert(graph_valid(scip, g));
2016 
2017  return SCIP_OKAY;
2018 }
2019 
2020 
2021 
2022 /** SD test for PC */
2024  SCIP* scip, /**< SCIP data structure */
2025  GRAPH* g, /**< graph data structure */
2026  PATH* vnoi, /**< Voronoi data structure */
2027  int* heap, /**< heap array */
2028  int* state, /**< array to store state of a node during Voronoi computation*/
2029  int* vbase, /**< Voronoi base to each node */
2030  int* nodesid, /**< array */
2031  int* nodesorg, /**< array */
2032  int* nelims /**< pointer to store number of eliminated edges */
2033  )
2034 {
2035  GRAPH* netgraph;
2036  SCIP_Real termdist1[4];
2037  SCIP_Real termdist2[4];
2038  int neighbterms1[4];
2039  int neighbterms2[4];
2040 
2041  int j;
2042  int maxnedges;
2043  const int root = g->source;
2044  const int nnodes = g->knots;
2045  const int nterms = g->terms;
2046  const int nedges = g->edges;
2047 
2048  assert(g != NULL);
2049  assert(heap != NULL);
2050  assert(vnoi != NULL);
2051  assert(state != NULL);
2052  assert(vbase != NULL);
2053  assert(scip != NULL);
2054  assert(nelims != NULL);
2055  assert(nodesid != NULL);
2056  assert(nodesorg != NULL);
2057  assert(!g->extended);
2058 
2059  *nelims = 0;
2060 
2061  if( nterms <= 1 )
2062  {
2063  return SCIP_OKAY;
2064  }
2065  else
2066  {
2067  const SCIP_Longint longedges = (SCIP_Longint) nedges;
2068  const SCIP_Longint longtermsq = (SCIP_Longint) (nterms - 1) * (SCIP_Longint) nterms;
2069 
2070  if( longedges <= longtermsq )
2071  maxnedges = nedges;
2072  else
2073  maxnedges = ((nterms - 1) * nterms);
2074  }
2075 
2076 
2077  /* compute nearest four terminals to each non-terminal */
2078  graph_get4nextTermPaths(g, g->cost, g->cost, vnoi, vbase, state);
2079 
2080  /*
2081  * construct auxiliary graph to compute paths between terminals
2082  */
2083 
2084  SCIP_CALL( graph_init(scip, &netgraph, nterms, maxnedges, 1) );
2085 
2086  for( int k = 0; k < 4; k++ )
2087  {
2088  termdist1[k] = FARAWAY;
2089  termdist2[k] = FARAWAY;
2090  }
2091 
2092  j = 0;
2093  for( int k = 0; k < nnodes; k++ )
2094  {
2095  if( Is_term(g->term[k]) )
2096  {
2097  graph_knot_add(netgraph, -1);
2098  nodesid[k] = j;
2099  nodesorg[j++] = k;
2100  }
2101  else
2102  {
2103  nodesid[k] = UNKNOWN;
2104  }
2105  }
2106 
2107  assert(netgraph->knots == j);
2108  assert(netgraph->knots == nterms);
2109 
2110  /* insert Voronoi boundary paths as edges into netgraph */
2111  for( int k = 0; k < nnodes; k++ )
2112  {
2113  if( !g->mark[k] )
2114  continue;
2115 
2116  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
2117  {
2118  int i;
2119  if( !g->mark[g->head[e]] )
2120  continue;
2121  i = vbase[k];
2122  assert(i != UNKNOWN);
2123  if( i != vbase[g->head[e]] )
2124  {
2125  SCIP_Real ecost;
2126  int ne;
2127  const int i2 = vbase[g->head[e]];
2128 
2129  assert(i2 != UNKNOWN);
2130  assert(Is_term(g->term[i]));
2131  assert(Is_term(g->term[i2]));
2132  assert(nodesid[i] >= 0);
2133  assert(nodesid[i2] >= 0);
2134 
2135  for( ne = netgraph->outbeg[nodesid[i]]; ne != EAT_LAST; ne = netgraph->oeat[ne] )
2136  if( netgraph->head[ne] == nodesid[i2] )
2137  break;
2138 
2139  ecost = g->cost[e] + vnoi[g->head[e]].dist + vnoi[g->tail[e]].dist;
2140 
2141  /* edge exists? */
2142  if( ne != EAT_LAST )
2143  {
2144  assert(ne >= 0);
2145  assert(netgraph->head[ne] == nodesid[i2]);
2146  assert(netgraph->tail[ne] == nodesid[i]);
2147 
2148  if( SCIPisGT(scip, netgraph->cost[ne], ecost) )
2149  {
2150  netgraph->cost[ne] = ecost;
2151  netgraph->cost[flipedge(ne)] = ecost;
2152  assert(ne <= maxnedges);
2153  }
2154  }
2155  else
2156  {
2157  graph_edge_add(scip, netgraph, nodesid[i], nodesid[i2], ecost, ecost);
2158  assert(netgraph->edges <= maxnedges);
2159  }
2160  }
2161  }
2162  }
2163 
2164  /* compute four close terminals to each terminal */
2165  SCIP_CALL( graph_get4nextTTerms(scip, g, g->cost, vnoi, vbase, heap, state) );
2166 
2167  /* traverse all edges */
2168  for( int i = 0; i < nnodes; i++ )
2169  {
2170  int enext;
2171  if( !g->mark[i] )
2172  continue;
2173 
2174  enext = g->outbeg[i];
2175  while( enext != EAT_LAST )
2176  {
2177  SCIP_Real ecost;
2178  int e = enext;
2179  int nnterms1;
2180  int nnterms2;
2181  const int i2 = g->head[e];
2182  enext = g->oeat[e];
2183 
2184  if( i2 < i || Is_term(g->term[i2]) || !g->mark[i2] )
2185  continue;
2186  ecost = g->cost[e];
2187 
2188  /* @todo: fix */
2189 #if 1
2190  if( Is_term(g->term[i]) )
2191  nnterms1 = getcloseterms2term(scip, g, netgraph, termdist1, ecost, neighbterms1, nodesid, nodesorg, i);
2192  else
2193  nnterms1 = getcloseterms(scip, vnoi, termdist1, ecost, vbase, neighbterms1, i, nnodes);
2194 #else
2195  if( Is_term(g->term[i]) )
2196  nnterms1 = 0;
2197  else
2198  nnterms1 = getcloseterms(scip, vnoi, termdist1, ecost, vbase, neighbterms1, i, nnodes);
2199 #endif
2200 
2201  if( nnterms1 == 0 )
2202  continue;
2203 
2204  /* @todo: fix */
2205 #if 1
2206  if( Is_term(g->term[i2]) )
2207  nnterms2 = getcloseterms2term(scip, g, netgraph, termdist2, ecost, neighbterms2, nodesid, nodesorg, i2);
2208  else
2209  nnterms2 = getcloseterms(scip, vnoi, termdist2, ecost, vbase, neighbterms2, i2, nnodes);
2210 #else
2211  if( Is_term(g->term[i2]) )
2212  nnterms2 = 0;
2213  else
2214  nnterms2 = getcloseterms(scip, vnoi, termdist2, ecost, vbase, neighbterms2, i2, nnodes);
2215 #endif
2216 
2217  if( nnterms2 == 0 )
2218  continue;
2219 
2220  /* todo: mark nearest terminals! */
2221  for( j = 0; j < nnterms1; j++ )
2222  {
2223  int tj;
2224 
2225  /* has edge already been deleted? */
2226  if( g->oeat[e] == EAT_FREE )
2227  break;
2228 
2229  tj = neighbterms1[j];
2230 
2231  assert(tj >= 0);
2232  assert(Is_term(g->term[tj]));
2233 
2234  for( int k = 0; k < nnterms2; k++ )
2235  {
2236  const int tk = neighbterms2[k];
2237 
2238  assert(tk >= 0);
2239  assert(Is_term(g->term[tk]));
2240 
2241  if( tj == tk )
2242  {
2243  if( SCIPisGT(scip, ecost, termdist1[j] + termdist2[k] - g->prize[tj]) || tj == root )
2244  {
2245  graph_edge_del(scip, g, e, TRUE);
2246  (*nelims)++;
2247  break;
2248  }
2249  }
2250  else
2251  {
2252  SCIP_Real necost = FARAWAY;
2253  int e2;
2254  int pos;
2255 
2256  /* get distance between terminals */
2257  for( e2 = netgraph->outbeg[nodesid[tj]]; e2 != EAT_LAST; e2 = netgraph->oeat[e2] )
2258  {
2259  if( netgraph->head[e2] == nodesid[tk] )
2260  {
2261  necost = netgraph->cost[e2];
2262  break;
2263  }
2264  }
2265  pos = tj;
2266  for( int l = 0; l < 4; l++ )
2267  {
2268  if( vbase[pos] == UNKNOWN )
2269  break;
2270  if( vbase[pos] == tk && SCIPisLT(scip, vnoi[pos].dist, necost) )
2271  {
2272  necost = vnoi[pos].dist;
2273  break;
2274  }
2275  pos += nnodes;
2276  }
2277 
2278  if( SCIPisGT(scip, ecost, necost)
2279  && SCIPisGT(scip, ecost, necost + termdist1[j] - g->prize[tj])
2280  && SCIPisGT(scip, ecost, necost + termdist2[k] - g->prize[tk])
2281  && SCIPisGT(scip, ecost, necost + termdist1[j] + termdist2[k] - g->prize[tj] - g->prize[tk]) )
2282  {
2283  SCIPdebugMessage("SDPC delete: %d %d (%d)\n", g->tail[e], g->head[e], e);
2284  graph_edge_del(scip, g, e, TRUE);
2285  (*nelims)++;
2286  break;
2287  }
2288  }
2289  }
2290  }
2291  }
2292  }
2293 
2294  SCIPdebugMessage("SDPC eliminations: %d \n", *nelims);
2295  graph_free(scip, &netgraph, TRUE);
2296 
2297  assert(graph_valid(scip, g));
2298 
2299  return SCIP_OKAY;
2300 }
2301 
2302 
2303 /** get SD to a single edge by using path computations */
2305  SCIP* scip,
2306  GRAPH* g,
2307  PATH* pathtail,
2308  PATH* pathhead,
2309  SCIP_Real* sdist,
2310  SCIP_Real distlimit,
2311  int* heap,
2312  int* statetail,
2313  int* statehead,
2314  int* memlbltail,
2315  int* memlblhead,
2316  int i,
2317  int i2,
2318  int limit,
2319  SCIP_Bool pc,
2320  SCIP_Bool mw
2321  )
2322 {
2323  SCIP_Real sd;
2324  SCIP_Real dist;
2325  int k;
2326  int l;
2327  int e;
2328  int nnodes;
2329  int nlbltail;
2330  int nlblhead;
2331  const SCIP_Bool pcmw = (pc || mw);
2332 
2333  assert(g != NULL);
2334  assert(scip != NULL);
2335  assert(pathtail != NULL);
2336  assert(pathhead != NULL);
2337  assert(heap != NULL);
2338  assert(statetail != NULL);
2339  assert(statehead != NULL);
2340  assert(memlbltail != NULL);
2341  assert(memlblhead != NULL);
2342  assert(sdist != NULL);
2343 
2344  nnodes = g->knots;
2345 
2346  /* start from tail */
2347  graph_sdPaths(g, pathtail, g->cost, distlimit, heap, statetail, memlbltail, &nlbltail, i, i2, limit);
2348 
2349  /* test whether edge e can be eliminated */
2350  graph_sdPaths(g, pathhead, g->cost, distlimit, heap, statehead, memlblhead, &nlblhead, i2, i, limit);
2351 
2352  sd = FARAWAY;
2353 
2354  /* get restore state and path of tail and head */
2355  for( k = 0; k < nlbltail; k++ )
2356  {
2357  l = memlbltail[k];
2358  assert(statetail[l] != UNKNOWN);
2359  if( statehead[l] != UNKNOWN )
2360  {
2361  assert(SCIPisGT(scip, FARAWAY, pathtail[l].dist));
2362  assert(SCIPisGT(scip, FARAWAY, pathhead[l].dist));
2363  if( Is_term(g->term[l]) )
2364  {
2365  dist = 0.0;
2366  if( SCIPisLT(scip, dist, pathhead[l].dist) )
2367  dist = pathhead[l].dist;
2368  if( SCIPisLT(scip, dist, pathtail[l].dist) )
2369  dist = pathtail[l].dist;
2370  if( pcmw && SCIPisLT(scip, dist, pathhead[l].dist + pathtail[l].dist - g->prize[l]) )
2371  dist = pathhead[l].dist + pathtail[l].dist - g->prize[l];
2372  if( SCIPisGT(scip, sd, dist) )
2373  sd = dist;
2374  }
2375  else
2376  {
2377  if( mw && l != i && l != i2 )
2378  assert(SCIPisLE(scip, g->prize[l], 0.0));
2379  if( mw && SCIPisLT(scip, g->prize[l], 0.0) )
2380  dist = pathhead[l].dist + pathtail[l].dist + g->prize[l];
2381  else
2382  dist = pathhead[l].dist + pathtail[l].dist;
2383  if( SCIPisGT(scip, sd, dist) )
2384  sd = dist;
2385  }
2386  }
2387 
2388  statetail[l] = UNKNOWN;
2389  pathtail[l].dist = FARAWAY;
2390  pathtail[l].edge = UNKNOWN;
2391  }
2392  /* restore state and path of tail and head */
2393  for( k = 0; k < nlblhead; k++ )
2394  {
2395  l = memlblhead[k];
2396  statehead[l] = UNKNOWN;
2397  pathhead[l].dist = FARAWAY;
2398  pathhead[l].edge = UNKNOWN;
2399  }
2400 
2401 
2402  for( k = 0; k < nnodes; k++ )
2403  {
2404  assert(statetail[k] == UNKNOWN);
2405  assert(pathtail[k].dist == FARAWAY);
2406  assert(pathtail[k].edge == UNKNOWN);
2407  assert(statehead[k] == UNKNOWN);
2408  assert(pathhead[k].dist == FARAWAY);
2409  assert(pathhead[k].edge == UNKNOWN);
2410  }
2411 
2412 
2413  l = 0;
2414  /* compare restricted sd with edge cost (if existing) */
2415  for( e = g->outbeg[i]; (l++ <= limit) && (e != EAT_LAST); e = g->oeat[e] )
2416  {
2417  if( g->head[e] == i2 )
2418  {
2419  if( mw )
2420  sd = 0.0;
2421  else if( SCIPisGT(scip, sd, g->cost[e]) )
2422  sd = g->cost[e];
2423  break;
2424  }
2425  }
2426 
2427  *sdist = sd;
2428  return SCIP_OKAY;
2429 }
2430 
2431 
2432 /** gets special distance to a pair of nodes */
2434  const GRAPH* g, /**< graph structure */
2435  int i, /**< first vertex */
2436  int i2, /**< second vertex */
2437  SCIP_Real sd_upper, /**< upper bound on special distance that is accepted (can be FARAWAY) */
2438  SCIP_Real sd_sufficient, /**< bound below which to terminate (can be 0.0) */
2439  SD* sddata /**< SD */
2440  )
2441 {
2442  assert(g && sddata);
2443 
2444  return sdGetSd(g, i, i2, sd_upper, sd_sufficient, FALSE, sddata);
2445 }
2446 
2447 /** gets special distance to a pair of nodes,
2448  * but only allows SDs with intermediate terminals */
2450  const GRAPH* g, /**< graph structure */
2451  int i, /**< first vertex */
2452  int i2, /**< second vertex */
2453  SCIP_Real sd_upper, /**< upper bound on special distance that is accepted (can be FARAWAY) */
2454  SCIP_Real sd_sufficient, /**< bound below which to terminate (can be 0.0) */
2455  SD* sddata /**< SD */
2456  )
2457 {
2458  assert(g && sddata);
2459 
2460  return sdGetSd(g, i, i2, sd_upper, sd_sufficient, TRUE, sddata);
2461 }
2462 
2463 
2464 /** get SD to a single edge*/
2465 static
2467  SCIP* scip,
2468  const GRAPH* g,
2469  SCIP_Real distlimit,
2470  int i,
2471  int i2,
2472  int edgelimit,
2473  SD1PC* sd1pc
2474  )
2475 {
2476  PATH *pathtail = sd1pc->pathtail;
2477  PATH *pathhead = sd1pc->pathhead;
2478  int *heap = sd1pc->heap;
2479  int *statetail = sd1pc->statetail;
2480  int *statehead = sd1pc->statehead;
2481  int *memlbltail = sd1pc->memlbltail;
2482  int *memlblhead = sd1pc->memlblhead;
2483  int *pathmaxnodetail = sd1pc->pathmaxnodetail;
2484  int *pathmaxnodehead = sd1pc->pathmaxnodehead;
2485  SCIP_Real sd;
2486  int nlbltail;
2487  int nlblhead;
2488  const int nnodes = g->knots;
2489  const SCIP_Bool mw = g->stp_type == STP_MWCSP;
2490 
2491  assert((g->stp_type == STP_PCSPG || g->stp_type == STP_RPCSPG) || mw);
2492  assert(g != NULL);
2493  assert(scip != NULL);
2494  assert(pathtail != NULL);
2495  assert(pathhead != NULL);
2496  assert(heap != NULL);
2497  assert(statetail != NULL);
2498  assert(statehead != NULL);
2499  assert(memlbltail != NULL);
2500  assert(memlblhead != NULL);
2501  assert(pathmaxnodetail != NULL);
2502  assert(pathmaxnodehead != NULL);
2503 
2504  graph_path_PcMwSd(scip, g, pathtail, g->cost, distlimit, pathmaxnodetail, heap, statetail, NULL, memlbltail, &nlbltail, i, i2, edgelimit);
2505  graph_path_PcMwSd(scip, g, pathhead, g->cost, distlimit, pathmaxnodehead, heap, statehead, statetail, memlblhead, &nlblhead, i2, i, edgelimit);
2506 
2507  sd = distlimit;
2508 
2509  /* get restore state and path of tail and head */
2510  for( int k = 0; k < nlbltail; k++ )
2511  {
2512  const int l = memlbltail[k];
2513  assert(statetail[l] != UNKNOWN);
2514 
2515  if( statehead[l] != UNKNOWN )
2516  {
2517  SCIP_Real dist = FARAWAY;
2518  const int tailmaxterm = pathmaxnodetail[l];
2519  const int headmaxterm = pathmaxnodehead[l];
2520 
2521  assert(SCIPisGT(scip, FARAWAY, pathtail[l].dist));
2522  assert(SCIPisGT(scip, FARAWAY, pathhead[l].dist));
2523  assert(tailmaxterm != i && headmaxterm != i);
2524  assert(tailmaxterm != i2 && headmaxterm != i2);
2525 
2526  /* any terminal on the path? */
2527  if( tailmaxterm >= 0 || headmaxterm >= 0 )
2528  {
2529  if( tailmaxterm == headmaxterm )
2530  {
2531  assert(tailmaxterm == l);
2532  assert(SCIPisPositive(scip, g->prize[tailmaxterm]));
2533 
2534  dist = miscstp_maxReal((SCIP_Real []) {
2535  pathhead[headmaxterm].dist,
2536  pathtail[tailmaxterm].dist,
2537  pathhead[l].dist + pathtail[l].dist - g->prize[l]
2538  }, 3);
2539  SCIPdebugMessage("sd1 %f \n", dist);
2540  }
2541  else if( tailmaxterm >= 0 && headmaxterm >= 0 )
2542  {
2543  const SCIP_Real distl2tailmax = pathtail[l].dist - pathtail[tailmaxterm].dist;
2544  const SCIP_Real distl2headmax = pathhead[l].dist - pathhead[headmaxterm].dist;
2545 
2546  assert(tailmaxterm != headmaxterm);
2547  assert(!SCIPisNegative(scip, distl2tailmax));
2548  assert(!SCIPisNegative(scip, distl2headmax));
2549  assert(SCIPisPositive(scip, g->prize[tailmaxterm]) && SCIPisPositive(scip, g->prize[headmaxterm]));
2550 
2551  dist = miscstp_maxReal((SCIP_Real []) {
2552  pathhead[headmaxterm].dist,
2553  pathtail[tailmaxterm].dist,
2554  distl2tailmax + distl2headmax,
2555  distl2tailmax + pathhead[l].dist - g->prize[headmaxterm],
2556  distl2headmax + pathtail[l].dist - g->prize[tailmaxterm],
2557  pathhead[l].dist + pathtail[l].dist - g->prize[tailmaxterm] - g->prize[headmaxterm]
2558  }, 6);
2559  SCIPdebugMessage("sd2 %f \n", dist);
2560  }
2561  else if( tailmaxterm >= 0 )
2562  {
2563  const SCIP_Real distl2tailmax = pathtail[l].dist - pathtail[tailmaxterm].dist;
2564 
2565  assert(headmaxterm < 0);
2566  assert(SCIPisPositive(scip, g->prize[tailmaxterm]));
2567 
2568  dist = miscstp_maxReal((SCIP_Real []) {
2569  pathtail[tailmaxterm].dist,
2570  distl2tailmax + pathhead[l].dist,
2571  pathhead[l].dist + pathtail[l].dist - g->prize[tailmaxterm]
2572  }, 3);
2573  SCIPdebugMessage("sd3 %f \n", dist);
2574  }
2575  else if( headmaxterm >= 0 )
2576  {
2577  const SCIP_Real distl2headmax = pathhead[l].dist - pathhead[headmaxterm].dist;
2578 
2579  assert(tailmaxterm < 0);
2580  assert(SCIPisPositive(scip, g->prize[headmaxterm]));
2581 
2582  dist = miscstp_maxReal((SCIP_Real []) {
2583  pathhead[headmaxterm].dist,
2584  distl2headmax + pathtail[l].dist,
2585  pathhead[l].dist + pathtail[l].dist - g->prize[headmaxterm]
2586  }, 3);
2587  SCIPdebugMessage("sd4 %f \n", dist);
2588  }
2589  }
2590  else
2591  {
2592  dist = pathhead[l].dist + pathtail[l].dist;
2593  }
2594 
2595  if( dist < sd )
2596  sd = dist;
2597 
2598  if( Is_term(g->term[l]) )
2599  {
2600  dist = miscstp_maxReal((SCIP_Real []) {
2601  pathhead[l].dist,
2602  pathtail[l].dist,
2603  pathhead[l].dist + pathtail[l].dist - g->prize[l]
2604  }, 3);
2605  if( dist < sd )
2606  sd = dist;
2607  }
2608  }
2609  }
2610 
2611  /* restore state and path of tail and head */
2612 
2613  for( int k = 0; k < nlbltail; k++ )
2614  {
2615  const int l = memlbltail[k];
2616  statetail[l] = UNKNOWN;
2617  pathtail[l].dist = FARAWAY;
2618  pathtail[l].edge = UNKNOWN;
2619  pathmaxnodetail[l] = -1;
2620  }
2621 
2622  for( int k = 0; k < nlblhead; k++ )
2623  {
2624  const int l = memlblhead[k];
2625  statehead[l] = UNKNOWN;
2626  pathhead[l].dist = FARAWAY;
2627  pathhead[l].edge = UNKNOWN;
2628  pathmaxnodehead[l] = -1;
2629  }
2630 
2631  for( int k = 0; k < nnodes; k++ )
2632  {
2633  assert(statetail[k] == UNKNOWN);
2634  assert(pathtail[k].dist == FARAWAY);
2635  assert(pathtail[k].edge == UNKNOWN);
2636  assert(statehead[k] == UNKNOWN);
2637  assert(pathhead[k].dist == FARAWAY);
2638  assert(pathhead[k].edge == UNKNOWN);
2639  assert(pathmaxnodehead[k] == -1);
2640  assert(pathmaxnodetail[k] == -1);
2641  }
2642 
2643  /* compare restricted sd with edge cost (if existing) */
2644  for( int e = g->outbeg[i], count = 0; (count++ <= edgelimit) && (e != EAT_LAST); e = g->oeat[e] )
2645  {
2646  if( g->head[e] == i2 )
2647  {
2648  if( mw )
2649  sd = 0.0;
2650  else if( sd > g->cost[e] )
2651  sd = g->cost[e];
2652  break;
2653  }
2654  }
2655 
2656  return sd;
2657 }
2658 
2659 
2660 /** SDC test for the SAP using a limited version of Dijkstra's algorithm from both endpoints of an arc */
2662  SCIP* scip, /**< SCIP data structure */
2663  GRAPH* g, /**< graph data structure */
2664  PATH* pathtail, /**< path tails */
2665  PATH* pathhead, /**< path heads */
2666  int* heap, /**< heap */
2667  int* statetail, /**< states of tails */
2668  int* statehead, /**< states of heads */
2669  int* memlbltail, /**< storage for tails */
2670  int* memlblhead, /**< storage for heads */
2671  int* nelims, /**< number of eliminations */
2672  int limit /**< limit for number of visits */
2673  )
2674 {
2675  SCIP_Real sdist;
2676  SCIP_Real* costrev;
2677  int i;
2678  int k;
2679  int l;
2680  int e;
2681  int i2;
2682  int enext;
2683  int nnodes;
2684  int nedges;
2685  int nlbltail;
2686  int nlblhead;
2687 
2688  assert(g != NULL);
2689  assert(scip != NULL);
2690  assert(pathtail != NULL);
2691  assert(pathhead != NULL);
2692  assert(heap != NULL);
2693  assert(statetail != NULL);
2694  assert(statehead != NULL);
2695  assert(memlbltail != NULL);
2696  assert(memlblhead != NULL);
2697  assert(nelims != NULL);
2698 
2699  nedges = g->edges;
2700  nnodes = g->knots;
2701  *nelims = 0;
2702 
2703  for( i = 0; i < nnodes; i++ )
2704  {
2705  g->mark[i] = (g->grad[i] > 0);
2706  statetail[i] = UNKNOWN;
2707  pathtail[i].dist = FARAWAY;
2708  pathtail[i].edge = UNKNOWN;
2709  statehead[i] = UNKNOWN;
2710  pathhead[i].dist = FARAWAY;
2711  pathhead[i].edge = UNKNOWN;
2712  }
2713 
2714  SCIP_CALL( SCIPallocBufferArray(scip, &costrev, nedges) );
2715 
2716  for( e = 0; e < nedges; e++ )
2717  costrev[e] = g->cost[flipedge(e)];
2718 
2719  /* iterate through all nodes */
2720  for( i = 0; i < nnodes; i++ )
2721  {
2722  if( !g->mark[i] )
2723  continue;
2724  /* traverse neighbours */
2725  e = g->outbeg[i];
2726  while( e != EAT_LAST )
2727  {
2728  enext = g->oeat[e];
2729  i2 = g->head[e];
2730 
2731  assert(g->mark[i2]);
2732 
2733  /* start limited dijkstra from i, marking all reached vertices */
2734  graph_sdPaths(g, pathtail, g->cost, g->cost[e], heap, statetail, memlbltail, &nlbltail, i, i2, limit);
2735 
2736  /* start limited dijkstra from i2, marking all reached vertices */
2737  graph_sdPaths(g, pathhead, costrev, g->cost[e], heap, statehead, memlblhead, &nlblhead, i2, i, limit);
2738 
2739  sdist = FARAWAY;
2740 #ifdef SCIP_DISABLED
2741  if( statetail[i2] != UNKNOWN )
2742  {
2743  sdist = pathtail[i2].dist;
2744  assert(SCIPisGT(scip, FARAWAY, sdist));
2745  }
2746  if( statehead[i] != UNKNOWN && SCIPisGT(scip, sdist, pathhead[i].dist) )
2747  {
2748  sdist = pathhead[i].dist;
2749  assert(SCIPisGT(scip, FARAWAY, sdist));
2750  }
2751 #endif
2752  /* get restore state and path of tail and head */
2753  for( k = 0; k < nlbltail; k++ )
2754  {
2755  l = memlbltail[k];
2756  assert(g->mark[l]);
2757  assert(statetail[l] != UNKNOWN);
2758  if( statehead[l] != UNKNOWN )
2759  {
2760  assert(SCIPisGT(scip, FARAWAY, pathtail[l].dist));
2761  assert(SCIPisGT(scip, FARAWAY, pathhead[l].dist));
2762 
2763  if( SCIPisGT(scip, sdist, pathhead[l].dist + pathtail[l].dist) )
2764  sdist = pathhead[l].dist + pathtail[l].dist;
2765  }
2766 
2767  statetail[l] = UNKNOWN;
2768  pathtail[l].dist = FARAWAY;
2769  pathtail[l].edge = UNKNOWN;
2770  }
2771  /* restore state and path of tail and head */
2772  for( k = 0; k < nlblhead; k++ )
2773  {
2774  l = memlblhead[k];
2775  statehead[l] = UNKNOWN;
2776  pathhead[l].dist = FARAWAY;
2777  pathhead[l].edge = UNKNOWN;
2778  }
2779 
2780  /* can edge be deleted? */
2781  if( SCIPisGE(scip, g->cost[e], sdist) )
2782  {
2783  if( SCIPisGE(scip, costrev[e], FARAWAY) )
2784  {
2785  graph_edge_del(scip, g, e, TRUE);
2786  (*nelims)++;
2787  }
2788  else
2789  {
2790  if( SCIPisLT(scip, g->cost[e], FARAWAY) )
2791  (*nelims)++;
2792 
2793  g->cost[e] = FARAWAY;
2794  costrev[flipedge(e)] = FARAWAY;
2795  }
2796  }
2797 
2798  e = enext;
2799  }
2800  }
2801 
2802  for( k = 0; k < nnodes; k++ )
2803  {
2804  assert(statetail[k] == UNKNOWN);
2805  assert(pathtail[k].dist == FARAWAY);
2806  assert(pathtail[k].edge == UNKNOWN);
2807  assert(statehead[k] == UNKNOWN);
2808  assert(pathhead[k].dist == FARAWAY);
2809  assert(pathhead[k].edge == UNKNOWN);
2810  }
2811 
2812  SCIPfreeBufferArray(scip, &costrev);
2813 
2814  return SCIP_OKAY;
2815 }
2816 
2817 /** SD test for PcMw using only limited Dijkstra-like walk from both endpoints of an edge */
2819  SCIP* scip, /**< SCIP data structure */
2820  int edgelimit, /**< edge limit */
2821  const int* edgestate, /**< per edge: state */
2822  GRAPH* g, /**< graph data structure */
2823  int* termmark, /**< per node: terminal property */
2824  SCIP_Real* dist, /**< per node: distance */
2825  int* visitlist, /**< array to store visited nodes */
2826  STP_Bool* visited, /**< per node: was visited? */
2827  DHEAP* dheap, /**< head data structure */
2828  int* nelims /**< pointer to store number of eliminations */
2829  )
2830 {
2831  DCSR* dcsr;
2832  RANGE* range_csr;
2833  int* head_csr;
2834  int* edgeid_csr;
2835  SCIP_Real* cost_csr;
2836  SCIP_Bool* edge_deletable;
2837  const int nnodes = g->knots;
2838  const int nedges = g->edges;
2839  const SCIP_Bool checkstate = (edgestate != NULL);
2840 
2841  assert(g && scip && nelims && visited && visitlist && dheap);
2842  assert(!g->extended);
2843  assert(graph_pc_isPcMw(g));
2844 
2845  if( edgelimit <= 0 )
2846  return SCIP_OKAY;
2847 
2848  for( int i = 0; i < nnodes; i++ )
2849  {
2850  visited[i] = FALSE;
2851  dist[i] = FARAWAY;
2852  }
2853 
2854  graph_heap_clean(TRUE, dheap);
2855  graph_init_dcsr(scip, g);
2856 
2857  dcsr = g->dcsr_storage;
2858  range_csr = dcsr->range;
2859  head_csr = dcsr->head;
2860  edgeid_csr = dcsr->edgeid;
2861  cost_csr = dcsr->cost;
2862 
2863  SCIP_CALL( SCIPallocBufferArray(scip, &edge_deletable, nedges / 2) );
2864 
2865  for( int e = 0; e < nedges / 2; e++ )
2866  edge_deletable[e] = FALSE;
2867 
2868  assert(dcsr && range_csr && edgeid_csr && cost_csr);
2869 
2870  graph_pc_termMarkProper(g, termmark);
2871 
2872  for( int i = 0; i < nnodes; i++ )
2873  {
2874  int enext;
2875  const int start = range_csr[i].start;
2876 
2877  /* degree <= 1? */
2878  if( range_csr[i].end - start <= 1 )
2879  continue;
2880 
2881  /* traverse neighbours */
2882  for( int e = start; e < range_csr[i].end; e = enext )
2883  {
2884  SCIP_Bool success;
2885  const SCIP_Real ecost = cost_csr[e];
2886  int nvisits;
2887  const int i2 = head_csr[e];
2888 
2889  assert(g->mark[i] && g->mark[i2]);
2890 
2891  enext = e + 1;
2892 
2893  if( checkstate )
2894  {
2895  const int orgedge = edgeid_csr[e];
2896  if( edgestate[orgedge] == EDGE_BLOCKED )
2897  continue;
2898  }
2899 
2900  success = graph_sdWalks_csr(scip, g, termmark, ecost, i, i2, edgelimit, dist, visitlist, &nvisits, dheap, visited);
2901  sdwalkReset(nnodes, nvisits, visitlist, dist, dheap->position, visited);
2902  graph_heap_clean(FALSE, dheap);
2903 
2904  if( success )
2905  {
2906  edge_deletable[edgeid_csr[e] / 2] = TRUE;
2907  graph_dcsr_deleteEdgeBi(scip, dcsr, e);
2908 
2909  (*nelims)++;
2910  enext--;
2911 
2912  if( range_csr[i].end - start <= 1 )
2913  break;
2914  }
2915  }
2916  }
2917 
2918 #ifndef NDEBUG
2919  for( int e = 0; e < nedges / 2; e++ )
2920  {
2921  if( edge_deletable[e] )
2922  assert(dcsr->id2csredge[e * 2] == -1);
2923  else if( g->oeat[e * 2] != EAT_FREE )
2924  assert(dcsr->id2csredge[e * 2] != -1 || !g->mark[g->tail[e * 2]] || !g->mark[g->head[e * 2]]);
2925  }
2926 #endif
2927 
2928  graph_edge_delBlocked(scip, g, edge_deletable, TRUE);
2929 
2930  SCIPfreeBufferArray(scip, &edge_deletable);
2931 
2932  graph_free_dcsr(scip, g);
2933 
2934  return SCIP_OKAY;
2935 }
2936 
2937 
2938 /** SD test */
2940  SCIP* scip, /**< SCIP data structure */
2941  int edgelimit, /**< edge limit */
2942  GRAPH* g, /**< graph data structure */
2943  int* nelims /**< number of eliminations */
2944 )
2945 {
2946  const int nnodes = graph_get_nNodes(g);
2947  SDPROFIT* sdprofit;
2948  SCIP_Real sds = FARAWAY;
2949  int cliquenodes[2];
2950  SDCLIQUE cliquedata = { .dijkdata = NULL, .cliquenodes = cliquenodes, .ncliquenodes = 2, .sds = &sds };
2951 
2952  SCIP_CALL( graph_dijkLimited_init(scip, g, &(cliquedata.dijkdata)) );
2953  graph_dijkLimited_clean(g, (cliquedata.dijkdata));
2954  cliquedata.dijkdata->edgelimit = edgelimit;
2955  SCIP_CALL( reduce_sdprofitInit(scip, g, &sdprofit) );
2956 
2957  graph_mark(g);
2958 
2959  SCIPdebugMessage("Starting SD biased... \n");
2960 
2961  /* traverse all edges */
2962  for( int i = 0; i < nnodes; i++ )
2963  {
2964  int enext;
2965  if( !g->mark[i] )
2966  continue;
2967 
2968  enext = g->outbeg[i];
2969  while( enext != EAT_LAST )
2970  {
2971  const int e = enext;
2972  const int i2 = g->head[e];
2973  const SCIP_Real ecost = g->cost[e];
2974 
2975  enext = g->oeat[e];
2976 
2977  if( i2 < i || !g->mark[i2] )
2978  continue;
2979 
2980  sds = ecost;
2981  cliquenodes[0] = i;
2982  cliquenodes[1] = i2;
2983  SCIP_CALL( graph_sdComputeCliqueStar(scip, g, sdprofit, &cliquedata) );
2984 
2985  graph_dijkLimited_reset(g, cliquedata.dijkdata);
2986 
2987  // todo LT
2988  if( SCIPisLT(scip, sds, ecost) )
2989  {
2990 #ifdef SCIP_DEBUG
2991  printf("SD biased deletes (sd=%f): ", sds);
2992  graph_edge_printInfo(g, e);
2993 #endif
2994 
2995  graph_edge_del(scip, g, e, TRUE);
2996  (*nelims)++;
2997 
2998  break;
2999  }
3000  }
3001  }
3002 
3003  reduce_sdprofitFree(scip, &sdprofit);
3004  graph_dijkLimited_free(scip, &(cliquedata.dijkdata));
3005 
3006  return SCIP_OKAY;
3007 }
3008 
3009 
3010 /** SD test for PcMw using limited Dijkstra-like walk from both endpoints of an edge */
3012  SCIP* scip, /**< SCIP data structure */
3013  int edgelimit, /**< edge limit */
3014  SCIP_Bool usestrongreds, /**< allow strong reductions? */
3015  GRAPH* g, /**< graph data structure */
3016  int* termmark, /**< terminal mark */
3017  SCIP_Real* dist, /**< distances */
3018  int* visitlist, /**< array to store visited nodes */
3019  STP_Bool* visited, /**< per node: was visited? */
3020  DHEAP* dheap, /**< heap data structure */
3021  int* nelims /**< number of eliminations */
3022  )
3023 {
3024  DCSR* dcsr;
3025  RANGE* range_csr;
3026  int* head_csr;
3027  int* edgeid_csr;
3028  int* state2;
3029  int* visitlist2;
3030  SCIP_Real* dist2;
3031  SCIP_Real* cost_csr;
3032  SCIP_Real* prizeoffset;
3033  SCIP_Bool* edge_deletable;
3034  STP_Bool* visited2;
3035  const int nnodes = g->knots;
3036  const int nedges = g->edges;
3037 
3038  assert(g && scip && nelims && visited && visitlist && dheap);
3039  assert(!g->extended);
3040  assert(graph_pc_isPcMw(g));
3041 
3042  if( edgelimit <= 0 )
3043  return SCIP_OKAY;
3044 
3045  graph_heap_clean(TRUE, dheap);
3046  graph_init_dcsr(scip, g);
3047 
3048  dcsr = g->dcsr_storage;
3049  range_csr = dcsr->range;
3050  head_csr = dcsr->head;
3051  edgeid_csr = dcsr->edgeid;
3052  cost_csr = dcsr->cost;
3053 
3054  SCIP_CALL( SCIPallocBufferArray(scip, &dist2, nnodes) );
3055  SCIP_CALL( SCIPallocBufferArray(scip, &state2, nnodes) );
3056  SCIP_CALL( SCIPallocBufferArray(scip, &visited2, nnodes) );
3057  SCIP_CALL( SCIPallocBufferArray(scip, &visitlist2, nnodes) );
3058  SCIP_CALL( SCIPallocBufferArray(scip, &prizeoffset, nnodes) );
3059  SCIP_CALL( SCIPallocBufferArray(scip, &edge_deletable, nedges / 2) );
3060 
3061  for( int i = 0; i < nnodes; i++ )
3062  {
3063  visited[i] = FALSE;
3064  visited2[i] = FALSE;
3065  dist[i] = FARAWAY;
3066  dist2[i] = FARAWAY;
3067  state2[i] = UNKNOWN;
3068  }
3069 
3070  for( int e = 0; e < nedges / 2; e++ )
3071  edge_deletable[e] = FALSE;
3072 
3073  assert(dcsr && range_csr && edgeid_csr && cost_csr);
3074 
3075  graph_pc_termMarkProper(g, termmark);
3076 
3077  /* main loop */
3078  for( int i = 0; i < nnodes; i++ )
3079  {
3080  int enext;
3081  const int start = range_csr[i].start;
3082 
3083  /* degree <= 1? */
3084  if( range_csr[i].end - start <= 1 )
3085  continue;
3086 
3087  /* traverse neighbors of i */
3088  for( int e = start; e < range_csr[i].end; e = enext )
3089  {
3090  SCIP_Bool success;
3091  const SCIP_Real ecost = cost_csr[e];
3092  int nvisits;
3093  const int i2 = head_csr[e];
3094 
3095  assert(g->mark[i] && g->mark[i2]);
3096 
3097  enext = e + 1;
3098 
3099  /* avoid double checking */
3100  if( i2 < i )
3101  continue;
3102 
3103  success = graph_sdWalksTriangle(scip, g, termmark, NULL, ecost, i, i2, edgelimit, NULL, dist, visitlist, &nvisits, dheap, visited);
3104 
3105  /* could not reach i2? */
3106  if( !success )
3107  {
3108  int nvisits2;
3109  int* const state = dheap->position;
3110 
3111  dheap->position = state2;
3112  graph_heap_clean(FALSE, dheap);
3113 
3114 #ifndef NDEBUG
3115  for( int k = 0; k < nnodes; k++ )
3116  prizeoffset[k] = -FARAWAY;
3117 #endif
3118 
3119  /* run from i2 */
3120  success = graph_sdWalksTriangle(scip, g, termmark, state, ecost, i2, i, edgelimit, prizeoffset, dist2, visitlist2, &nvisits2, dheap, visited2);
3121 
3122  /* could not reach i1? */
3123  if( !success )
3124  {
3125  assert(nvisits2 > 0 && visitlist2[0] == i2);
3126 
3127  /* maybe we can connect two walks */
3128  for( int k = 1; k < nvisits2; k++ )
3129  {
3130  const int node = visitlist2[k];
3131  SCIP_Real dist_combined;
3132 
3133  assert(visited2[node]);
3134  assert(node != i && node != i2);
3135 
3136  if( !visited[node] )
3137  continue;
3138 
3139  dist_combined = dist[node] + dist2[node];
3140  assert(dist_combined < FARAWAY);
3141 
3142  if( termmark[node] != 0 )
3143  {
3144  dist_combined += prizeoffset[node];
3145  assert(prizeoffset[node] >= 0.0);
3146  }
3147 
3148  if( SCIPisLE(scip, dist_combined, ecost) )
3149  {
3150  success = TRUE;
3151  break;
3152  }
3153  }
3154  }
3155 
3156  dheap->position = state;
3157  sdwalkReset(nnodes, nvisits2, visitlist2, dist2, state2, visited2);
3158  }
3159 
3160  sdwalkReset(nnodes, nvisits, visitlist, dist, dheap->position, visited);
3161  graph_heap_clean(FALSE, dheap);
3162 
3163  if( success )
3164  {
3165  edge_deletable[edgeid_csr[e] / 2] = TRUE;
3166  graph_dcsr_deleteEdgeBi(scip, dcsr, e);
3167 
3168  (*nelims)++;
3169  enext--;
3170 
3171  if( range_csr[i].end - start <= 1 )
3172  break;
3173  }
3174  }
3175  }
3176 
3177 #ifndef NDEBUG
3178  for( int e = 0; e < nedges / 2; e++ )
3179  {
3180  if( edge_deletable[e] )
3181  assert(dcsr->id2csredge[e * 2] == -1);
3182  else if( g->oeat[e * 2] != EAT_FREE )
3183  assert(dcsr->id2csredge[e * 2] != -1 || !g->mark[g->tail[e * 2]] || !g->mark[g->head[e * 2]]);
3184  }
3185 #endif
3186 
3187  graph_edge_delBlocked(scip, g, edge_deletable, TRUE);
3188 
3189  SCIPfreeBufferArray(scip, &edge_deletable);
3190  SCIPfreeBufferArray(scip, &prizeoffset);
3191  SCIPfreeBufferArray(scip, &visitlist2);
3192  SCIPfreeBufferArray(scip, &visited2);
3193  SCIPfreeBufferArray(scip, &state2);
3194  SCIPfreeBufferArray(scip, &dist2);
3195 
3196  graph_free_dcsr(scip, g);
3197 
3198  return SCIP_OKAY;
3199 }
3200 
3201 /** SD star test for PcMw and SPG */
3203  SCIP* scip, /**< SCIP data structure */
3204  int edgelimit, /**< limit */
3205  SCIP_Bool usestrongreds, /**< allow strong reductions? */
3206  GRAPH* g, /**< graph data structure */
3207  SCIP_Real* dist, /**< vertex distances */
3208  int* star_base, /**< array of size nnodes */
3209  int* visitlist, /**< array of size nnodes */
3210  STP_Bool* visited, /**< array of size nnodes */
3211  DHEAP* dheap, /**< Dijkstra heap */
3212  int* nelims /**< point to store number of deleted edges */
3213  )
3214 {
3215  DCSR* dcsr;
3216  RANGE* range_csr;
3217  int* head_csr;
3218  int* edgeid_csr;
3219  SCIP_Bool* edge_deletable;
3220  const int nnodes = g->knots;
3221  const int nedges = g->edges;
3222 
3223  assert(g && scip && nelims && visited && visitlist && dheap && star_base);
3224  assert(!graph_pc_isPcMw(g) || !g->extended);
3225 
3226  if( edgelimit <= 0 )
3227  return SCIP_OKAY;
3228 
3229  graph_heap_clean(TRUE, dheap);
3230  SCIP_CALL( graph_init_dcsr(scip, g) );
3231 
3232  dcsr = g->dcsr_storage;
3233  range_csr = dcsr->range;
3234  head_csr = dcsr->head;
3235  edgeid_csr = dcsr->edgeid;
3236 
3237  SCIP_CALL( SCIPallocBufferArray(scip, &edge_deletable, nedges / 2) );
3238 
3239  for( int e = 0; e < nedges / 2; e++ )
3240  edge_deletable[e] = FALSE;
3241 
3242  assert(dcsr && range_csr && edgeid_csr);
3243 
3244  for( int i = 0; i < nnodes; i++ )
3245  {
3246  visited[i] = FALSE;
3247  dist[i] = FARAWAY;
3248  star_base[i] = SDSTAR_BASE_UNSET;
3249  }
3250 
3251  for( int i = 0; i < nnodes; i++ )
3252  {
3253  SCIP_Bool runloop;
3254 
3255  if( !g->mark[i] )
3256  {
3257  assert(g->grad[i] == 2 || g->grad[i] == 0 || i == g->source);
3258  continue;
3259  }
3260 
3261  runloop = TRUE;
3262 
3263  while( runloop )
3264  {
3265  SCIP_Bool success;
3266  int nvisits;
3267  const int start = range_csr[i].start;
3268 
3269  if( range_csr[i].end - start <= 1 )
3270  break;
3271 
3272  runloop = FALSE;
3273 
3274  /* do the actual star run */
3275  graph_sdStar(scip, g, FALSE, i, edgelimit, star_base, dist, visitlist, &nvisits, dheap, visited, &success);
3276 
3277  if( success )
3278  {
3279  int enext;
3280 
3281  /* check all star nodes (neighbors of i) */
3282  for( int e = start; e < range_csr[i].end; e = enext )
3283  {
3284  const int starnode = head_csr[e];
3285  const int starbase = star_base[starnode];
3286  assert(star_base[starnode] >= 0);
3287  assert(SCIPisLE(scip, dist[starnode], dcsr->cost[e]));
3288  assert(star_base[starnode] == starnode || star_base[starnode] >= 0);
3289 
3290  enext = e + 1;
3291 
3292  /* shorter path to current star node found? */
3293  if( starnode != starbase )
3294  {
3295  assert(star_base[starbase] != SDSTAR_BASE_UNSET);
3296 
3297  star_base[starnode] = SDSTAR_BASE_KILLED;
3298  edge_deletable[edgeid_csr[e] / 2] = TRUE;
3299  graph_dcsr_deleteEdgeBi(scip, dcsr, e);
3300 
3301  (*nelims)++;
3302  enext--;
3303  }
3304  } /* traverse star nodes */
3305  } /* if success */
3306 
3307  sdStarReset(nnodes, nvisits, visitlist, star_base, dist, visited, dheap);
3308  }
3309  }
3310 
3311 #ifndef NDEBUG
3312  for( int e = 0; e < nedges / 2; e++ )
3313  {
3314  if( edge_deletable[e] )
3315  assert(dcsr->id2csredge[e * 2] == -1);
3316  else if( g->oeat[e * 2] != EAT_FREE )
3317  assert(dcsr->id2csredge[e * 2] != -1 || !g->mark[g->tail[e * 2]] || !g->mark[g->head[e * 2]]);
3318  }
3319 #endif
3320 
3321  graph_edge_delBlocked(scip, g, edge_deletable, TRUE);
3322 
3323  SCIPfreeBufferArray(scip, &edge_deletable);
3324 
3325  graph_free_dcsr(scip, g);
3326 
3327  return SCIP_OKAY;
3328 }
3329 
3330 
3331 /** SD star test for PcMw and SPG */
3333  SCIP* scip, /**< SCIP data structure */
3334  int edgelimit, /**< limit */
3335  SCIP_Bool usestrongreds, /**< allow strong reductions? */
3336  GRAPH* g, /**< graph data structure */
3337  int* nelims /**< point to store number of deleted edges */
3338  )
3339 {
3340  SDPROFIT* sdprofit;
3341 
3342  assert(scip && nelims);
3343 
3344  SCIP_CALL( reduce_sdprofitInit(scip, g, &sdprofit) );
3345  SCIP_CALL( reduce_sdStarBiasedWithProfit(scip, edgelimit, sdprofit, usestrongreds, g, nelims) );
3346  reduce_sdprofitFree(scip, &sdprofit);
3347 
3348  return SCIP_OKAY;
3349 }
3350 
3351 
3352 /** SD star test for PcMw and SPG */
3354  SCIP* scip, /**< SCIP data structure */
3355  int edgelimit, /**< limit */
3356  const SDPROFIT* sdprofit, /**< with profit given */
3357  SCIP_Bool usestrongreds, /**< allow strong reductions? */
3358  GRAPH* g, /**< graph data structure */
3359  int* nelims /**< point to store number of deleted edges */
3360  )
3361 {
3362  DIJK* dijkdata;
3363 
3364  int* RESTRICT star_base;
3365  SCIP_Bool* RESTRICT edge_deletable;
3366  const int nnodes = graph_get_nNodes(g);
3367 
3368  assert(scip && nelims);
3369  assert(edgelimit > 0);
3370 
3371  graph_init_dcsr(scip, g);
3372 
3373  SCIP_CALL( sdStarInit(scip, g, edgelimit, &dijkdata, &star_base, &edge_deletable) );
3374 
3375  for( int i = 0; i < nnodes; i++ )
3376  {
3377  if( !g->mark[i] )
3378  {
3379  assert(g->grad[i] == 2 || g->grad[i] == 0 || i == g->source);
3380  continue;
3381  }
3382 
3383  SCIP_CALL( sdStarBiasedProcessNode(scip, i, usestrongreds, sdprofit, g, dijkdata, star_base, edge_deletable, nelims) );
3384  }
3385 
3386  sdStarFinalize(scip, g, &dijkdata, &star_base, &edge_deletable);
3387  graph_free_dcsr(scip, g);
3388 
3389  return SCIP_OKAY;
3390 }
3391 
3392 
3393 /** SD star test for PcMw */
3395  SCIP* scip, /**< SCIP data structure */
3396  int edgelimit, /**< limit */
3397  SCIP_Bool usestrongreds, /**< allow strong reductions? */
3398  GRAPH* g, /**< graph data structure */
3399  SCIP_Real* dist, /**< vertex distances */
3400  int* star_base, /**< array of size nnodes */
3401  int* visitlist, /**< array of size nnodes */
3402  STP_Bool* visited, /**< array of size nnodes */
3403  DHEAP* dheap, /**< Dijkstra heap */
3404  int* nelims /**< point to store number of deleted edges */
3405  )
3406 {
3407  DCSR* dcsr;
3408  RANGE* range_csr;
3409  SCIP_Real* cost_dcsr_org;
3410  SCIP_Real* cost_dcsr_biased;
3411  int* head_csr;
3412  int* edgeid_csr;
3413  SCIP_Bool* edge_deletable;
3414  const int nnodes = g->knots;
3415  const int nedges = g->edges;
3416 
3417  assert(g && scip && nelims && visited && visitlist && dheap && star_base);
3418  assert(graph_pc_isPcMw(g) && !g->extended);
3419 
3420  if( edgelimit <= 0 )
3421  return SCIP_OKAY;
3422 
3423  graph_mark(g);
3424  graph_heap_clean(TRUE, dheap);
3425  graph_init_dcsr(scip, g);
3426 
3427  dcsr = g->dcsr_storage;
3428  range_csr = dcsr->range;
3429  head_csr = dcsr->head;
3430  edgeid_csr = dcsr->edgeid;
3431  cost_dcsr_org = dcsr->cost;
3432 
3433  SCIP_CALL( SCIPallocBufferArray(scip, &edge_deletable, nedges / 2) );
3434  SCIP_CALL( SCIPallocBufferArray(scip, &cost_dcsr_biased, dcsr->nedges) );
3435 
3436  for( int e = 0; e < nedges / 2; e++ )
3437  edge_deletable[e] = FALSE;
3438 
3439  assert(dcsr && range_csr && edgeid_csr);
3440 
3441  pcBiasCostsDCSR(scip, g, FALSE, cost_dcsr_biased, dist);
3442 
3443  dcsr->cost = cost_dcsr_biased;
3444 
3445  for( int i = 0; i < nnodes; i++ )
3446  {
3447  visited[i] = FALSE;
3448  dist[i] = FARAWAY;
3449  star_base[i] = SDSTAR_BASE_UNSET;
3450  }
3451 
3452  for( int i = 0; i < nnodes; i++ )
3453  {
3454  SCIP_Bool runloop;
3455 
3456  if( !g->mark[i] )
3457  {
3458  assert(g->grad[i] == 2 || g->grad[i] == 0 || i == g->source);
3459  continue;
3460  }
3461 
3462  runloop = TRUE;
3463 
3464  while( runloop )
3465  {
3466  SCIP_Bool success;
3467  int nvisits;
3468  const int start = range_csr[i].start;
3469 
3470  if( range_csr[i].end - start <= 1 )
3471  break;
3472 
3473  runloop = FALSE;
3474 
3475  /* do the actual star run */
3476  graph_sdStar(scip, g, TRUE, i, 2 * edgelimit, star_base, dist, visitlist, &nvisits, dheap, visited, &success);
3477 
3478  if( success )
3479  {
3480  int enext;
3481 
3482  /* check all star nodes (neighbors of i) */
3483  for( int e = start; e < range_csr[i].end; e = enext )
3484  {
3485  const int starnode = head_csr[e];
3486  const int starbase = star_base[starnode];
3487  assert(star_base[starnode] >= 0);
3488  assert(SCIPisLE(scip, dist[starnode], dcsr->cost[e]));
3489  assert(star_base[starnode] == starnode || star_base[starnode] >= 0);
3490 
3491  enext = e + 1;
3492 
3493  /* shorter path to current star node found? */
3494  if( starnode != starbase )
3495  {
3496  assert(star_base[starbase] != SDSTAR_BASE_UNSET);
3497 
3498  if( !usestrongreds && EQ(dist[starnode], dcsr->cost[e]) )
3499  continue;
3500 
3501  star_base[starnode] = SDSTAR_BASE_KILLED;
3502  edge_deletable[edgeid_csr[e] / 2] = TRUE;
3503 
3504  dcsr->cost = cost_dcsr_org;
3505  dcsr->cost2 = cost_dcsr_biased;
3506  graph_dcsr_deleteEdgeBi(scip, dcsr, e);
3507  dcsr->cost = cost_dcsr_biased;
3508  dcsr->cost2 = NULL;
3509 
3510  (*nelims)++;
3511  enext--;
3512  }
3513  } /* traverse star nodes */
3514  } /* if success */
3515 
3516  sdStarReset(nnodes, nvisits, visitlist, star_base, dist, visited, dheap);
3517  }
3518  }
3519 
3520 #ifndef NDEBUG
3521  for( int e = 0; e < nedges / 2; e++ )
3522  {
3523  if( edge_deletable[e] )
3524  assert(dcsr->id2csredge[e * 2] == -1);
3525  else if( g->oeat[e * 2] != EAT_FREE )
3526  assert(dcsr->id2csredge[e * 2] != -1 || !g->mark[g->tail[e * 2]] || !g->mark[g->head[e * 2]]);
3527  }
3528 #endif
3529 
3530  graph_edge_delBlocked(scip, g, edge_deletable, TRUE);
3531 
3532  dcsr->cost = cost_dcsr_org;
3533 
3534  SCIPfreeBufferArray(scip, &cost_dcsr_biased);
3535  SCIPfreeBufferArray(scip, &edge_deletable);
3536 
3537  graph_free_dcsr(scip, g);
3538 
3539  return SCIP_OKAY;
3540 }
3541 
3542 
3543 
3544 /** SD star test for PcMw
3545  * NOTE: deprecated */
3547  SCIP* scip, /**< SCIP data structure */
3548  int edgelimit, /**< limit */
3549  const int* edgestate, /**< state array or NULL */
3550  GRAPH* g, /**< graph data structure */
3551  SCIP_Real* dist, /**< vertex distances */
3552  int* star_base, /**< array of size nnodes */
3553  int* visitlist, /**< array of size nnodes */
3554  STP_Bool* visited, /**< array of size nnodes */
3555  DHEAP* dheap, /**< Dijkstra heap */
3556  int* nelims /**< point to store number of deleted edges */
3557  )
3558 {
3559  DCSR* dcsr;
3560  RANGE* range_csr;
3561  int* head_csr;
3562  int* edgeid_csr;
3563  int* star_base_out;
3564  SCIP_Real* cost_csr;
3565  SCIP_Real* costbiased_out;
3566  SCIP_Real* costbiased_in;
3567  SCIP_Bool* edge_deletable;
3568  const int nnodes = g->knots;
3569  const int nedges = g->edges;
3570  const SCIP_Bool checkstate = (edgestate != NULL);
3571 
3572  assert(g && scip && nelims && visited && visitlist && dheap && star_base);
3573  assert(!graph_pc_isPcMw(g) || !g->extended);
3574 
3575  if( edgelimit <= 0 )
3576  return SCIP_OKAY;
3577 
3578  graph_heap_clean(TRUE, dheap);
3579  graph_init_dcsr(scip, g);
3580 
3581  dcsr = g->dcsr_storage;
3582  range_csr = dcsr->range;
3583  head_csr = dcsr->head;
3584  edgeid_csr = dcsr->edgeid;
3585  cost_csr = dcsr->cost;
3586 
3587  assert(dcsr && range_csr && edgeid_csr && cost_csr);
3588 
3589  SCIP_CALL( SCIPallocBufferArray(scip, &edge_deletable, nedges / 2) );
3590  SCIP_CALL( SCIPallocBufferArray(scip, &costbiased_out, dcsr->nedges) );
3591  SCIP_CALL( SCIPallocBufferArray(scip, &costbiased_in, dcsr->nedges) );
3592  SCIP_CALL( SCIPallocBufferArray(scip, &star_base_out, nnodes) );
3593 
3594  for( int e = 0; e < nedges / 2; e++ )
3595  edge_deletable[e] = FALSE;
3596 
3597  pcBiasCostsDCSR(scip, g, FALSE, costbiased_out, dist);
3598  pcBiasCostsDCSR(scip, g, TRUE, costbiased_in, dist);
3599 
3600  for( int i = 0; i < nnodes; i++ )
3601  {
3602  visited[i] = FALSE;
3603  dist[i] = FARAWAY;
3604  star_base[i] = SDSTAR_BASE_UNSET;
3605  star_base_out[i] = SDSTAR_BASE_UNSET;
3606  }
3607 
3608  for( int i = 0; i < nnodes; i++ )
3609  {
3610  SCIP_Bool runloop;
3611 
3612  if( !g->mark[i] )
3613  {
3614  assert(g->grad[i] == 2 || g->grad[i] == 0 || i == g->source);
3615  continue;
3616  }
3617 
3618  runloop = TRUE;
3619 
3620  while( runloop )
3621  {
3622  SCIP_Bool success;
3623  int nvisits;
3624  const int start = range_csr[i].start;
3625 
3626  if( range_csr[i].end - start <= 1 )
3627  break;
3628 
3629  runloop = FALSE;
3630 
3631  /* do two star runs */
3632 
3633  dcsr->cost = costbiased_out;
3634  graph_sdStar(scip, g, TRUE, i, edgelimit, star_base, dist, visitlist, &nvisits, dheap, visited, &success);
3635 
3636  if( success )
3637  {
3638  for( int e = start; e < range_csr[i].end; e++ )
3639  star_base_out[head_csr[e]] = star_base[head_csr[e]];
3640  }
3641 
3642  sdStarReset(nnodes, nvisits, visitlist, star_base, dist, visited, dheap);
3643 
3644  if( success )
3645  {
3646  dcsr->cost = costbiased_in;
3647  graph_sdStar(scip, g, TRUE, i, edgelimit, star_base, dist, visitlist, &nvisits, dheap, visited, &success);
3648  }
3649 
3650  if( success )
3651  {
3652  int* const star_base_in = star_base;
3653  int enext;
3654 
3655  dcsr->cost = cost_csr;
3656  dcsr->cost2 = costbiased_in;
3657  dcsr->cost3 = costbiased_out;
3658 
3659  /* check all star nodes (neighbors of i) */
3660  for( int e = start; e < range_csr[i].end; e = enext )
3661  {
3662  const int starnode = head_csr[e];
3663  const int starbase_in = star_base_in[starnode];
3664  const int starbase_out = star_base_out[starnode];
3665 
3666  assert(starbase_in >= 0 && starbase_out >= 0);
3667 
3668  assert(SCIPisLE(scip, dist[starnode], costbiased_in[e]));
3669 
3670  enext = e + 1;
3671 
3672  if( checkstate )
3673  {
3674  const int orgedge = edgeid_csr[e];
3675  if( edgestate[orgedge] == EDGE_BLOCKED )
3676  continue;
3677  }
3678 
3679  /* shorter path to current star node found? */
3680  if( starnode != starbase_in && starnode != starbase_out )
3681  {
3682  assert(star_base_in[starbase_in] != SDSTAR_BASE_UNSET);
3683  assert(star_base_out[starbase_out] != SDSTAR_BASE_UNSET);
3684 
3685  /* path still valid? */
3686  if( star_base_in[starbase_in] != SDSTAR_BASE_KILLED && star_base_out[starbase_out] != SDSTAR_BASE_KILLED )
3687  {
3688  star_base_in[starnode] = SDSTAR_BASE_KILLED;
3689  star_base_out[starnode] = SDSTAR_BASE_KILLED;
3690 
3691  edge_deletable[edgeid_csr[e] / 2] = TRUE;
3692  graph_dcsr_deleteEdgeBi(scip, dcsr, e);
3693 
3694  (*nelims)++;
3695  enext--;
3696  }
3697  else
3698  {
3699  runloop = TRUE;
3700  }
3701  }
3702  } /* traverse star nodes */
3703  } /* if success */
3704 
3705  /* todo bit of an overkill */
3706  for( int k = 0; k < nvisits; k++ )
3707  star_base_out[visitlist[k]] = SDSTAR_BASE_UNSET;
3708 
3709  sdStarReset(nnodes, nvisits, visitlist, star_base, dist, visited, dheap);
3710 
3711 #ifndef NDEBUG
3712  for( int k = 0; k < nnodes; k++ )
3713  assert(star_base_out[k] == SDSTAR_BASE_UNSET);
3714 #endif
3715  }
3716  }
3717 
3718 #ifndef NDEBUG
3719  for( int e = 0; e < nedges / 2; e++ )
3720  {
3721  if( edge_deletable[e] )
3722  assert(dcsr->id2csredge[e * 2] == -1);
3723  else if( g->oeat[e * 2] != EAT_FREE )
3724  assert(dcsr->id2csredge[e * 2] != -1 || !g->mark[g->tail[e * 2]] || !g->mark[g->head[e * 2]]);
3725  }
3726 #endif
3727 
3728  graph_edge_delBlocked(scip, g, edge_deletable, TRUE);
3729 
3730  SCIPfreeBufferArray(scip, &star_base_out);
3731  SCIPfreeBufferArray(scip, &costbiased_in);
3732  SCIPfreeBufferArray(scip, &costbiased_out);
3733  SCIPfreeBufferArray(scip, &edge_deletable);
3734 
3735  dcsr->cost = cost_csr;
3736 
3737  graph_free_dcsr(scip, g);
3738 
3739  return SCIP_OKAY;
3740 }
3741 
3742 /** SD test for PcMw using only limited Dijkstra-like walk from both endpoints of an edge */
3744  SCIP* scip,
3745  int edgelimit,
3746  const int* edgestate,
3747  GRAPH* g,
3748  int* termmark,
3749  SCIP_Real* dist,
3750  int* heap,
3751  int* state,
3752  int* visitlist,
3753  STP_Bool* visited,
3754  int* nelims
3755  )
3756 {
3757  const int nnodes = g->knots;
3758  const SCIP_Bool checkstate = (edgestate != NULL);
3759 
3760  assert(g != NULL);
3761  assert(scip != NULL);
3762  assert(heap != NULL);
3763  assert(nelims != NULL);
3764  assert(visited != NULL);
3765  assert(visitlist != NULL);
3766  assert(!g->extended);
3767  assert(graph_pc_isPcMw(g));
3768 
3769  if( edgelimit <= 0 )
3770  return SCIP_OKAY;
3771 
3772  for( int i = 0; i < nnodes; i++ )
3773  {
3774  visited[i] = FALSE;
3775  state[i] = UNKNOWN;
3776  dist[i] = FARAWAY;
3777  }
3778 
3779  graph_pc_termMarkProper(g, termmark);
3780 
3781  for( int i = 0; i < nnodes; i++ )
3782  {
3783  int e;
3784  if( !g->mark[i] )
3785  continue;
3786 
3787  /* traverse neighbours */
3788  e = g->outbeg[i];
3789  while( e != EAT_LAST )
3790  {
3791  SCIP_Bool success;
3792  const SCIP_Real ecost = g->cost[e];
3793  int nvisits;
3794  const int i2 = g->head[e];
3795  const int enext = g->oeat[e];
3796 
3797  if( !g->mark[i2] )
3798  {
3799  e = enext;
3800  continue;
3801  }
3802 
3803  if( checkstate && edgestate[e] == EDGE_BLOCKED )
3804  {
3805  e = enext;
3806  continue;
3807  }
3808 
3809  success = graph_sdWalks(scip, g, g->cost, termmark, ecost, i2, i, edgelimit, dist, heap, state, visitlist, &nvisits, visited);
3810  sdwalkReset(nnodes, nvisits, visitlist, dist, state, visited);
3811 
3812  if( success )
3813  {
3814  graph_edge_del(scip, g, e, TRUE);
3815  (*nelims)++;
3816  }
3817 
3818  e = enext;
3819  }
3820  }
3821 
3822  return SCIP_OKAY;
3823 }
3824 
3825 
3826 /** SD test for PcMw using only limited Dijkstra-like walk from both endpoints of an edge */
3828  SCIP* scip, /**< SCIP data structure */
3829  int edgelimit, /**< edge limit */
3830  SCIP_Bool usestrongreds, /**< allow strong reductions? */
3831  GRAPH* g, /**< graph data structure */
3832  SCIP_Real* dist, /**< per node: distances */
3833  int* heap, /**< heap */
3834  int* state, /**< state */
3835  int* visitlist, /**< array to store visited nodes */
3836  STP_Bool* visited, /**< number of visited nodes */
3837  int* nelims /**< number of eliminations */
3838  )
3839 {
3840  int* prevterms;
3841  int* nprevterms;
3842  const int nnodes = g->knots;
3843 
3844  assert(g != NULL);
3845  assert(scip != NULL);
3846  assert(heap != NULL);
3847  assert(nelims != NULL);
3848  assert(visited != NULL);
3849  assert(visitlist != NULL);
3850  assert(!g->extended);
3851  assert(graph_pc_isPcMw(g));
3852 
3853  if( edgelimit <= 0 )
3854  return SCIP_OKAY;
3855 
3856  SCIP_CALL( SCIPallocBufferArray(scip, &prevterms, nnodes * STP_SDWALK_MAXNPREVS) );
3857  SCIP_CALL( SCIPallocBufferArray(scip, &nprevterms, nnodes) );
3858 
3859  for( int i = 0; i < nnodes; i++ )
3860  {
3861  visited[i] = FALSE;
3862  state[i] = UNKNOWN;
3863  dist[i] = FARAWAY;
3864  nprevterms[i] = 0;
3865  }
3866 
3867  for( int i = 0; i < nnodes; i++ )
3868  {
3869  int e;
3870  if( !g->mark[i] )
3871  continue;
3872 
3873  /* traverse neighbours */
3874  e = g->outbeg[i];
3875  while( e != EAT_LAST )
3876  {
3877  SCIP_Bool success;
3878  const SCIP_Real ecost = g->cost[e];
3879  int nvisits;
3880  const int i2 = g->head[e];
3881  const int enext = g->oeat[e];
3882 
3883  /* avoid double checking */
3884  if( !g->mark[i2] )
3885  {
3886  e = enext;
3887  continue;
3888  }
3889 
3890  success = graph_sdWalksExt(scip, g, g->cost, ecost, i2, i, edgelimit, STP_SDWALK_MAXNPREVS, dist, prevterms, nprevterms, heap, state, visitlist, &nvisits, visited);
3891  sdwalkResetExt(nnodes, nvisits, visitlist, dist, nprevterms, state, visited);
3892 
3893  if( success )
3894  {
3895  graph_edge_del(scip, g, e, TRUE);
3896  (*nelims)++;
3897  }
3898 
3899  e = enext;
3900  }
3901  }
3902 
3903  SCIPfreeBufferArray(scip, &nprevterms);
3904  SCIPfreeBufferArray(scip, &prevterms);
3905 
3906  return SCIP_OKAY;
3907 }
3908 
3909 /** SD test for PcMw using only limited Dijkstra-like walk from both endpoints of an edge */
3911  SCIP* scip, /**< SCIP data structure */
3912  int edgelimit, /**< edge limit */
3913  const int* edgestate, /**< per edge: state */
3914  GRAPH* g, /**< graph data structure */
3915  int* termmark, /**< per node: terminal state */
3916  SCIP_Real* dist, /**< per node: distance */
3917  int* heap, /**< heap */
3918  int* state, /**< state */
3919  int* visitlist, /**< visited nodes */
3920  STP_Bool* visited, /**< number of visited nodes */
3921  int* nelims /**< number of eliminations */
3922  )
3923 {
3924  int* prevterms;
3925  int* nprevterms;
3926  int* prevNPterms;
3927  int* nprevNPterms;
3928  int* prevedges;
3929  int* nprevedges;
3930  const int nnodes = g->knots;
3931  const SCIP_Bool checkstate = (edgestate != NULL);
3932 
3933  assert(g != NULL);
3934  assert(scip != NULL);
3935  assert(heap != NULL);
3936  assert(nelims != NULL);
3937  assert(visited != NULL);
3938  assert(visitlist != NULL);
3939  assert(!g->extended);
3940  assert(graph_pc_isPcMw(g));
3941 
3942  if( edgelimit <= 0 )
3943  return SCIP_OKAY;
3944 
3945  assert(0 && "triggers bug in STP-DIMACS/PCSPG-hand/HAND_SMALL_ICERM/handsi04.stp");
3946 
3947  SCIP_CALL( SCIPallocBufferArray(scip, &prevterms, nnodes * STP_SDWALK_MAXNPREVS) );
3948  SCIP_CALL( SCIPallocBufferArray(scip, &nprevterms, nnodes) );
3949  SCIP_CALL( SCIPallocBufferArray(scip, &prevNPterms, nnodes * STP_SDWALK_MAXNPREVS) );
3950  SCIP_CALL( SCIPallocBufferArray(scip, &nprevNPterms, nnodes) );
3951  SCIP_CALL( SCIPallocBufferArray(scip, &prevedges, nnodes * STP_SDWALK_MAXNPREVS) );
3952  SCIP_CALL( SCIPallocBufferArray(scip, &nprevedges, nnodes) );
3953 
3954  for( int i = 0; i < nnodes; i++ )
3955  {
3956  visited[i] = FALSE;
3957  state[i] = UNKNOWN;
3958  dist[i] = FARAWAY;
3959  nprevterms[i] = 0;
3960  nprevNPterms[i] = 0;
3961  nprevedges[i] = 0;
3962  }
3963 
3964  graph_pc_termMarkProper(g, termmark);
3965 
3966  for( int i = 0; i < nnodes; i++ )
3967  {
3968  int e;
3969  if( !g->mark[i] )
3970  continue;
3971 
3972  /* traverse neighbours */
3973  e = g->outbeg[i];
3974  while( e != EAT_LAST )
3975  {
3976  SCIP_Bool success;
3977  const SCIP_Real ecost = g->cost[e];
3978  int nvisits;
3979  const int i2 = g->head[e];
3980  const int enext = g->oeat[e];
3981 
3982  /* avoid double checking */
3983  if( !g->mark[i2] )
3984  {
3985  e = enext;
3986  continue;
3987  }
3988 
3989  if( checkstate && edgestate[e] == EDGE_BLOCKED )
3990  {
3991  e = enext;
3992  continue;
3993  }
3994 
3995  success = graph_sdWalksExt2(scip, g, g->cost, termmark, ecost, i2, i, edgelimit, STP_SDWALK_MAXNPREVS, dist, prevterms, nprevterms,
3996  prevNPterms, nprevNPterms, prevedges, nprevedges, heap, state, visitlist, &nvisits, visited);
3997  sdwalkResetExt2(nnodes, nvisits, visitlist, dist, nprevterms, nprevNPterms, nprevedges, state, visited);
3998 
3999  if( success )
4000  {
4001  graph_edge_del(scip, g, e, TRUE);
4002  (*nelims)++;
4003  }
4004 
4005  e = enext;
4006  }
4007  }
4008 
4009  SCIPfreeBufferArray(scip, &nprevedges);
4010  SCIPfreeBufferArray(scip, &prevedges);
4011  SCIPfreeBufferArray(scip, &nprevNPterms);
4012  SCIPfreeBufferArray(scip, &prevNPterms);
4013  SCIPfreeBufferArray(scip, &nprevterms);
4014  SCIPfreeBufferArray(scip, &prevterms);
4015 
4016  return SCIP_OKAY;
4017 }
4018 
4019 /** SD test using only limited Dijkstra from both endpoints of an edge */
4021  SCIP* scip, /**< SCIP data structure */
4022  GRAPH* g, /**< graph data structure */
4023  PATH* pathtail, /**< path tails */
4024  int* heap, /**< heap */
4025  int* statetail, /**< tails */
4026  int* statehead, /**< heads */
4027  int* memlbltail, /**< to save changed tails */
4028  int* memlblhead, /**< to save changed heads */
4029  int* nelims, /**< number of eliminations */
4030  int limit, /**< limit for number checks */
4031  SCIP_Bool usestrongreds /**< allow strong reductions? */
4032 )
4033 {
4034  PATH *pathhead = NULL;
4035  int* pathmaxnodetail = NULL;
4036  int* pathmaxnodehead = NULL;
4037  const int nnodes = graph_get_nNodes(g);
4038  const SCIP_Bool pc = (g->stp_type == STP_PCSPG || g->stp_type == STP_RPCSPG);
4039 
4040  assert(scip != NULL);
4041  assert(pathtail != NULL);
4042  assert(heap != NULL);
4043  assert(statetail != NULL);
4044  assert(statehead != NULL);
4045  assert(memlbltail != NULL);
4046  assert(memlblhead != NULL);
4047  assert(nelims != NULL);
4048  assert(!g->extended);
4049 
4050  *nelims = 0;
4051 
4052  if( limit <= 0 )
4053  return SCIP_OKAY;
4054 
4055  SCIP_CALL( SCIPallocBufferArray(scip, &pathhead, nnodes) );
4056 
4057  if( pc )
4058  {
4059  SCIP_CALL( SCIPallocBufferArray(scip, &pathmaxnodetail, nnodes) );
4060  SCIP_CALL( SCIPallocBufferArray(scip, &pathmaxnodehead, nnodes) );
4061 
4062  for( int i = 0; i < nnodes; i++ )
4063  {
4064  pathmaxnodetail[i] = -1;
4065  pathmaxnodehead[i] = -1;
4066  }
4067  }
4068  else
4069  {
4070  for( int i = 0; i < nnodes; i++ )
4071  g->mark[i] = (g->grad[i] > 0);
4072  }
4073 
4074  for( int i = 0; i < nnodes; i++ )
4075  {
4076  statetail[i] = UNKNOWN;
4077  pathtail[i].dist = FARAWAY;
4078  pathtail[i].edge = UNKNOWN;
4079  statehead[i] = UNKNOWN;
4080  pathhead[i].dist = FARAWAY;
4081  pathhead[i].edge = UNKNOWN;
4082  }
4083 
4084  /* iterate through all nodes */
4085  for( int i = 0; i < nnodes; i++ )
4086  {
4087  int e;
4088  if( !g->mark[i] )
4089  continue;
4090 
4091  /* traverse neighbours */
4092  e = g->outbeg[i];
4093  while( e != EAT_LAST )
4094  {
4095  const SCIP_Real ecost = g->cost[e];
4096  const int i2 = g->head[e];
4097  const int enext = g->oeat[e];
4098  int nlbltail;
4099  int nlblhead;
4100  SCIP_Bool deletable;
4101 
4102  /* avoid double checking */
4103  if( i2 < i || !g->mark[i2] )
4104  {
4105  e = enext;
4106  continue;
4107  }
4108 
4109  /* execute limited Dijkstra from both sides */
4110 
4111  if( pc )
4112  {
4113  graph_path_PcMwSd(scip, g, pathtail, g->cost, ecost, pathmaxnodetail, heap, statetail, NULL, memlbltail, &nlbltail, i, i2, limit);
4114  graph_path_PcMwSd(scip, g, pathhead, g->cost, ecost, pathmaxnodehead, heap, statehead, statetail, memlblhead, &nlblhead, i2, i, limit);
4115  }
4116  else
4117  {
4118  graph_sdPaths(g, pathtail, g->cost, ecost, heap, statetail, memlbltail, &nlbltail, i, i2, limit);
4119  graph_sdPaths(g, pathhead, g->cost, ecost, heap, statehead, memlblhead, &nlblhead, i2, i, limit);
4120  }
4121 
4122  deletable = FALSE;
4123 
4124  /* check whether edge e can be deleted and restore data structures */
4125  for( int k = 0; k < nlbltail && !deletable; k++ )
4126  {
4127  const int l = memlbltail[k];
4128 
4129  assert(g->mark[l]);
4130  assert(statetail[l] != UNKNOWN);
4131 
4132  if( statehead[l] != UNKNOWN )
4133  {
4134  assert(SCIPisGT(scip, FARAWAY, pathtail[l].dist));
4135  assert(SCIPisGT(scip, FARAWAY, pathhead[l].dist));
4136 
4137  if( pc )
4138  {
4139  const int tailmaxterm = pathmaxnodetail[l];
4140  const int headmaxterm = pathmaxnodehead[l];
4141 
4142  assert(tailmaxterm != i && headmaxterm != i);
4143  assert(tailmaxterm != i2 && headmaxterm != i2);
4144 
4145  /* any terminal on the path? */
4146  if( tailmaxterm >= 0 || headmaxterm >= 0 )
4147  {
4148  if( tailmaxterm == headmaxterm )
4149  {
4150  assert(tailmaxterm == l);
4151  assert(SCIPisPositive(scip, g->prize[tailmaxterm]));
4152  assert(SCIPisGE(scip, ecost, pathhead[headmaxterm].dist) && SCIPisGE(scip, ecost, pathtail[tailmaxterm].dist));
4153 
4154  if( SCIPisGE(scip, ecost, pathhead[l].dist + pathtail[l].dist - g->prize[l]) )
4155  {
4156  deletable = TRUE;
4157  SCIPdebugMessage("delete1Term \n");
4158  }
4159  }
4160  else if( tailmaxterm >= 0 && headmaxterm >= 0 )
4161  {
4162  const SCIP_Real distl2tailmax = pathtail[l].dist - pathtail[tailmaxterm].dist;
4163  const SCIP_Real distl2headmax = pathhead[l].dist - pathhead[headmaxterm].dist;
4164 
4165  assert(tailmaxterm != headmaxterm);
4166  assert(!SCIPisNegative(scip, distl2tailmax));
4167  assert(!SCIPisNegative(scip, distl2headmax));
4168  assert(SCIPisPositive(scip, g->prize[tailmaxterm]) && SCIPisPositive(scip, g->prize[headmaxterm]));
4169  assert(SCIPisGE(scip, ecost, pathhead[headmaxterm].dist) && SCIPisGE(scip, ecost, pathtail[tailmaxterm].dist));
4170 
4171  if( SCIPisGE(scip, ecost, distl2tailmax + distl2headmax)
4172  && SCIPisGE(scip, ecost, distl2tailmax + pathhead[l].dist - g->prize[headmaxterm])
4173  && SCIPisGE(scip, ecost, distl2headmax + pathtail[l].dist - g->prize[tailmaxterm])
4174  && SCIPisGE(scip, ecost, pathhead[l].dist + pathtail[l].dist - g->prize[tailmaxterm] - g->prize[headmaxterm]) )
4175  {
4176  deletable = TRUE;
4177  SCIPdebugMessage("delete2Term \n");
4178  }
4179  }
4180  else if( tailmaxterm >= 0 )
4181  {
4182  const SCIP_Real distl2tailmax = pathtail[l].dist - pathtail[tailmaxterm].dist;
4183  // todo consider l == term?
4184  assert(headmaxterm < 0);
4185  assert(SCIPisGE(scip, ecost, pathtail[tailmaxterm].dist));
4186  assert(SCIPisPositive(scip, g->prize[tailmaxterm]));
4187 
4188  if( SCIPisGE(scip, ecost, distl2tailmax + pathhead[l].dist)
4189  && SCIPisGE(scip, ecost, pathhead[l].dist + pathtail[l].dist - g->prize[tailmaxterm]) )
4190  {
4191  deletable = TRUE;
4192  SCIPdebugMessage("deleteHalfTerm1 \n");
4193  }
4194  }
4195  else if( headmaxterm >= 0 )
4196  {
4197  const SCIP_Real distl2headmax = pathhead[l].dist - pathhead[headmaxterm].dist;
4198  // todo consider l == term?
4199  assert(tailmaxterm < 0);
4200  assert(SCIPisGE(scip, ecost, pathhead[headmaxterm].dist));
4201  assert(SCIPisPositive(scip, g->prize[headmaxterm]));
4202 
4203  if( SCIPisGE(scip, ecost, distl2headmax + pathtail[l].dist)
4204  && SCIPisGE(scip, ecost, pathhead[l].dist + pathtail[l].dist - g->prize[headmaxterm]) )
4205  {
4206  deletable = TRUE;
4207  SCIPdebugMessage("deleteHalfTerm2 \n");
4208  }
4209  }
4210  }
4211  else if( SCIPisGE(scip, ecost, pathhead[l].dist + pathtail[l].dist) )
4212  {
4213  deletable = TRUE;
4214  }
4215 
4216  if( Is_term(g->term[l]) )
4217  {
4218  if( SCIPisGE(scip, ecost, pathhead[l].dist) && SCIPisGE(scip, ecost, pathtail[l].dist)
4219  && SCIPisGE(scip, ecost, pathhead[l].dist + pathtail[l].dist - g->prize[l]) )
4220  deletable = TRUE;
4221  }
4222  }
4223  else
4224  {
4225  if( Is_term(g->term[l]) )
4226  {
4227  if( SCIPisGE(scip, ecost, pathhead[l].dist) && SCIPisGE(scip, ecost, pathtail[l].dist) )
4228  {
4229  deletable = TRUE;
4230 
4231  if( !usestrongreds && SCIPisEQ(scip, ecost, pathhead[l].dist) && SCIPisEQ(scip, ecost, pathtail[l].dist) )
4232  deletable = FALSE;
4233  }
4234  }
4235  else
4236  {
4237  if( SCIPisGE(scip, ecost, pathhead[l].dist + pathtail[l].dist) )
4238  {
4239  deletable = TRUE;
4240 
4241  if( !usestrongreds && SCIPisEQ(scip, ecost, pathhead[l].dist + pathtail[l].dist) )
4242  deletable = FALSE;
4243  }
4244  }
4245  }
4246  }
4247  }
4248 
4249  /* restore data */
4250 
4251  for( int k = 0; k < nlbltail; k++ )
4252  {
4253  const int l = memlbltail[k];
4254  statetail[l] = UNKNOWN;
4255  pathtail[l].dist = FARAWAY;
4256  pathtail[l].edge = UNKNOWN;
4257  if( pc )
4258  pathmaxnodetail[l] = -1;
4259  }
4260 
4261  for( int k = 0; k < nlblhead; k++ )
4262  {
4263  const int l = memlblhead[k];
4264  statehead[l] = UNKNOWN;
4265  pathhead[l].dist = FARAWAY;
4266  pathhead[l].edge = UNKNOWN;
4267  if( pc )
4268  pathmaxnodehead[l] = -1;
4269  }
4270 
4271 #ifndef NDEBUG
4272  for( int k = 0; k < nnodes; k++ )
4273  {
4274  assert(statetail[k] == UNKNOWN);
4275  assert(pathtail[k].dist == FARAWAY);
4276  assert(pathtail[k].edge == UNKNOWN);
4277  assert(statehead[k] == UNKNOWN);
4278  assert(pathhead[k].dist == FARAWAY);
4279  assert(pathhead[k].edge == UNKNOWN);
4280  if( pc )
4281  {
4282  assert(pathmaxnodetail[k] == -1);
4283  assert(pathmaxnodehead[k] == -1);
4284  }
4285  }
4286 #endif
4287  /* can edge be deleted? */
4288  if( deletable )
4289  {
4290  graph_edge_del(scip, g, e, TRUE);
4291  (*nelims)++;
4292  }
4293 
4294  e = enext;
4295  }
4296  }
4297 
4298  SCIPfreeBufferArrayNull(scip, &pathmaxnodehead);
4299  SCIPfreeBufferArrayNull(scip, &pathmaxnodetail);
4300  SCIPfreeBufferArray(scip, &pathhead);
4301 
4302  assert(graph_valid(scip, g));
4303 
4304  return SCIP_OKAY;
4305 }
4306 
4307 
4308 /** bd_k test for given Steiner bottleneck distances */
4309 /* *** DEPRECATED ***/
4311  SCIP* scip, /**< SCIP data structure */
4312  GRAPH* g, /**< graph structure */
4313  SDGRAPH* sdgraph, /**< auxiliary graph structure */
4314  PATH* vnoi, /**< path structure */
4315  int* vbase, /**< bases for nearest terminals */
4316  int* nelims /**< number of eliminations */
4317  )
4318 {
4319  SCIP_Real cutoffs[STP_BD_MAXDNEDGES];
4321  SCIP_Real ecost[STP_BD_MAXDEGREE];
4322  int edges[STP_BD_MAXDEGREE];
4323  int adjvert[STP_BD_MAXDEGREE];
4324  GRAPH* auxg;
4325  const int nnodes = g->knots;
4326  int nnewelims = 0;
4327 
4328  assert(scip && g && vnoi);
4329  assert(!graph_pc_isPcMw(g));
4330 
4331  /* build auxiliary graph */
4333  assert(auxg->edges == 2 * STP_BD_MAXDNEDGES);
4334 
4335  SCIP_CALL( graph_path_init(scip, auxg) );
4336 
4337  SCIPdebugMessage("BD34-SD Reduction: ");
4338 
4339  for( int i = 0; i < STP_BD_MAXDEGREE; i++ )
4340  sd[i] = 0.0;
4341 
4342  /* NOTE: necessary due to compiler warning... */
4343  for( int i = 0; i < STP_BD_MAXDEGREE; i++ )
4344  adjvert[i] = -1;
4345 
4346  graph_mark(g);
4347 
4348  for( int degree = 3; degree <= STP_BD_MAXDEGREE; degree ++ )
4349  {
4350  for( int i = 0; i < nnodes; i++ )
4351  {
4352  if( Is_term(g->term[i]) || g->grad[i] != degree )
4353  {
4354  continue;
4355  }
4356  else
4357  {
4358  int k = 0;
4359  for( int e = g->outbeg[i]; e != EAT_LAST; e = g->oeat[e] )
4360  {
4361  edges[k] = e;
4362  ecost[k] = g->cost[e];
4363  adjvert[k++] = g->head[e];
4364  }
4365  assert(k == degree);
4366  }
4367 
4368  assert(g->mark[i]);
4369 
4370  /* vertex of degree 3? */
4371  if( degree == 3 )
4372  {
4373  const SCIP_Real costsum = ecost[0] + ecost[1] + ecost[2];
4374 
4375  sd[0] = getSd(scip, g, sdgraph, vnoi, ecost[0] + ecost[1], vbase, adjvert[0], adjvert[1], 300);
4376  sd[1] = getSd(scip, g, sdgraph, vnoi, ecost[1] + ecost[2], vbase, adjvert[1], adjvert[2], 300);
4377  sd[2] = getSd(scip, g, sdgraph, vnoi, ecost[2] + ecost[0], vbase, adjvert[2], adjvert[0], 300);
4378 
4379  if( isPseudoDeletableDeg3(scip, g, sd, edges, costsum, TRUE) )
4380  {
4381  SCIP_Bool success;
4382 
4383  cutoffs[0] = sd[0];
4384  cutoffs[1] = sd[2];
4385  cutoffs[2] = sd[1];
4386 
4387  SCIP_CALL(graph_knot_delPseudo(scip, g, g->cost, cutoffs, NULL, i, NULL, &success));
4388 
4389  assert(success);
4390  assert(g->grad[i] == 0);
4391 
4392  SCIPdebugMessage("BD3-R Reduction: %f %f %f csum: %f\n ", sd[0], sd[1], sd[2], costsum);
4393  nnewelims++;
4394  }
4395  }
4396  /* vertex of degree 4? */
4397  else if( degree == 4 )
4398  {
4399 
4400  /* SDs of adjacent vertices in canonical order */
4401  SCIP_Real adjsds[6];
4402  SCIP_Bool success = TRUE;
4403 
4404  adjsds[0] = getSd(scip, g, sdgraph, vnoi, ecost[0] + ecost[1], vbase, adjvert[0], adjvert[1], 200);
4405  adjsds[1] = getSd(scip, g, sdgraph, vnoi, ecost[0] + ecost[2], vbase, adjvert[0], adjvert[2], 200);
4406  adjsds[3] = getSd(scip, g, sdgraph, vnoi, ecost[1] + ecost[2], vbase, adjvert[1], adjvert[2], 200);
4407 
4408  if( !isPseudoDeletableDeg3(scip, g, (SCIP_Real[3]){ adjsds[0], adjsds[1], adjsds[3] },
4409  (int[3]){ edges[0], edges[1], edges[2]},
4410  ecost[0] + ecost[1] + ecost[2], TRUE) )
4411  {
4412  continue;
4413  }
4414 
4415  adjsds[2] = getSd(scip, g, sdgraph, vnoi, ecost[0] + ecost[3], vbase, adjvert[0], adjvert[3], 200);
4416  adjsds[4] = getSd(scip, g, sdgraph, vnoi, ecost[1] + ecost[3], vbase, adjvert[1], adjvert[3], 200);
4417 
4418  if( !isPseudoDeletableDeg3(scip, g, (SCIP_Real[3]){ adjsds[0], adjsds[2], adjsds[4] },
4419  (int[3]){ edges[0], edges[1], edges[3]},
4420  ecost[0] + ecost[1] + ecost[3], TRUE) )
4421  {
4422  continue;
4423  }
4424 
4425  adjsds[5] = getSd(scip, g, sdgraph, vnoi, ecost[2] + ecost[3], vbase, adjvert[2], adjvert[3], 200);
4426 
4427  if( !isPseudoDeletableDeg3(scip, g, (SCIP_Real[3]){ adjsds[1], adjsds[2], adjsds[5] },
4428  (int[3]){ edges[0], edges[2], edges[3]},
4429  ecost[0] + ecost[2] + ecost[3], TRUE) )
4430  {
4431  continue;
4432  }
4433 
4434  if( !isPseudoDeletableDeg3(scip, g, (SCIP_Real[3]){ adjsds[3], adjsds[4], adjsds[5] },
4435  (int[3]){ edges[1], edges[2], edges[3]},
4436  ecost[1] + ecost[2] + ecost[3], TRUE) )
4437  {
4438  continue;
4439  }
4440 
4441  for( int k = 0; k < 4; k++ )
4442  auxg->mark[k] = TRUE;
4443 
4444  for( int k = 0; k < 3; k++ )
4445  {
4446  for( int e = auxg->outbeg[k]; e != EAT_LAST; e = auxg->oeat[e] )
4447  {
4448  const int k2 = auxg->head[e];
4449  if( k2 > k )
4450  {
4451  if( k == 0 )
4452  auxg->cost[e] = adjsds[k2 - 1];
4453  else
4454  auxg->cost[e] = adjsds[k + k2];
4455 
4456  assert(EQ(auxg->cost[e], getSd(scip, g, sdgraph, vnoi, ecost[k] + ecost[k2], vbase,
4457  adjvert[k], adjvert[k2], 200)));
4458 
4459  auxg->cost[flipedge(e)] = auxg->cost[e];
4460  }
4461  }
4462  }
4463 
4464  success = isPseudoDeletable(scip, g, auxg, ecost, edges, 4);
4465 
4466  if( success )
4467  {
4468  int edgecount = 0;
4469  for( int k = 0; k < 3; k++ )
4470  {
4471  for( int e = auxg->outbeg[k]; e != EAT_LAST; e = auxg->oeat[e] )
4472  {
4473  const int k2 = auxg->head[e];
4474  if( k2 > k )
4475  cutoffs[edgecount++] = auxg->cost[e];
4476  }
4477  }
4478 
4479  SCIP_CALL(graph_knot_delPseudo(scip, g, g->cost, cutoffs, NULL, i, NULL, &success));
4480 
4481  if( success )
4482  {
4483  nnewelims++;
4484  }
4485  }
4486  }
4487  }
4488  }
4489 
4490  // todo there might be an issue that SDs become invalid because of a conflict deletion...
4491  if( nnewelims > 0 )
4492  SCIP_CALL( reduce_unconnected(scip, g) );
4493 
4494  assert(graph_valid(scip, g));
4495 
4496  graph_path_exit(scip, auxg);
4497  graph_free(scip, &auxg, TRUE);
4498 
4499  *nelims += nnewelims;
4500 
4501  return SCIP_OKAY;
4502 }
4503 
4504 
4505 /* C. W. Duin and A. Volganant
4506  *
4507  * "Reduction Tests for the Steiner Problem in Graphs"
4508  *
4509  * Networks, Volume 19 (1989), 549-567
4510  *
4511  * Bottleneck Degree 3,4 Test
4512  *
4513  * ONLY USED FOR PC!
4514  * todo adapt
4515  */
4517  SCIP* scip, /**< SCIP data structure */
4518  GRAPH* g, /**< graph structure */
4519  PATH* pathtail, /**< array for internal use */
4520  PATH* pathhead, /**< array for internal use */
4521  int* heap, /**< array for internal use */
4522  int* statetail, /**< array for internal use */
4523  int* statehead, /**< array for internal use */
4524  int* memlbltail, /**< array for internal use */
4525  int* memlblhead, /**< array for internal use */
4526  int* nelims, /**< point to return number of eliminations */
4527  int limit, /**< limit for edges to consider for each vertex */
4528  SCIP_Real* offset /**< offset */
4529  )
4530 {
4531  SD1PC sd1pc;
4532  SCIP_Real cutoffs[STP_BD_MAXDNEDGES];
4533  int edges[STP_BD_MAXDEGREE];
4534  SCIP_Real ecost[STP_BD_MAXDEGREE];
4535  GRAPH* auxg;
4536  int* pathmaxnodetail = NULL;
4537  int* pathmaxnodehead = NULL;
4538  int adjvert[STP_BD_MAXDEGREE];
4539  const int nnodes = g->knots;
4540  const int limit4 = limit / 3;
4541 
4542  SCIPdebugMessage("BD34-Reduction: ");
4543 
4544  assert(scip && g && heap && nelims);
4545  assert(!g->extended);
4546  assert(graph_pc_isPc(g));
4547  assert(limit > 0 && limit4 > 0);
4548 
4549  /* build auxiliary graph */
4551  assert(auxg->edges == 2 * STP_BD_MAXDNEDGES);
4552  SCIP_CALL( graph_path_init(scip, auxg) );
4553 
4554  *nelims = 0;
4555 
4556  SCIP_CALL( SCIPallocBufferArray(scip, &pathmaxnodetail, nnodes) );
4557  SCIP_CALL( SCIPallocBufferArray(scip, &pathmaxnodehead, nnodes) );
4558 
4559  graph_mark(g);
4560 
4561  for( int i = 0; i < nnodes; i++ )
4562  {
4563  statetail[i] = UNKNOWN;
4564  pathtail[i].dist = FARAWAY;
4565  pathtail[i].edge = UNKNOWN;
4566  statehead[i] = UNKNOWN;
4567  pathhead[i].dist = FARAWAY;
4568  pathhead[i].edge = UNKNOWN;
4569 
4570  pathmaxnodetail[i] = -1;
4571  pathmaxnodehead[i] = -1;
4572  }
4573 
4574  sd1pc = (SD1PC) { .pathtail = pathtail, .pathhead = pathhead, .heap = heap,
4575  .statetail = statetail, .statehead = statehead, .memlbltail = memlbltail,
4576  .memlblhead = memlblhead, .pathmaxnodetail = pathmaxnodetail, .pathmaxnodehead = pathmaxnodehead };
4577 
4578  for( int degree = 3; degree <= STP_BD_MAXDEGREE; degree++ )
4579  {
4580  for( int i = 0; i < nnodes; i++ )
4581  {
4582  int edgecount;
4583 
4584  {
4585  int pcdegree;
4586 
4587  if( !g->mark[i] || graph_pc_knotIsFixedTerm(g, i) )
4588  continue;
4589 
4590  if( Is_term(g->term[i]) && !graph_pc_termIsNonLeafTerm(g, i) )
4591  continue;
4592 
4593  pcdegree = graph_pc_realDegree(g, i, FALSE);
4594 
4595  if( pcdegree != degree )
4596  continue;
4597  }
4598 
4599 
4600  edgecount = 0;
4601  for( int e = g->outbeg[i]; e != EAT_LAST; e = g->oeat[e] )
4602  {
4603  const int head = g->head[e];
4604 
4605  if( g->mark[head] )
4606  {
4607  edges[edgecount] = e;
4608  ecost[edgecount] = g->cost[e];
4609  adjvert[edgecount++] = g->head[e];
4610  }
4611  else
4612  {
4613  assert(Is_term(g->term[i]));
4614  }
4615  }
4616 
4617  assert(edgecount == degree);
4618 
4619  /* vertex of degree 3? */
4620  if( degree == 3 )
4621  {
4622  SCIP_Real sd[3];
4623  const SCIP_Real iprize = (Is_term(g->term[i])) ? g->prize[i] : 0.0;
4624  const SCIP_Real csum = ecost[0] + ecost[1] + ecost[2] - iprize;
4625 
4626  assert(edgecount == 3);
4627  assert(iprize <= ecost[0] && iprize <= ecost[1] && iprize <= ecost[2]);
4628 
4629  sd[0] = sdGetSdPcMw(scip, g, ecost[0] + ecost[1], adjvert[0], adjvert[1], limit, &sd1pc);
4630  sd[1] = sdGetSdPcMw(scip, g, ecost[1] + ecost[2], adjvert[1], adjvert[2], limit, &sd1pc);
4631  sd[2] = sdGetSdPcMw(scip, g, ecost[2] + ecost[0], adjvert[2], adjvert[0], limit, &sd1pc);
4632 
4633  if( isPseudoDeletableDeg3(scip, g, sd, edges, csum, !Is_term(g->term[i])) )
4634  {
4635  SCIP_Bool success;
4636 
4637  cutoffs[0] = sd[0];
4638  cutoffs[1] = sd[2];
4639  cutoffs[2] = sd[1];
4640 
4641  if( Is_term(g->term[i]) )
4642  {
4643  assert(offset != NULL);
4644  assert(graph_pc_isPcMw(g));
4645 
4646  *offset += g->prize[i];
4647  }
4648 
4649  SCIP_CALL(graph_knot_delPseudo(scip, g, g->cost, cutoffs, NULL, i, NULL, &success));
4650  assert(success);
4651  assert(g->grad[i] == 0);
4652 
4653  SCIPdebugMessage("BD3 Reduction: %f %f %f csum: %f\n ", sd[0], sd[1], sd[2], csum);
4654  (*nelims)++;
4655  }
4656  }
4657  /* non-terminal of degree 4? */
4658  else if( degree == 4 && !Is_term(g->term[i]) )
4659  {
4660  /* SDs of adjacent vertices in canonical order */
4661  SCIP_Real adjsds[6];
4662  SCIP_Bool success = TRUE;
4663 
4664  adjsds[0] = sdGetSdPcMw(scip, g, ecost[0] + ecost[1], adjvert[0], adjvert[1], limit4, &sd1pc);
4665  adjsds[1] = sdGetSdPcMw(scip, g, ecost[0] + ecost[2], adjvert[0], adjvert[2], limit4, &sd1pc);
4666  adjsds[3] = sdGetSdPcMw(scip, g, ecost[1] + ecost[2], adjvert[1], adjvert[2], limit4, &sd1pc);
4667 
4668  if( !isPseudoDeletableDeg3(scip, g, (SCIP_Real[3]){ adjsds[0], adjsds[1], adjsds[3] },
4669  (int[3]){ edges[0], edges[1], edges[2]},
4670  ecost[0] + ecost[1] + ecost[2], TRUE) )
4671  {
4672  continue;
4673  }
4674 
4675  adjsds[2] = sdGetSdPcMw(scip, g, ecost[0] + ecost[3], adjvert[0], adjvert[3], limit4, &sd1pc);
4676  adjsds[4] = sdGetSdPcMw(scip, g, ecost[1] + ecost[3], adjvert[1], adjvert[3], limit4, &sd1pc);
4677 
4678  if( !isPseudoDeletableDeg3(scip, g, (SCIP_Real[3]){ adjsds[0], adjsds[2], adjsds[4] },
4679  (int[3]){ edges[0], edges[1], edges[3]},
4680  ecost[0] + ecost[1] + ecost[3], TRUE) )
4681  {
4682  continue;
4683  }
4684 
4685  adjsds[5] = sdGetSdPcMw(scip, g, ecost[2] + ecost[3], adjvert[2], adjvert[3], limit4, &sd1pc);
4686 
4687  if( !isPseudoDeletableDeg3(scip, g, (SCIP_Real[3]){ adjsds[1], adjsds[2], adjsds[5] },
4688  (int[3]){ edges[0], edges[2], edges[3]},
4689  ecost[0] + ecost[2] + ecost[3], TRUE) )
4690  {
4691  continue;
4692  }
4693 
4694  if( !isPseudoDeletableDeg3(scip, g, (SCIP_Real[3]){ adjsds[3], adjsds[4], adjsds[5] },
4695  (int[3]){ edges[1], edges[2], edges[3]},
4696  ecost[1] + ecost[2] + ecost[3], TRUE) )
4697  {
4698  continue;
4699  }
4700 
4701  for( int k = 0; k < 4; k++ )
4702  auxg->mark[k] = TRUE;
4703 
4704  for( int k = 0; k < 3; k++ )
4705  {
4706  for( int e = auxg->outbeg[k]; e != EAT_LAST; e = auxg->oeat[e] )
4707  {
4708  const int k2 = auxg->head[e];
4709  if( k2 > k )
4710  {
4711  if( k == 0 )
4712  auxg->cost[e] = adjsds[k2 - 1];
4713  else
4714  auxg->cost[e] = adjsds[k + k2];
4715 
4716  assert(EQ(auxg->cost[e], sdGetSdPcMw(scip, g, ecost[k] + ecost[k2], adjvert[k], adjvert[k2], limit4, &sd1pc)));
4717  auxg->cost[flipedge(e)] = auxg->cost[e];
4718  }
4719  }
4720  }
4721 
4722  success = isPseudoDeletable(scip, g, auxg, ecost, edges, 4);
4723 
4724  if( success )
4725  {
4726  edgecount = 0;
4727 
4728  for( int k = 0; k < 3; k++ )
4729  {
4730  for( int e = auxg->outbeg[k]; e != EAT_LAST; e = auxg->oeat[e] )
4731  {
4732  const int k2 = auxg->head[e];
4733  if( k2 > k )
4734  cutoffs[edgecount++] = auxg->cost[e];
4735  }
4736  }
4737 
4738  SCIP_CALL(graph_knot_delPseudo(scip, g, g->cost, cutoffs, NULL, i, NULL, &success));
4739 
4740  if( success )
4741  {
4742  (*nelims)++;
4743  }
4744  }
4745  }
4746  }
4747  }
4748 
4749 
4750  SCIPfreeBufferArrayNull(scip, &pathmaxnodehead);
4751  SCIPfreeBufferArrayNull(scip, &pathmaxnodetail);
4752 
4753  graph_path_exit(scip, auxg);
4754  graph_free(scip, &auxg, TRUE);
4755 
4756  SCIPdebugMessage("bd34: %d nodes deleted\n", *nelims);
4757 
4758  assert(graph_valid(scip, g));
4759 
4760  return SCIP_OKAY;
4761 }
int graph_get_nEdges(const GRAPH *)
Definition: graph_stats.c:548
int * edgearrint
Definition: reducedefs.h:114
void graph_knot_chg(GRAPH *, int, int)
Definition: graph_node.c:86
static volatile int nterms
Definition: interrupt.c:38
int * visitlist
Definition: graphdefs.h:314
int graph_pc_realDegree(const GRAPH *, int, SCIP_Bool)
#define SDSTAR_BASE_KILLED
Definition: graphdefs.h:77
int *RESTRICT head
Definition: graphdefs.h:224
void graph_edge_del(SCIP *, GRAPH *, int, SCIP_Bool)
Definition: graph_edge.c:368
int source
Definition: graphdefs.h:195
SCIP_Bool graph_sdWalksExt(SCIP *, const GRAPH *, const SCIP_Real *, SCIP_Real, int, int, int, int, SCIP_Real *, int *, int *, int *, int *, int *, int *, STP_Bool *)
#define Is_term(a)
Definition: graphdefs.h:102
int start
Definition: graphdefs.h:152
SCIP_Bool graph_sdWalks_csr(SCIP *, const GRAPH *, const int *, SCIP_Real, int, int, int, SCIP_Real *, int *, int *, DHEAP *, STP_Bool *)
signed int edge
Definition: graphdefs.h:287
SCIP_Bool graph_valid(SCIP *, const GRAPH *)
Definition: graph_base.c:1480
static SCIP_Bool sddeltable(SCIP *scip, GRAPH *g, PATH *path, int *vbase, int *forbidden, int tpos, int hpos, int tail, int head, int edge, int nnodes)
Definition: reduce_sd.c:351
static SCIP_Bool isPseudoDeletable(SCIP *scip, const GRAPH *g, const GRAPH *auxg, const SCIP_Real *ecost, const int *edges, int degree)
Definition: reduce_sd.c:1033
static void sdwalkResetExt(int nnodes, int nvisits, const int *visitlist, SCIP_Real *RESTRICT dist, int *RESTRICT nprevterms, int *RESTRICT state, STP_Bool *RESTRICT visited)
Definition: reduce_sd.c:281
int terms
Definition: graphdefs.h:192
void graph_pc_termMarkProper(const GRAPH *, int *)
SCIP_RETCODE reduce_sd(SCIP *scip, GRAPH *g, REDBASE *redbase, int *nelims)
Definition: reduce_sd.c:1517
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void graph_path_exec(SCIP *, const GRAPH *, int, int, const SCIP_Real *, PATH *)
Definition: graph_path.c:541
int * nodearrint
Definition: reducedefs.h:113
void graph_mark(GRAPH *)
Definition: graph_base.c:1130
static void sdwalkReset(int nnodes, int nvisits, const int *visitlist, SCIP_Real *RESTRICT dist, int *RESTRICT state, STP_Bool *RESTRICT visited)
Definition: reduce_sd.c:253
int * nodearrint2
Definition: reducedefs.h:115
void graph_free_dcsr(SCIP *, GRAPH *)
Definition: graph_util.c:1807
SCIP_RETCODE reduce_sdWalk(SCIP *scip, int edgelimit, const int *edgestate, GRAPH *g, int *termmark, SCIP_Real *dist, int *heap, int *state, int *visitlist, STP_Bool *visited, int *nelims)
Definition: reduce_sd.c:3743
void reduce_sdneighborGetCloseTerms(const GRAPH *, const SDN *, int, SCIP_Real, int *RESTRICT, SCIP_Real *RESTRICT, int *RESTRICT)
SCIP_Real reduce_sdgraphGetSd(int, int, SDGRAPH *)
void graph_free(SCIP *, GRAPH **, SCIP_Bool)
Definition: graph_base.c:796
SCIP_RETCODE graph_path_init(SCIP *, GRAPH *)
Definition: graph_path.c:480
void graph_dcsr_deleteEdgeBi(SCIP *, DCSR *, int)
Definition: graph_util.c:1894
#define EAT_FREE
Definition: graphdefs.h:57
#define FALSE
Definition: def.h:87
int *RESTRICT path_state
Definition: graphdefs.h:256
#define STP_BD_MAXDNEDGES
Definition: reduce_sd.c:43
SCIP_Real * cost2
Definition: graphdefs.h:165
#define SDSTAR_BASE_UNSET
Definition: graphdefs.h:76
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Problem data for stp problem.
#define TRUE
Definition: def.h:86
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
includes various files containing graph methods used for Steiner tree problems
void graph_heap_clean(SCIP_Bool, DHEAP *)
Definition: graph_util.c:938
SCIP_Real * cost
Definition: graphdefs.h:164
const int * cliqueToNodeMap
Definition: graphdefs.h:342
void graph_path_PcMwSd(SCIP *, const GRAPH *, PATH *, SCIP_Real *, SCIP_Real, int *, int *, int *, int *, int *, int *, int, int, int)
Definition: graph_path.c:788
#define EAT_LAST
Definition: graphdefs.h:58
#define SCIPdebugMessage
Definition: pub_message.h:87
SCIP_Bool graph_heap_isClean(const DHEAP *)
Definition: graph_util.c:962
#define FARAWAY
Definition: graphdefs.h:89
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE reduce_bd34WithSd(SCIP *scip, GRAPH *g, SDGRAPH *sdgraph, PATH *vnoi, int *vbase, int *nelims)
Definition: reduce_sd.c:4310
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
SCIP_RETCODE reduce_sdWalkExt2(SCIP *scip, int edgelimit, const int *edgestate, GRAPH *g, int *termmark, SCIP_Real *dist, int *heap, int *state, int *visitlist, STP_Bool *visited, int *nelims)
Definition: reduce_sd.c:3910
SCIP_Real reduce_sdGetSdIntermedTerms(const GRAPH *g, int i, int i2, SCIP_Real sd_upper, SCIP_Real sd_sufficient, SD *sddata)
Definition: reduce_sd.c:2449
SCIP_Real * node_distance
Definition: graphdefs.h:316
SCIP_Bool graph_sdWalks(SCIP *, const GRAPH *, const SCIP_Real *, const int *, SCIP_Real, int, int, int, SCIP_Real *, int *, int *, int *, int *, STP_Bool *)
SCIP_Real miscstp_maxReal(const SCIP_Real *realarr, unsigned nreals)
Definition: misc_stp.c:142
SCIP_RETCODE graph_init_dcsr(SCIP *, GRAPH *)
Definition: graph_util.c:1721
SCIP_RETCODE reduce_sdImpLongEdge(SCIP *scip, const int *edgestate, GRAPH *g, SD *sdistance, int *nelims)
Definition: reduce_sd.c:1421
SCIP_RETCODE reduce_sdWalk_csr(SCIP *scip, int edgelimit, const int *edgestate, GRAPH *g, int *termmark, SCIP_Real *dist, int *visitlist, STP_Bool *visited, DHEAP *dheap, int *nelims)
Definition: reduce_sd.c:2818
int *RESTRICT mark
Definition: graphdefs.h:198
#define STP_BD_MAXDEGREE
Definition: reduce_sd.c:42
SCIP_Bool graph_pc_termIsNonLeafTerm(const GRAPH *, int)
SCIP_Bool graph_sdWalksTriangle(SCIP *, const GRAPH *, const int *, const int *, SCIP_Real, int, int, int, SCIP_Real *, SCIP_Real *, int *, int *, DHEAP *, STP_Bool *)
SCIP_RETCODE reduce_sdBiasedNeighbor(SCIP *scip, SD *sdistance, GRAPH *g, int *nelims)
Definition: reduce_sd.c:1927
SCIP_RETCODE reduce_sdWalkTriangle(SCIP *scip, int edgelimit, SCIP_Bool usestrongreds, GRAPH *g, int *termmark, SCIP_Real *dist, int *visitlist, STP_Bool *visited, DHEAP *dheap, int *nelims)
Definition: reduce_sd.c:3011
static int getcloseterms2term(SCIP *scip, const GRAPH *g, const GRAPH *netgraph, SCIP_Real *termdist, SCIP_Real ecost, int *neighbterms, int *nodesid, int *nodesorg, int i)
Definition: reduce_sd.c:503
static SCIP_RETCODE sdCliqueInitData(SCIP *scip, const GRAPH *g, int centernode, const GRAPH *cliquegraph, const int *cliqueNodeMap, DIJK *dijkdata, SDCLIQUE *sdclique)
Definition: reduce_sd.c:1122
SCIP_Real * cost3
Definition: graphdefs.h:166
static void sdwalkResetExt2(int nnodes, int nvisits, const int *visitlist, SCIP_Real *dist, int *nprevterms, int *nprevNPterms, int *nprevedges, int *state, STP_Bool *visited)
Definition: reduce_sd.c:312
int * position
Definition: graphdefs.h:305
void graph_dijkLimited_reset(const GRAPH *, DIJK *)
Definition: graph_util.c:2105
int *RESTRICT oeat
Definition: graphdefs.h:231
static SCIP_Real sdGetSdNeighbor(const GRAPH *g, int i, int i2, SCIP_Real sd_upper, SCIP_Real sd_sufficient, SD *sddata)
Definition: reduce_sd.c:912
SCIP_RETCODE graph_get4nextTTerms(SCIP *, GRAPH *, const SCIP_Real *, PATH *, int *, int *, int *)
Definition: graph_tpath.c:1601
#define LE(a, b)
Definition: portab.h:83
static SCIP_Real getSd(SCIP *scip, GRAPH *g, SDGRAPH *sdgraph, PATH *vnoi, SCIP_Real sd_initial, int *vbase, int i, int i2, int limit)
Definition: reduce_sd.c:703
#define GE(a, b)
Definition: portab.h:85
static SCIP_RETCODE sdStarBiasedProcessNode(SCIP *scip, int node, SCIP_Bool usestrongreds, const SDPROFIT *sdprofit, GRAPH *g, DIJK *dijkdata, int *RESTRICT star_base, SCIP_Bool *RESTRICT edge_deletable, int *nelims)
Definition: reduce_sd.c:172
miscellaneous methods used for solving Steiner problems
SCIP_Bool extended
Definition: graphdefs.h:267
int stp_type
Definition: graphdefs.h:264
static SCIP_RETCODE sdStarInit(SCIP *scip, const GRAPH *g, int edgelimit, DIJK **dijkdata, int *RESTRICT *star_base, SCIP_Bool *RESTRICT *edge_deletable)
Definition: reduce_sd.c:53
SCIP_RETCODE reduce_sdPc(SCIP *scip, GRAPH *g, PATH *vnoi, int *heap, int *state, int *vbase, int *nodesid, int *nodesorg, int *nelims)
Definition: reduce_sd.c:2023
DHEAP * dheap
Definition: graphdefs.h:315
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool usestrongreds
Definition: reducedefs.h:84
static void sdGetSdsCliqueTermWalks(const GRAPH *g, SD *RESTRICT sddata, GRAPH *RESTRICT cliquegraph, SDCLIQUE *RESTRICT sdclique)
Definition: reduce_sd.c:1242
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:128
SCIP_Real * prize
Definition: graphdefs.h:210
static int getcloseterms(SCIP *scip, const PATH *vnoi, SCIP_Real *termdist, SCIP_Real ecost, const int *vbase, int *neighbterms, int i, int nnodes)
Definition: reduce_sd.c:464
void graph_edge_add(SCIP *, GRAPH *, int, int, double, double)
SCIP_Real dist
Definition: graphdefs.h:286
static void sdStarReset(int nnodes, int nvisits, const int *visitlist, int *RESTRICT star_base, SCIP_Real *RESTRICT dist, STP_Bool *RESTRICT visited, DHEAP *RESTRICT dheap)
Definition: reduce_sd.c:135
int *RESTRICT grad
Definition: graphdefs.h:201
static SCIP_RETCODE ledgeFromNetgraph(SCIP *scip, const GRAPH *netgraph, const PATH *mst, const int *edgeorg, const PATH *vnoi, const int *vbase, GRAPH *g, int *nelims)
Definition: reduce_sd.c:1301
SCIP_RETCODE reduce_unconnected(SCIP *, GRAPH *)
void graph_knot_add(GRAPH *, int)
Definition: graph_node.c:64
SCIP_Real reduce_sdGetSd(const GRAPH *g, int i, int i2, SCIP_Real sd_upper, SCIP_Real sd_sufficient, SD *sddata)
Definition: reduce_sd.c:2433
static int getlecloseterms(SCIP *scip, PATH *vnoi, SCIP_Real *termdist, SCIP_Real ecost, int *vbase, int *neighbterms, int i, int nnodes)
Definition: reduce_sd.c:554
void graph_edge_delBlocked(SCIP *, GRAPH *, const SCIP_Bool *, SCIP_Bool)
Definition: graph_edge.c:448
#define NULL
Definition: lpi_spx1.cpp:155
SCIP_RETCODE graph_knot_delPseudo(SCIP *, GRAPH *, const SCIP_Real *, const SCIP_Real *, const SCIP_Real *, int, REDCOST *, SCIP_Bool *)
const SCIP_Bool * reduce_sdneighborGetBlocked(const SDN *)
#define EQ(a, b)
Definition: portab.h:79
void reduce_sdgraphFreeFromDistGraph(SCIP *, SDGRAPH **)
void reduce_sdprofitFree(SCIP *, SDPROFIT **)
int knots
Definition: graphdefs.h:190
SCIP_Bool graph_pseudoAncestors_edgesInConflict(SCIP *, const GRAPH *, const int *, int)
#define SCIP_CALL(x)
Definition: def.h:384
#define MST_MODE
Definition: graphdefs.h:98
SCIP_RETCODE graph_sdComputeCliqueStar(SCIP *, const GRAPH *, const SDPROFIT *, SDCLIQUE *)
SCIP_RETCODE reduce_sdEdgeCliqueStar(SCIP *scip, int edgelimit, GRAPH *g, int *nelims)
Definition: reduce_sd.c:2939
#define STP_PCSPG
Definition: graphdefs.h:44
#define LT(a, b)
Definition: portab.h:81
#define STP_SDWALK_MAXNPREVS
Definition: reduce_sd.c:44
SCIP_Real reduce_sdgraphGetMaxCost(const SDGRAPH *)
struct single_special_distance_pc SD1PC
unsigned char STP_Bool
Definition: portab.h:34
static SCIP_Real reduce_sdprofitGetProfit(const SDPROFIT *sdprofit, int node, int nonsource1, int nonsource2)
Definition: reducedefs.h:178
SCIP_RETCODE graph_dijkLimited_init(SCIP *, const GRAPH *, DIJK **)
Definition: graph_util.c:1989
static SCIP_Real sdGetSd(const GRAPH *g, int i, int i2, SCIP_Real sd_upper, SCIP_Real sd_sufficient, SCIP_Bool onlyIntermedTerms, SD *sddata)
Definition: reduce_sd.c:815
SCIP_RETCODE graph_sdStarBiased(SCIP *, const GRAPH *, const SDPROFIT *, int, int *, DIJK *, SCIP_Bool *)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
#define GT(a, b)
Definition: portab.h:84
void graph_dijkLimited_free(SCIP *, DIJK **)
Definition: graph_util.c:2143
#define SCIP_Bool
Definition: def.h:84
int *RESTRICT ieat
Definition: graphdefs.h:230
SCIP_Bool graph_isMarked(const GRAPH *)
Definition: graph_base.c:1165
static void pcBiasCostsDCSR(SCIP *scip, const GRAPH *g, SCIP_Bool biasreversed, SCIP_Real *costbiased, SCIP_Real *mincost_in)
Definition: reduce_sd.c:595
int *RESTRICT tail
Definition: graphdefs.h:223
#define flipedge(edge)
Definition: graphdefs.h:84
#define MAX(x, y)
Definition: tclique_def.h:83
SCIP_RETCODE reduce_sdStarBiasedWithProfit(SCIP *scip, int edgelimit, const SDPROFIT *sdprofit, SCIP_Bool usestrongreds, GRAPH *g, int *nelims)
Definition: reduce_sd.c:3353
int *RESTRICT term
Definition: graphdefs.h:196
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:127
void graph_edge_printInfo(const GRAPH *, int)
Definition: graph_stats.c:133
#define EDGE_BLOCKED
Definition: graphdefs.h:95
void graph_tpathsGet4CloseTerms(const GRAPH *, const TPATHS *, int, SCIP_Real, int *RESTRICT, int *RESTRICT, SCIP_Real *RESTRICT, int *RESTRICT)
SCIP_Bool graph_sdWalksExt2(SCIP *, const GRAPH *, const SCIP_Real *, const int *, SCIP_Real, int, int, int, int, SCIP_Real *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, STP_Bool *)
void graph_path_exit(SCIP *, GRAPH *)
Definition: graph_path.c:515
SCIP_Bool graph_pc_isPc(const GRAPH *)
#define CONNECT
Definition: graphdefs.h:87
Portable definitions.
void graph_get4nextTermPaths(GRAPH *, const SCIP_Real *, const SCIP_Real *, PATH *, int *, int *)
Definition: graph_tpath.c:1582
static SCIP_Bool isPseudoDeletableDeg3(SCIP *scip, const GRAPH *g, const SCIP_Real *sdsK3, const int *edgesK3, SCIP_Real costK3, SCIP_Bool allowEquality)
Definition: reduce_sd.c:989
static void sdStarFinalize(SCIP *scip, GRAPH *g, DIJK **dijkdata, int *RESTRICT *star_base, SCIP_Bool *RESTRICT *edge_deletable)
Definition: reduce_sd.c:103
static void deleteEdge(SCIP *scip, int edge, GRAPH *g, PR *pr)
Definition: reduce_path.c:127
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE reduce_sdBiased(SCIP *scip, SD *sdistance, GRAPH *g, int *nelims)
Definition: reduce_sd.c:1845
SCIP_RETCODE reduce_sdgraphInitFromDistGraph(SCIP *, const GRAPH *, GRAPH *, int *, SDGRAPH **)
SCIP_RETCODE reduce_sdspSap(SCIP *scip, GRAPH *g, PATH *pathtail, PATH *pathhead, int *heap, int *statetail, int *statehead, int *memlbltail, int *memlblhead, int *nelims, int limit)
Definition: reduce_sd.c:2661
SCIP_Bool graph_pc_knotIsFixedTerm(const GRAPH *, int)
SCIP_Real * cost
Definition: graphdefs.h:221
static SCIP_RETCODE sdCliqueUpdateGraphWithStarWalks(SCIP *scip, const GRAPH *g, const SDPROFIT *sdprofit, GRAPH *cliquegraph, SDCLIQUE *sdclique)
Definition: reduce_sd.c:1179
SCIP_Bool reduce_sdgraphHasMstHalfMark(const SDGRAPH *)
SCIP_Bool graph_pc_isPcMw(const GRAPH *)
void graph_dijkLimited_clean(const GRAPH *, DIJK *)
Definition: graph_util.c:2083
SCIP_RETCODE reduce_getSdByPaths(SCIP *scip, GRAPH *g, PATH *pathtail, PATH *pathhead, SCIP_Real *sdist, SCIP_Real distlimit, int *heap, int *statetail, int *statehead, int *memlbltail, int *memlblhead, int i, int i2, int limit, SCIP_Bool pc, SCIP_Bool mw)
Definition: reduce_sd.c:2304
static void sdCliqueFreeData(SCIP *scip, SDCLIQUE *sdclique)
Definition: reduce_sd.c:1166
#define SCIP_Real
Definition: def.h:177
SCIP_RETCODE reduce_sdUpdateWithSdNeighbors(SCIP *, GRAPH *, SD *, int *)
void graph_sdStar(SCIP *, const GRAPH *, SCIP_Bool, int, int, int *, SCIP_Real *, int *, int *, DHEAP *, STP_Bool *, SCIP_Bool *)
SCIP_RETCODE reduce_sdStar(SCIP *scip, int edgelimit, SCIP_Bool usestrongreds, GRAPH *g, SCIP_Real *dist, int *star_base, int *visitlist, STP_Bool *visited, DHEAP *dheap, int *nelims)
Definition: reduce_sd.c:3202
void graph_sdPaths(const GRAPH *, PATH *, const SCIP_Real *, SCIP_Real, int *, int *, int *, int *, int, int, int)
Definition: graph_path.c:684
int *RESTRICT outbeg
Definition: graphdefs.h:204
SCIP_RETCODE reduce_sdprofitInit(SCIP *, const GRAPH *, SDPROFIT **)
#define SCIP_Longint
Definition: def.h:162
int edges
Definition: graphdefs.h:219
STP_Bool * node_visited
Definition: graphdefs.h:317
int graph_get_nNodes(const GRAPH *)
Definition: graph_stats.c:536
static SCIP_Real sdGetSdPcMw(SCIP *scip, const GRAPH *g, SCIP_Real distlimit, int i, int i2, int edgelimit, SD1PC *sd1pc)
Definition: reduce_sd.c:2466
SCIP_RETCODE reduce_bd34(SCIP *scip, GRAPH *g, PATH *pathtail, PATH *pathhead, int *heap, int *statetail, int *statehead, int *memlbltail, int *memlblhead, int *nelims, int limit, SCIP_Real *offset)
Definition: reduce_sd.c:4516
SCIP_RETCODE reduce_sdStarPc(SCIP *scip, int edgelimit, const int *edgestate, GRAPH *g, SCIP_Real *dist, int *star_base, int *visitlist, STP_Bool *visited, DHEAP *dheap, int *nelims)
Definition: reduce_sd.c:3546
RPARAMS * redparameters
Definition: reducedefs.h:102
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define UNKNOWN
Definition: sepa_mcf.c:4095
SCIP_RETCODE graph_buildCompleteGraph(SCIP *, GRAPH **, int)
Definition: graph_base.c:440
#define nnodes
Definition: gastrans.c:65
SCIP_RETCODE reduce_sdsp(SCIP *scip, GRAPH *g, PATH *pathtail, int *heap, int *statetail, int *statehead, int *memlbltail, int *memlblhead, int *nelims, int limit, SCIP_Bool usestrongreds)
Definition: reduce_sd.c:4020
SCIP_RETCODE graph_init(SCIP *, GRAPH **, int, int, int)
Definition: graph_base.c:607
DCSR * dcsr_storage
Definition: graphdefs.h:271
const STP_Bool * reduce_sdgraphGetMstHalfMark(const SDGRAPH *)
SCIP_Bool nodereplacing
Definition: reducedefs.h:79
includes various reduction methods for Steiner tree problems
SCIP_RETCODE reduce_sdStarPc2(SCIP *scip, int edgelimit, SCIP_Bool usestrongreds, GRAPH *g, SCIP_Real *dist, int *star_base, int *visitlist, STP_Bool *visited, DHEAP *dheap, int *nelims)
Definition: reduce_sd.c:3394
#define STP_RPCSPG
Definition: graphdefs.h:45
#define STP_MWCSP
Definition: graphdefs.h:51
SCIP_RETCODE reduce_sdStarBiased(SCIP *scip, int edgelimit, SCIP_Bool usestrongreds, GRAPH *g, int *nelims)
Definition: reduce_sd.c:3332
SCIP_RETCODE reduce_sdGetSdsCliquegraph(SCIP *scip, const GRAPH *g, int centernode, const int *cliqueNodeMap, DIJK *dijkdata, SD *sddata, GRAPH *cliquegraph)
Definition: reduce_sd.c:1394
SCIP callable library.
SCIP_RETCODE reduce_sdWalkExt(SCIP *scip, int edgelimit, SCIP_Bool usestrongreds, GRAPH *g, SCIP_Real *dist, int *heap, int *state, int *visitlist, STP_Bool *visited, int *nelims)
Definition: reduce_sd.c:3827