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