Scippy

SCIP

Solving Constraint Integer Programs

graph_path.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 graph_path.c
17  * @brief Shortest path based graph algorithms for Steiner problems
18  * @author Thorsten Koch
19  * @author Henriette Franz
20  * @author Daniel Rehfeldt
21  *
22  * This file encompasses various (heap-based) shortest path based algorithms including
23  * Dijkstra's algorithm.
24  *
25  */
26 //#define SCIP_DEBUG
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <stddef.h>
30 #include <assert.h>
31 #include "portab.h"
32 #include "graph.h"
33 #include "graphheaps.h"
34 #include "shortestpath.h"
35 #include "solstp.h"
36 
37 
38 
39 /*---------------------------------------------------------------------------*/
40 /*--- Name : CORRECT heap ---*/
41 /*--- Function : Setzt ein neues Element auf den Heap, bzw. korrigiert ---*/
42 /*--- die Position eines vorhandenen Elementes ---*/
43 /*--- Parameter: Derzeitige Entfernungen und benutzten Kanten, ---*/
44 /*--- Neuer Knoten, Vorgaengerknoten, Kante von der man aus ---*/
45 /*--- den neuen Knoten erreicht, Kosten der Kante, ---*/
46 /*--- sowie Betriebsmodus ---*/
47 /*--- Returns : Nichts ---*/
48 /*---------------------------------------------------------------------------*/
49 inline static
51  int* RESTRICT heap,
52  int* RESTRICT state,
53  int* RESTRICT count, /* pointer to store the number of elements on the heap */
54  PATH* RESTRICT path,
55  int l,
56  int k,
57  int edge,
58  SCIP_Real cost,
59  int mode)
60 {
61  int t;
62  int c;
63  int j;
64 
65  path[l].dist = (mode == MST_MODE) ? cost : (path[k].dist + cost);
66  path[l].edge = edge;
67 
68  /* new node? */
69  if( state[l] == UNKNOWN )
70  {
71  heap[++(*count)] = l;
72  state[l] = (*count);
73  }
74 
75  /* Heap shift up */
76  j = state[l];
77  c = j / 2;
78  while( (j > 1) && path[heap[c]].dist > path[heap[j]].dist )
79  {
80  t = heap[c];
81  heap[c] = heap[j];
82  heap[j] = t;
83  state[heap[j]] = j;
84  state[heap[c]] = c;
85  j = c;
86  c = j / 2;
87  }
88 }
89 
90 inline static
92  int* RESTRICT heap,
93  int* RESTRICT state,
94  int* RESTRICT count, /* pointer to store the number of elements on the heap */
95  const PATH* path)
96 {
97  int k;
98  int t;
99  int c;
100  int j;
101 
102  /* Heap shift down
103  * (Oberstes Element runter und korrigieren)
104  */
105  k = heap[1];
106  j = 1;
107  c = 2;
108  heap[1] = heap[(*count)--];
109  state[heap[1]] = 1;
110 
111  if ((*count) > 2)
112  if (LT(path[heap[3]].dist, path[heap[2]].dist))
113  c++;
114 
115  while((c <= (*count)) && GT(path[heap[j]].dist, path[heap[c]].dist))
116  {
117  t = heap[c];
118  heap[c] = heap[j];
119  heap[j] = t;
120  state[heap[j]] = j;
121  state[heap[c]] = c;
122  j = c;
123  c += c;
124 
125  if ((c + 1) <= (*count))
126  if (LT(path[heap[c + 1]].dist, path[heap[c]].dist))
127  c++;
128  }
129  return(k);
130 }
131 
132 /** resets node */
133 inline static
135  PATH* RESTRICT path,
136  int* RESTRICT heap,
137  int* RESTRICT state,
138  int* RESTRICT count,
139  int node
140  )
141 {
142  int t;
143  int c;
144  int j;
145 
146  path[node].dist = 0.0;
147 
148  heap[++(*count)] = node;
149  state[node] = (*count);
150 
151  /* heap shift up */
152  j = state[node];
153  c = j / 2;
154 
155  while( (j > 1) && GT(path[heap[c]].dist, path[heap[j]].dist) )
156  {
157  t = heap[c];
158  heap[c] = heap[j];
159  heap[j] = t;
160  state[heap[j]] = j;
161  state[heap[c]] = c;
162  j = c;
163  c = j / 2;
164  }
165 }
166 
167 
168 /** connect given node to tree */
169 static inline
171  int k, /**< the vertex */
172  const GRAPH* g, /**< graph data structure */
173  SPATHSPC* spaths_pc, /**< shortest paths data */
174  SCIP_Real* pathdist, /**< distance array (on vertices) */
175  int* pathedge, /**< predecessor edge array (on vertices) */
176  STP_Bool* connected, /**< array to mark whether a vertex is part of computed Steiner tree */
177  int* count, /**< for the heap */
178  int* nterms /**< terminal count */
179 )
180 {
181  assert(k >= 0);
182 
183  connected[k] = TRUE;
184  pathdist[k] = 0.0;
185  shortestpath_pcConnectNode(g, connected, k, spaths_pc);
186  (*nterms)++;
187 
188  assert(pathedge[k] != -1);
189 
190  /* connect k to current subtree */
191  for( int node = g->tail[pathedge[k]]; !connected[node]; node = g->tail[pathedge[node]] )
192  {
193  connected[node] = TRUE;
194  resetX(pathdist, g->path_heap, g->path_state, count, node, 0.0);
195 
196  if( Is_pseudoTerm(g->term[node]) )
197  {
198  shortestpath_pcConnectNode(g, connected, node, spaths_pc);
199  (*nterms)++;
200  }
201 
202  assert(pathedge[node] != -1);
203  }
204 }
205 
206 
207 /** initialize */
208 static inline
210  GRAPH* g, /**< graph data structure */
211  SCIP_Real* pathdist, /**< distance array (on vertices) */
212  int* pathedge, /**< predecessor edge array (on vertices) */
213  STP_Bool* connected, /**< array to mark whether a vertex is part of computed Steiner tree */
214  int* npseudoterms /**< number of pseudo terminals */
215 )
216 {
217  const int nnodes = graph_get_nNodes(g);
218  int ntermspos = 0;
219  int* const RESTRICT state = g->path_state;
220 
221  for( int k = 0; k < nnodes; k++ )
222  {
223  g->mark[k] = ((g->grad[k] > 0) && !Is_term(g->term[k]));
224  state[k] = UNKNOWN;
225  pathdist[k] = FARAWAY;
226  pathedge[k] = -1;
227  connected[k] = FALSE;
228 
229  if( Is_pseudoTerm(g->term[k]) )
230  ntermspos++;
231  }
232 
233  if( npseudoterms )
234  *npseudoterms = ntermspos;
235 }
236 
237 
238 /** initialize */
239 static inline
241  GRAPH* g, /**< graph data structure */
242  SCIP_Real* pathdist, /**< distance array (on vertices) */
243  int* pathedge, /**< predecessor edge array (on vertices) */
244  STP_Bool* connected, /**< array to mark whether a vertex is part of computed Steiner tree */
245  int* nrealterms /**< number of real terminals */
246 )
247 {
248  const int nnodes = graph_get_nNodes(g);
249  int nrterms = 0;
250  int* const RESTRICT state = g->path_state;
251 
252  /* unmark dummy terminals */
254  assert(graph_pc_knotIsFixedTerm(g, g->source));
255 
256  for( int k = 0; k < nnodes; k++ )
257  {
258  state[k] = UNKNOWN;
259  pathdist[k] = FARAWAY;
260  pathedge[k] = -1;
261  connected[k] = FALSE;
262 
263  if( graph_pc_knotIsFixedTerm(g, k) )
264  {
265  assert(g->mark[k]);
266  nrterms++;
267  assert(!Is_pseudoTerm(g->term[k]));
268  }
269  }
270 
271  if( nrealterms )
272  *nrealterms = nrterms;
273 }
274 
275 
276 /** For DCSTP can terminal be connected to current tree? */
277 static inline
279  const GRAPH* g, /**< graph data structure */
280  int term, /**< terminal to be checked */
281  const int* deg_free, /**< free degree of each node */
282  const int* pathedge, /**< predecessor edge array (on vertices) */
283  const STP_Bool* connected /**< array to mark whether a vertex is part of computed Steiner tree */
284 )
285 {
286  int node;
287 
288  assert(!connected[term]);
289  assert(g->stp_type == STP_DCSTP);
290  assert(deg_free[term] >= 0);
291 
292  if( deg_free[term] == 0 )
293  {
294  SCIPdebugMessage("failed to add %d-path because free degree 0 end \n", term);
295  return FALSE;
296  }
297 
298  /* NOTE: intermediary path vertices need to be of degree at least 2 */
299  for( node = g->tail[pathedge[term]]; !connected[node]; node = g->tail[pathedge[node]] )
300  {
301  assert(pathedge[node] != -1);
302  assert(!Is_term(g->term[node]));
303  assert(deg_free[node] >= 0);
304 
305  if( deg_free[node] <= 1 )
306  {
307  SCIPdebugMessage("failed to add %d-path due to node %d (free degree: %d) \n", term, node, deg_free[node]);
308  return FALSE;
309  }
310  }
311 
312  assert(connected[node]);
313 
314  if( deg_free[node] == 0 )
315  {
316  SCIPdebugMessage("failed to add %d-path because free degree 0 start \n", node);
317  return FALSE;
318  }
319 
320  return TRUE;
321 }
322 
323 
324 
325 /** For DCSTP: extends (implicitly) given tree */
326 static
328  const GRAPH* g, /**< graph data structure */
329  const SCIP_Real* cost, /**< edgecosts */
330  int* heapsize, /**< heap size */
331  int* pathdeg_free, /**< currently available degree of path */
332  int* nodedeg_free, /**< currently available degree of node */
333  SCIP_Real* pathdist, /**< distance array (on vertices) */
334  int* pathedge, /**< predecessor edge array (on vertices) */
335  STP_Bool* connected, /**< array to mark whether a vertex is part of computed Steiner tree */
336  int* result, /**< solution array */
337  int* soldegfree, /**< per node: solution degree */
338  int* nsolterms /**< number of solution terminals */
339  )
340 {
341  int* RESTRICT heap = g->path_heap;
342  int* RESTRICT state = g->path_state;
343 
344  assert(*heapsize > 0);
345  assert(*soldegfree > 0);
346 
347  /* repeat until heap is empty */
348  while( *heapsize > 0 )
349  {
350  const int k = nearestX(heap, state, heapsize, pathdist);
351  state[k] = UNKNOWN;
352 
353  /* k is terminal and not connected yet? */
354  if( Is_term(g->term[k]) && !connected[k] )
355  {
356  /* no degree problem? */
357  if( stDcTermIsConnectable(g, k, nodedeg_free, pathedge, connected) )
358  {
359  int node;
360  assert(pathedge[k] >= 0);
361  assert(nodedeg_free[k] >= 1);
362 
363  nodedeg_free[k] -= 1;
364  result[pathedge[k]] = CONNECT;
365  connected[k] = TRUE;
366  pathdist[k] = 0.0;
367  pathdeg_free[k] = 0;
368  SCIPdebugMessage("connecting terminal %d \n", k);
369 
370  /* connect k to current solution */
371  for( node = g->tail[pathedge[k]]; !connected[node]; node = g->tail[pathedge[node]] )
372  {
373  assert(pathedge[node] != -1);
374  assert(!Is_term(g->term[node]));
375  assert(nodedeg_free[node] >= 2);
376 
377  SCIPdebugMessage("...adding path node %d \n", node);
378 
379  pathdeg_free[node] = 0;
380  nodedeg_free[node] -= 2;
381  connected[node] = TRUE;
382  result[pathedge[node]] = CONNECT;
383  resetX(pathdist, heap, state, heapsize, node, 0.0);
384  }
385 
386  assert(nodedeg_free[node] >= 1);
387  nodedeg_free[node] -= 1;
388 
389  /* have all terminals been reached? */
390  if( ++(*nsolterms) == g->terms )
391  break;
392  }
393  }
394 
395  assert((*nsolterms) < g->terms);
396 
397  if( !connected[k] )
398  {
399  /* NOTE: if k is not in tree yet, adding it as a non-leaf reduces its free degree by two */
400  if( nodedeg_free[k] <= 1 )
401  continue;
402 
403  /* NOTE: if path to terminal could not be connect now, it can also not be used as sub-path later */
404  if( Is_term(g->term[k]) )
405  continue;
406  }
407  else if( nodedeg_free[k] == 0 )
408  {
409  continue;
410  }
411 
412  /* update adjacent vertices */
413  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
414  {
415  const int m = g->head[e];
416 
417  if( connected[m] )
418  continue;
419 
420  assert(state[m]);
421 
422  if( GT(pathdist[m], (pathdist[k] + cost[e]))
423  || (EQ(pathdist[m], (pathdist[k] + cost[e])) && (pathdeg_free[k] + nodedeg_free[m] - 2 > pathdeg_free[m]) )
424  )
425  {
426  assert(nodedeg_free[m] > 0);
427  correctX(heap, state, heapsize, pathdist, pathedge, m, k, e, cost[e]);
428 
429  pathdeg_free[m] = pathdeg_free[k] + nodedeg_free[m] - 2;
430  }
431  }
432  }
433 }
434 
435 
436 
437 /*
438  * Interface methods
439  */
440 
441 /** adds element 'node' to heap */
443  const PATH* path,
444  int node, /* the node to be added */
445  int* RESTRICT heap, /* heap array */
446  int* RESTRICT state,
447  int* count /* pointer to store the number of elements on the heap */
448  )
449 {
450  int c;
451  int j;
452 
453  heap[++(*count)] = node;
454  state[node] = (*count);
455 
456  /* Heap shift up */
457  j = state[node];
458  c = j / 2;
459 
460  while((j > 1) && GT(path[heap[c]].dist, path[heap[j]].dist))
461  {
462  const int t = heap[c];
463  heap[c] = heap[j];
464  heap[j] = t;
465  state[heap[j]] = j;
466  state[heap[c]] = c;
467  j = c;
468  c = j / 2;
469  }
470 }
471 
472 
473 /*---------------------------------------------------------------------------*/
474 /*--- Name : INIT shortest PATH algorithm ---*/
475 /*--- Function : Initialisiert den benoetigten Speicher fuer die ---*/
476 /*--- kuerzeste Wege Berechnung ---*/
477 /*--- Parameter: Graph in dem berechnet werden soll. ---*/
478 /*--- Returns : Nichts ---*/
479 /*---------------------------------------------------------------------------*/
481  SCIP* scip, /**< SCIP data structure */
482  GRAPH* g /**< graph data structure */
483  )
484 {
485  assert(g != NULL);
486  assert(g->path_heap == NULL);
487  assert(g->path_state == NULL);
488 
489  SCIP_CALL( SCIPallocMemoryArray(scip, &(g->path_heap), g->knots + 1) );
490  SCIP_CALL( SCIPallocMemoryArray(scip, &(g->path_state), g->knots) );
491 
492  return SCIP_OKAY;
493 }
494 
495 
496 /** existing? */
498  const GRAPH* g /**< graph data structure */
499  )
500 {
501  assert(g);
502  assert((g->path_heap != NULL) == (g->path_state != NULL));
503 
504  return (g->path_heap != NULL) ;
505 }
506 
507 
508 /*---------------------------------------------------------------------------*/
509 /*--- Name : EXIT shortest PATH algorithm ---*/
510 /*--- Function : Gibt den bei der initialisierung angeforderten Speicher ---*/
511 /*--- wieder frei ---*/
512 /*--- Parameter: Keine ---*/
513 /*--- Returns : Nichts ---*/
514 /*---------------------------------------------------------------------------*/
516  SCIP* scip, /**< SCIP data structure */
517  GRAPH* g /**< graph data structure */
518  )
519 {
520  assert(g);
521 #ifndef WITH_UG
522  assert(g->path_heap && g->path_state);
523 #endif
524 
525  SCIPfreeMemoryArrayNull(scip, &(g->path_state));
526  SCIPfreeMemoryArrayNull(scip, &(g->path_heap));
527 }
528 
529 /*---------------------------------------------------------------------------*/
530 /*--- Name : FIND shortest PATH / minimum spanning tree ---*/
531 /*--- Function : Dijkstras Algorithmus zur bestimmung eines kuerzesten ---*/
532 /*--- Weges in einem gerichteten Graphen. ---*/
533 /*--- Parameter: Graph, Nummer des Startknotens und Betriebsmodus ---*/
534 /*--- (Kuerzeste Wege oder minimal spannender Baum) ---*/
535 /*--- Returns : Liefert einen Vektor mit einem PATH Element je Knotem. ---*/
536 /*---- Setzt das .dist Feld zu jedem Knoten auf die Entfernung ---*/
537 /*--- zum Startknoten, sowie das .prev Feld auf den Knoten von ---*/
538 /*--- dem man zum Knoten gekommen ist. Im MST Modus steht im ---*/
539 /*--- .dist Feld die Entfernung zum naechsten Knoten. ---*/
540 /*---------------------------------------------------------------------------*/
542  SCIP* scip, /**< SCIP data structure */
543  const GRAPH* g, /**< graph data structure */
544  int mode, /**< shortest path (FSP_MODE) or minimum spanning tree (MST_MODE)? */
545  int start, /**< start vertex */
546  const SCIP_Real* cost, /**< edge costs */
547  PATH* path /**< shortest paths data structure */
548  )
549 {
550  const int nnodes = graph_get_nNodes(g);
551  int* RESTRICT heap = g->path_heap;
552  int* RESTRICT state = g->path_state;
553 
554  assert(g != NULL);
555  assert(start >= 0);
556  assert(start < g->knots);
557  assert((mode == FSP_MODE) || (mode == MST_MODE));
558  assert(g->path_heap != NULL);
559  assert(g->path_state != NULL);
560  assert(path != NULL);
561  assert(cost != NULL);
562  assert(g->mark[start]);
563 
564  /* initialize */
565  for( int i = 0; i < nnodes; i++ )
566  {
567  state[i] = UNKNOWN;
568  path[i].dist = FARAWAY + 1.0;
569  path[i].edge = UNKNOWN;
570  }
571 
572  path[start].dist = 0.0;
573 
574  if( nnodes > 1 )
575  {
576  /* add first node to heap */
577  int nheapElems = 1;
578  heap[nheapElems] = start;
579  state[start] = nheapElems;
580 
581  while( nheapElems > 0 )
582  {
583  /* get nearest labeled node */
584  const int k = pathheapGetNearest(heap, state, &nheapElems, path);
585 
586  /* mark as scanned */
587  state[k] = CONNECT;
588 
589  for( int e = g->outbeg[k]; e >= 0; e = g->oeat[e] )
590  {
591  const int m = g->head[e];
592  assert(e != EAT_LAST);
593 
594  /* node not scanned and valid? */
595  if( state[m] )
596  {
597  /* closer than previously and valid? */
598  if( path[m].dist > ((mode == MST_MODE) ? cost[e] : (path[k].dist + cost[e])) && g->mark[m] )
599  {
600  pathheapCorrect(heap, state, &nheapElems, path, m, k, e, cost[e], mode);
601  }
602  }
603  }
604  }
605  }
606 }
607 
608 
609 /** limited Dijkstra on incoming edges */
611  const GRAPH* g, /**< graph data structure */
612  const SCIP_Real* edges_cost, /**< edge cost */
613  const SCIP_Bool* nodes_abort, /**< nodes to abort at */
614  int startnode, /**< start */
615  DIJK* dijkdata, /**< Dijkstra data */
616  SCIP_Real* abortdistance /**< distance at which abort happened */
617 )
618 {
619  SCIP_Real* RESTRICT nodes_dist = dijkdata->node_distance;
620  int* RESTRICT visitlist = dijkdata->visitlist;
621  STP_Bool* RESTRICT visited = dijkdata->node_visited;
622  DHEAP* dheap = dijkdata->dheap;
623  int* const state = dheap->position;
624  int nvisits = 0;
625 
626  assert(nodes_dist && visitlist && visited && dheap && edges_cost && nodes_abort && abortdistance);
627  assert(dheap->size == 0);
628  assert(graph_knot_isInRange(g, startnode));
629 
630 #ifndef NDEBUG
631  for( int k = 0; k < g->knots; k++ )
632  {
633  assert(nodes_dist[k] == FARAWAY);
634  assert(state[k] == UNKNOWN);
635  }
636 #endif
637 
638  *abortdistance = -FARAWAY;
639  nodes_dist[startnode] = 0.0;
640  visitlist[(nvisits)++] = startnode;
641  visited[startnode] = TRUE;
642  graph_heap_correct(startnode, 0.0, dheap);
643 
644  while( dheap->size > 0 )
645  {
646  const int k = graph_heap_deleteMinReturnNode(dheap);
647  assert(state[k] == CONNECT);
648 
649  if( nodes_abort[k] )
650  {
651  *abortdistance = nodes_dist[k];
652  break;
653  }
654 
655  for( int e = g->inpbeg[k]; e >= 0; e = g->ieat[e] )
656  {
657  const int m = g->tail[e];
658 
659  if( state[m] != CONNECT )
660  {
661  const SCIP_Real distnew = nodes_dist[k] + edges_cost[e];
662 
663  if( !visited[m] )
664  {
665  assert(nvisits < g->knots);
666  visitlist[(nvisits)++] = m;
667  visited[m] = TRUE;
668  }
669 
670  if( LT(distnew, nodes_dist[m]) )
671  {
672  nodes_dist[m] = distnew;
673  graph_heap_correct(m, distnew, dheap);
674  }
675  }
676  }
677  }
678 
679  dijkdata->nvisits = nvisits;
680 }
681 
682 
683 /** limited Dijkstra, stopping at terminals */
685  const GRAPH* g, /**< graph data structure */
686  PATH* path, /**< shortest paths data structure */
687  const SCIP_Real* cost, /**< edge costs */
688  SCIP_Real distlimit, /**< distance limit of the search */
689  int* heap, /**< array representing a heap */
690  int* state, /**< array to indicate whether a node has been scanned during SP calculation */
691  int* memlbl, /**< array to save labelled nodes */
692  int* nlbl, /**< number of labelled nodes */
693  int tail, /**< tail of the edge */
694  int head, /**< head of the edge */
695  int limit /**< maximum number of edges to consider during execution */
696  )
697 {
698  int count;
699  int nchecks;
700  const int limit1 = limit / 2;
701  const SCIP_Bool isDirected = !graph_typeIsUndirected(g);
702 
703  assert(g != NULL);
704  assert(heap != NULL);
705  assert(path != NULL);
706  assert(cost != NULL);
707  assert(nlbl != NULL);
708  assert(memlbl != NULL);
709  assert(limit1 >= 0);
710 
711  *nlbl = 0;
712 
713  if( g->grad[tail] == 0 || g->grad[head] == 0 )
714  return;
715 
716  assert(g->mark[head] && g->mark[tail]);
717 
718  count = 0;
719  nchecks = 0;
720  path[tail].dist = 0.0;
721  state[tail] = CONNECT;
722  memlbl[(*nlbl)++] = tail;
723 
724  /* NOTE: for MW we do not consider the edge between tail and head */
725  if( !graph_pc_isMw(g) )
726  g->mark[head] = FALSE;
727 
728  for( int e = g->outbeg[tail]; e >= 0; e = g->oeat[e] )
729  {
730  const int m = g->head[e];
731 
732  if( g->mark[m] && (GE(distlimit, cost[e])) )
733  {
734  if( isDirected && GE(cost[e], FARAWAY) )
735  continue;
736 
737  assert(GT(path[m].dist, path[tail].dist + cost[e]));
738 
739  /* m labelled the first time */
740  memlbl[(*nlbl)++] = m;
741  pathheapCorrect(heap, state, &count, path, m, tail, e, cost[e], FSP_MODE);
742 
743  if( nchecks++ > limit1 )
744  break;
745  }
746  }
747 
748  g->mark[head] = TRUE;
749 
750  while( count > 0 && nchecks <= limit )
751  {
752  /* get nearest labelled node */
753  const int k = pathheapGetNearest(heap, state, &count, path);
754 
755  /* scanned */
756  state[k] = CONNECT;
757 
758  /* distance limit reached? */
759  if( GT(path[k].dist, distlimit) )
760  break;
761 
762  if( !isDirected )
763  {
764  if( Is_term(g->term[k]) || k == head )
765  continue;
766  }
767 
768  /* correct incident nodes */
769  for( int e = g->outbeg[k]; e >= 0; e = g->oeat[e] )
770  {
771  const int m = g->head[e];
772 
773  if( state[m] && g->mark[m] && GE(distlimit, cost[e]) && (GT(path[m].dist, path[k].dist + cost[e])) )
774  {
775  /* m labelled for the first time? */
776  if( state[m] == UNKNOWN )
777  memlbl[(*nlbl)++] = m;
778  pathheapCorrect(heap, state, &count, path, m, k, e, cost[e], FSP_MODE);
779  }
780  if( nchecks++ > limit )
781  break;
782  }
783  }
784 }
785 
786 
787 /** limited Dijkstra for PCSTP, taking terminals into account */
789  SCIP* scip, /**< SCIP data structure */
790  const GRAPH* g, /**< graph data structure */
791  PATH* path, /**< shortest paths data structure */
792  SCIP_Real* cost, /**< edge costs */
793  SCIP_Real distlimit, /**< distance limit of the search */
794  int* pathmaxnode, /**< maximum weight node on path */
795  int* heap, /**< array representing a heap */
796  int* state, /**< array to indicate whether a node has been scanned during SP calculation */
797  int* stateblock, /**< array to indicate whether a node has been scanned during previous SP calculation */
798  int* memlbl, /**< array to save labelled nodes */
799  int* nlbl, /**< number of labelled nodes */
800  int tail, /**< tail of the edge */
801  int head, /**< head of the edge */
802  int limit /**< maximum number of edges to consider during execution */
803  )
804 {
805  const int limit1 = limit / 2;
806  int count;
807  int nchecks;
808  const SCIP_Bool block = (stateblock != NULL);
809 
810  assert(limit > 0);
811  assert(g != NULL);
812  assert(heap != NULL);
813  assert(path != NULL);
814  assert(cost != NULL);
815  assert(nlbl != NULL);
816  assert(memlbl != NULL);
817  assert(g->prize != NULL);
818  assert(pathmaxnode != NULL);
819 
820  *nlbl = 0;
821 
822  if( g->grad[tail] == 0 || g->grad[head] == 0 )
823  return;
824 
825  assert(g->mark[head] && g->mark[tail]);
826 
827  nchecks = 0;
828  count = 0;
829  path[tail].dist = 0.0;
830  state[tail] = CONNECT;
831  memlbl[(*nlbl)++] = tail;
832 
833  if( g->stp_type != STP_MWCSP )
834  g->mark[head] = FALSE;
835 
836  for( int e = g->outbeg[tail]; e != EAT_LAST; e = g->oeat[e] )
837  {
838  const int m = g->head[e];
839 
840  if( g->mark[m] && SCIPisLE(scip, cost[e], distlimit) )
841  {
842  assert(SCIPisGT(scip, path[m].dist, path[tail].dist + cost[e]));
843 
844  /* m labelled the first time */
845  memlbl[(*nlbl)++] = m;
846  pathheapCorrect(heap, state, &count, path, m, tail, e, cost[e], FSP_MODE);
847 
848  if( nchecks++ > limit1 )
849  break;
850  }
851  }
852 
853  g->mark[head] = TRUE;
854 
855  /* main loop */
856  while( count > 0 )
857  {
858  const int k = pathheapGetNearest(heap, state, &count, path);
859  SCIP_Real maxweight = pathmaxnode[k] >= 0 ? g->prize[pathmaxnode[k]] : 0.0;
860 
861  assert(k != tail);
862  assert(maxweight >= 0);
863  assert(SCIPisLE(scip, path[k].dist - maxweight, distlimit));
864 
865  /* scanned */
866  state[k] = CONNECT;
867 
868  /* stop at other end */
869  if( k == head )
870  continue;
871 
872  if( Is_term(g->term[k]) && g->prize[k] > maxweight && distlimit >= path[k].dist )
873  {
874  pathmaxnode[k] = k;
875  maxweight = g->prize[k];
876  }
877 
878  /* stop at node scanned in first run */
879  if( block && stateblock[k] == CONNECT )
880  continue;
881 
882  /* correct incident nodes */
883  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
884  {
885  const int m = g->head[e];
886 
887  if( state[m] && g->mark[m] && path[m].dist > (path[k].dist + cost[e])
888  && distlimit >= (path[k].dist + cost[e] - maxweight) )
889  {
890  if( state[m] == UNKNOWN ) /* m labeled for the first time? */
891  memlbl[(*nlbl)++] = m;
892 
893  pathmaxnode[m] = pathmaxnode[k];
894  pathheapCorrect(heap, state, &count, path, m, k, e, cost[e], FSP_MODE);
895  }
896  if( nchecks++ > limit )
897  break;
898  }
899  }
900 }
901 
902 
903 
904 /** Dijkstra's algorithm starting from node 'start' */
906  SCIP* scip, /**< SCIP data structure */
907  const GRAPH* g, /**< graph data structure */
908  int start, /**< start vertex */
909  const SCIP_Real* cost, /**< edge costs */
910  SCIP_Real* pathdist, /**< distance array (on vertices) */
911  int* pathedge /**< predecessor edge array (on vertices) */
912  )
913 {
914  int k;
915  int m;
916  int i;
917  int count;
918  int nnodes;
919  int* heap;
920  int* state;
921 
922  assert(g != NULL);
923  assert(start >= 0);
924  assert(start < g->knots);
925  assert(g->path_heap != NULL);
926  assert(g->path_state != NULL);
927  assert(pathdist != NULL);
928  assert(pathedge != NULL);
929  assert(cost != NULL);
930 
931  nnodes = g->knots;
932 
933  if( nnodes == 0 )
934  return;
935 
936  heap = g->path_heap;
937  state = g->path_state;
938 
939  for( i = nnodes - 1; i >= 0; --i )
940  {
941  state[i] = UNKNOWN;
942  pathdist[i] = FARAWAY;
943  pathedge[i] = -1;
944  }
945 
946  k = start;
947  pathdist[k] = 0.0;
948 
949  if( nnodes > 1 )
950  {
951  count = 1;
952  heap[count] = k;
953  state[k] = count;
954 
955  while( count > 0 )
956  {
957  k = nearestX(heap, state, &count, pathdist);
958 
959  state[k] = CONNECT;
960 
961  for( i = g->outbeg[k]; i != EAT_LAST; i = g->oeat[i] )
962  {
963  m = g->head[i];
964 
965  if( state[m] && g->mark[m] && SCIPisGT(scip, pathdist[m], (pathdist[k] + cost[i])) )
966  correctX(heap, state, &count, pathdist, pathedge, m, k, i, cost[i]);
967  }
968  }
969  }
970 }
971 
972 /** Dijkstra on incoming edges until root is reached */
974  SCIP* scip, /**< SCIP data structure */
975  const GRAPH* g, /**< graph data structure */
976  int start, /**< start vertex */
977  const SCIP_Real* cost, /**< edge costs */
978  SCIP_Real* pathdist, /**< distance array (on vertices) */
979  int* pathedge /**< predecessor edge array (on vertices) */
980  )
981 {
982  SCIP_Real rootdist;
983  int k;
984  int m;
985  int i;
986  int count;
987  int nnodes;
988  int* heap;
989  int* state;
990 
991  assert(g != NULL);
992  assert(start >= 0);
993  assert(start < g->knots);
994  assert(g->path_heap != NULL);
995  assert(g->path_state != NULL);
996  assert(pathdist != NULL);
997  assert(pathedge != NULL);
998  assert(cost != NULL);
999 
1000  nnodes = g->knots;
1001 
1002  if( nnodes == 0 )
1003  return;
1004 
1005  heap = g->path_heap;
1006  state = g->path_state;
1007  rootdist = FARAWAY;
1008 
1009  for( i = nnodes - 1; i >= 0; --i )
1010  {
1011  state[i] = UNKNOWN;
1012  pathdist[i] = FARAWAY;
1013  pathedge[i] = -1;
1014  }
1015 
1016  k = start;
1017  pathdist[k] = 0.0;
1018 
1019  if( nnodes > 1 )
1020  {
1021  int root = g->source;
1022 
1023  count = 1;
1024  heap[count] = k;
1025  state[k] = count;
1026 
1027  while( count > 0 )
1028  {
1029  k = nearestX(heap, state, &count, pathdist);
1030 
1031  state[k] = CONNECT;
1032 
1033  if( k == root )
1034  rootdist = pathdist[k];
1035  else if( SCIPisGT(scip, pathdist[k], rootdist) )
1036  break;
1037 
1038  for( i = g->inpbeg[k]; i != EAT_LAST; i = g->ieat[i] )
1039  {
1040  m = g->tail[i];
1041 
1042  if( state[m] && g->mark[m] && SCIPisGT(scip, pathdist[m], (pathdist[k] + cost[i])) )
1043  correctX(heap, state, &count, pathdist, pathedge, m, k, i, cost[i]);
1044  }
1045  }
1046  }
1047 }
1048 
1049 
1050 /** extension heuristic */
1052  SCIP* scip, /**< SCIP data structure */
1053  const GRAPH* g, /**< graph data structure */
1054  int start, /**< start */
1055  STP_Bool* connected, /**< array to mark whether a vertex is part of computed Steiner tree */
1056  SCIP_Real* dist, /**< distances array */
1057  int* pred, /**< predecessor node */
1058  STP_Bool* connected_out, /**< array for internal stuff */
1059  DHEAP* dheap, /**< Dijkstra heap */
1060  SCIP_Bool* success /**< extension successful? */
1061  )
1062 {
1063  int* const state = dheap->position;
1064  const CSR* const csr = g->csr_storage;
1065  const int* const start_csr = csr->start;
1066  const int* const head_csr = csr->head;
1067  const SCIP_Real* const cost_csr = csr->cost;
1068  SCIP_Real outerprofit;
1069  SCIP_Real outermaxprize;
1070  const int nnodes = g->knots;
1071 
1072  assert(csr && g && dist && dheap && pred && connected && connected_out);
1073  assert(graph_pc_isPcMw(g));
1074  assert(!g->extended);
1075  assert(!connected[start]);
1076 
1077  *success = FALSE;
1078  outermaxprize = 0.0;
1079 
1080  for( int k = 0; k < nnodes; k++ )
1081  {
1082  state[k] = UNKNOWN;
1083  dist[k] = FARAWAY;
1084  connected_out[k] = FALSE;
1085 #ifndef NDEBUG
1086  pred[k] = -1;
1087 #endif
1088 
1089  if( !connected[k] && Is_term(g->term[k]) && g->prize[k] > outermaxprize && k != start )
1090  outermaxprize = g->prize[k];
1091  }
1092 
1093  graph_heap_clean(FALSE, dheap);
1094 
1095  dist[start] = 0.0;
1096  graph_heap_correct(start, 0.0, dheap);
1097  connected_out[start] = TRUE;
1098  outerprofit = g->prize[start];
1099 
1100  for( int rounds = 0; rounds < 2 && *success == FALSE; rounds++ )
1101  {
1102  if( rounds == 1 )
1103  {
1104  /* no improvement in last round? */
1105  if( !SCIPisGT(scip, outerprofit, g->prize[start]) )
1106  break;
1107 
1108  if( dheap->size > 0 )
1109  graph_heap_clean(TRUE, dheap);
1110 
1111  assert(dheap->size == 0);
1112 
1113  /* insert outer tree vertices into heap */
1114  for( int k = 0; k < nnodes; k++ )
1115  {
1116  if( connected_out[k] )
1117  {
1118  dist[k] = 0.0;
1119  graph_heap_correct(k, 0.0, dheap);
1120  }
1121  else
1122  dist[k] = FARAWAY;
1123  }
1124  }
1125 
1126  while( dheap->size > 0 )
1127  {
1128  /* get nearest labelled node */
1129  const int k = graph_heap_deleteMinReturnNode(dheap);
1130  const int k_start = start_csr[k];
1131  const int k_end = start_csr[k + 1];
1132  state[k] = UNKNOWN;
1133 
1134  /* if k is positive vertex and close enough, connect k to current subtree */
1135  if( (connected[k] && SCIPisGT(scip, outerprofit, dist[k]))
1136  || (!connected[k] && !connected_out[k] && Is_term(g->term[k]) && SCIPisGE(scip, g->prize[k], dist[k])) )
1137  {
1138  assert(k != start);
1139  assert(pred[k] != -1);
1140  assert(!connected_out[k] || !connected[k]);
1141 
1142  outerprofit += g->prize[k] - dist[k];
1143  connected_out[k] = TRUE;
1144  dist[k] = 0.0;
1145 
1146  assert(SCIPisGE(scip, outerprofit, g->prize[start]) || connected[k]);
1147 
1148  /* connect k to current subtree */
1149  for( int node = pred[k]; !connected_out[node]; node = pred[node] )
1150  {
1151  connected_out[node] = TRUE;
1152  dist[node] = 0.0;
1153  graph_heap_correct(node, 0.0, dheap);
1154 
1155  if( Is_term(g->term[node]) )
1156  outerprofit += g->prize[node];
1157 
1158  assert(state[node]);
1159  assert(pred[node] >= 0);
1160  }
1161 
1162  if( connected[k] )
1163  {
1164  *success = TRUE;
1165  break;
1166  }
1167  }
1168  else if( outerprofit + outermaxprize < dist[k] )
1169  {
1170  assert(*success == FALSE);
1171  break;
1172  }
1173 
1174  /* correct incident nodes */
1175  for( int e = k_start; e < k_end; e++ )
1176  {
1177  const int m = head_csr[e];
1178  const SCIP_Real distnew = dist[k] + cost_csr[e];
1179 
1180  if( distnew < dist[m] )
1181  {
1182  dist[m] = distnew;
1183  pred[m] = k;
1184  graph_heap_correct(m, distnew, dheap);
1185  }
1186  }
1187  }
1188  }
1189 
1190  if( *success )
1191  {
1192  for( int k = 0; k < nnodes; k++ )
1193  if( connected_out[k] )
1194  connected[k] = TRUE;
1195  }
1196 }
1197 
1198 /** Find a directed tree rooted in node 'start' and spanning all terminals */
1200  const GRAPH* g, /**< graph data structure */
1201  const SCIP_Real* cost, /**< edgecosts */
1202  SCIP_Real* pathdist, /**< distance array (on vertices) */
1203  int* pathedge, /**< predecessor edge array (on vertices) */
1204  int start, /**< start vertex */
1205  STP_Bool* connected /**< array to mark whether a vertex is part of computed Steiner tree */
1206  )
1207 {
1208  int count;
1209  int nnodes;
1210  int* heap;
1211  int* state;
1212 
1213  assert(pathdist != NULL);
1214  assert(pathedge != NULL);
1215  assert(g != NULL);
1216  assert(start >= 0);
1217  assert(start < g->knots);
1218  assert(cost != NULL);
1219  assert(connected != NULL);
1220 
1221  count = 0;
1222  nnodes = g->knots;
1223  heap = g->path_heap;
1224  state = g->path_state;
1225 
1226  /* initialize */
1227  for( int k = 0; k < nnodes; k++ )
1228  {
1229  state[k] = UNKNOWN;
1230  pathdist[k] = FARAWAY;
1231  pathedge[k] = -1;
1232  connected[k] = FALSE;
1233  }
1234 
1235  pathdist[start] = 0.0;
1236  connected[start] = TRUE;
1237 
1238  if( nnodes > 1 )
1239  {
1240  int nterms = 0;
1241 
1242  if( Is_term(g->term[start]) )
1243  nterms++;
1244 
1245  /* add start vertex to heap */
1246  count = 1;
1247  heap[count] = start;
1248  state[start] = count;
1249 
1250  /* repeat until heap is empty */
1251  while( count > 0 )
1252  {
1253  /* get closest node */
1254  const int k = nearestX(heap, state, &count, pathdist);
1255  state[k] = UNKNOWN;
1256 
1257  /* k is terminal an not connected yet? */
1258  if( Is_term(g->term[k]) && k != start )
1259  {
1260  assert(pathedge[k] >= 0 && !connected[k]);
1261 
1262  connected[k] = TRUE;
1263  pathdist[k] = 0.0;
1264 
1265  /* connect k to current solution */
1266  for( int node = g->tail[pathedge[k]]; !connected[node]; node = g->tail[pathedge[node]] )
1267  {
1268  assert(pathedge[node] != -1);
1269  assert(!Is_term(g->term[node]));
1270 
1271  connected[node] = TRUE;
1272  resetX(pathdist, heap, state, &count, node, 0.0);
1273  }
1274 
1275  /* have all terminals been reached? */
1276  if( ++nterms == g->terms )
1277  break;
1278  }
1279 
1280  /* update adjacent vertices */
1281  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
1282  {
1283  const int m = g->head[e];
1284 
1285  assert(state[m]);
1286 
1287  /* is m not connected, allowed and closer (as close)? */
1288  if( !connected[m] && pathdist[m] > (pathdist[k] + cost[e]) && g->mark[m] )
1289  correctX(heap, state, &count, pathdist, pathedge, m, k, e, cost[e]);
1290  }
1291  }
1292  }
1293 }
1294 
1295 
1296 
1297 
1298 /** For DCSTP: Find a directed tree rooted in node 'start' and spanning all terminals, while respecting degree constraints */
1300  SCIP* scip, /**< SCIP */
1301  const GRAPH* g, /**< graph data structure */
1302  const SCIP_Real* cost, /**< edgecosts */
1303  SCIP_Real* pathdist, /**< distance array (on vertices) */
1304  int* pathedge, /**< predecessor edge array (on vertices) */
1305  int start, /**< start vertex */
1306  STP_Bool* connected, /**< array to mark whether a vertex is part of computed Steiner tree */
1307  int* result, /**< solution */
1308  STP_Bool* solFound /**< pointer to store whether solution was found */
1309  )
1310 {
1311  const int nedges = graph_get_nEdges(g);
1312  const int nnodes = graph_get_nNodes(g);
1313  int* RESTRICT heap = g->path_heap;
1314  int* RESTRICT state = g->path_state;
1315  int* nodedeg_free;
1316  int* pathdeg_free;
1317 
1318  assert(cost && pathdist && pathedge && connected && result && solFound);
1319  assert(heap && state);
1320  assert(graph_knot_isInRange(g, start));
1321  assert(g->stp_type == STP_DCSTP);
1322  assert(g->maxdeg);
1323 
1324  *solFound = TRUE;
1325 
1326  SCIP_CALL( SCIPallocBufferArray(scip, &nodedeg_free, nnodes) );
1327  SCIP_CALL( SCIPallocBufferArray(scip, &pathdeg_free, nnodes) );
1328 
1329  BMScopyMemoryArray(nodedeg_free, g->maxdeg, nnodes);
1330 
1331  for( int e = 0; e < nedges; e++ )
1332  result[e] = UNKNOWN;
1333 
1334  for( int k = 0; k < nnodes; k++ )
1335  {
1336  pathdeg_free[k] = -1;
1337  state[k] = UNKNOWN;
1338  pathdist[k] = FARAWAY;
1339  pathedge[k] = -1;
1340  connected[k] = FALSE;
1341  }
1342 
1343  pathdist[start] = 0.0;
1344  connected[start] = TRUE;
1345 
1346  if( nnodes > 1 )
1347  {
1348  int heapsize;
1349  int nsolterms = 0;
1350  int nsolterms_old;
1351  int soldegfree;
1352 
1353  if( Is_term(g->term[start]) )
1354  nsolterms++;
1355 
1356 #ifdef SCIP_DEBUG
1357  printf("TM start=%d \n", start);
1358  graph_knot_printInfo(g, start);
1359 #endif
1360 
1361  soldegfree = nodedeg_free[start];
1362 
1363  /* add start vertex to heap */
1364  heapsize = 1;
1365  heap[heapsize] = start;
1366  state[start] = heapsize;
1367  pathdeg_free[start] = 0;
1368 
1369  /* repeat as long as the tree can be extended */
1370  do
1371  {
1372  SCIPdebugMessage("extension loop with nsolterms=%d \n", nsolterms);
1373 
1374 
1375  nsolterms_old = nsolterms;
1376  sdDcExtendTree(g, cost, &heapsize, pathdeg_free, nodedeg_free, pathdist, pathedge, connected, result, &soldegfree, &nsolterms);
1377 
1378  assert(nsolterms <= g->terms);
1379  assert(nsolterms >= nsolterms_old);
1380 
1381  /* will we continue? */
1382  if( nsolterms_old != nsolterms && nsolterms != g->terms && soldegfree > 0 )
1383  {
1384  heapsize = 0;
1385 
1386  for( int k = 0; k < nnodes; k++ )
1387  {
1388  if( connected[k] )
1389  {
1390  heap[++heapsize] = k;
1391  state[k] = heapsize;
1392  assert(pathdeg_free[k] == 0);
1393  }
1394  else
1395  {
1396  pathdeg_free[k] = 0;
1397  state[k] = UNKNOWN;
1398  pathdist[k] = FARAWAY;
1399  pathedge[k] = -1;
1400  }
1401  }
1402 
1403  assert(heapsize > 0);
1404  }
1405 
1406  /* finished? */
1407  if( nsolterms == g->terms )
1408  break;
1409 
1410  } while( nsolterms_old != nsolterms && soldegfree > 0 );
1411 
1412 
1413  *solFound = (g->terms == nsolterms);
1414 
1415  SCIPdebugMessage("g->terms == nterms? %d==%d \n", g->terms, nsolterms);
1416  }
1417 
1418  SCIPfreeBufferArray(scip, &pathdeg_free);
1419  SCIPfreeBufferArray(scip, &nodedeg_free);
1420 
1421  return SCIP_OKAY;
1422 }
1423 
1424 
1425 /** !!!LEGACY CODE!!!
1426  * Find a tree rooted in node 'start' and connecting
1427  * positive vertices as long as this is profitable.
1428  * Note that this function overwrites g->mark.
1429  * */
1431  GRAPH* g, /**< graph data structure */
1432  SCIP_Real* orderedprizes, /**< legacy code */
1433  int* orderedprizes_id, /**< legacy code */
1434  const SCIP_Real* cost, /**< edge costs */
1435  const SCIP_Real* prize, /**< (possibly biased) prize */
1436  SCIP_Bool costIsBiased, /**< is cost biased? */
1437  SCIP_Real* pathdist, /**< distance array (on vertices) */
1438  int* pathedge, /**< predecessor edge array (on vertices) */
1439  int start, /**< start vertex */
1440  STP_Bool* connected /**< array to mark whether a vertex is part of computed Steiner tree */
1441  )
1442 {
1443  const int nnodes = g->knots;
1444  int* const RESTRICT heap = g->path_heap;
1445  int* const RESTRICT state = g->path_state;
1446  int ntermspos = -1;
1447  SPATHSPC spaths_pc = { .orderedprizes = orderedprizes, .orderedprizes_id = orderedprizes_id,
1448  .maxoutprize = -FARAWAY, .maxoutprize_idx = -1};
1449 
1450  assert(g && cost && prize && pathdist && pathedge && connected);
1451  assert(start >= 0);
1452  assert(start < g->knots);
1453  assert(g->extended);
1454  assert(graph_pc_isPcMw(g) && !graph_pc_isRootedPcMw(g));
1455 
1456  /* initialize */
1457  stPcmwInit(g, pathdist, pathedge, connected, &ntermspos);
1458 
1459  assert(g->mark[start]);
1460  assert(ntermspos >= 0);
1461 
1462  pathdist[start] = 0.0;
1463  connected[start] = TRUE;
1464 
1465  if( nnodes > 1 )
1466  {
1467  int count = 1;
1468  int nterms = 0;
1469  const SCIP_Bool isPc = graph_pc_isPc(g);
1470 
1471  shortestpath_pcReset(&spaths_pc);
1472 
1473  if( Is_pseudoTerm(g->term[start]) )
1474  {
1475  nterms++;
1476  shortestpath_pcConnectNode(g, connected, start, &spaths_pc);
1477  }
1478 
1479  /* add start vertex to heap */
1480  heap[count] = start;
1481  state[start] = count;
1482 
1483  /* repeat until heap is empty */
1484  while( count > 0 )
1485  {
1486  SCIP_Bool connectK = FALSE;
1487  const int k = nearestX(heap, state, &count, pathdist);
1488  state[k] = UNKNOWN;
1489 
1490  /* if k is positive vertex and close enough, connect k to current subtree */
1491  if( !connected[k] && Is_pseudoTerm(g->term[k]) )
1492  {
1493  connectK = (prize[k] >= pathdist[k]);
1494 
1495  assert(k != start);
1496 
1497  if( !connectK )
1498  {
1499  SCIP_Real prizesum = 0.0;
1500 
1501  for( int node = g->tail[pathedge[k]]; !connected[node]; node = g->tail[pathedge[node]] )
1502  {
1503  if( Is_pseudoTerm(g->term[node]) )
1504  {
1505  prizesum += prize[node];
1506  }
1507  else if( isPc && !costIsBiased && graph_pc_knotIsNonLeafTerm(g, node) )
1508  {
1509  prizesum += prize[node];
1510  }
1511  }
1512 
1513  assert(prizesum >= 0.0 && LT(prizesum, FARAWAY));
1514 
1515  connectK = (prize[k] + prizesum >= pathdist[k]);
1516  }
1517 
1518  if( connectK )
1519  {
1520  stPcmwConnectNode(k, g, &spaths_pc, pathdist, pathedge, connected, &count, &nterms);
1521 
1522  assert(nterms <= ntermspos);
1523 
1524  /* have all biased terminals been connected? */
1525  if( nterms == ntermspos )
1526  {
1527  SCIPdebugMessage("all terms reached \n");
1528  break;
1529  }
1530  }
1531  }
1532 
1533  if( !connectK && pathdist[k] > spaths_pc.maxoutprize )
1534  {
1535  break;
1536  }
1537 
1538  /* update adjacent vertices */
1539  for( int e = g->outbeg[k]; e >= 0; e = g->oeat[e] )
1540  {
1541  const int m = g->head[e];
1542 
1543  assert(state[m] && e != EAT_LAST);
1544 
1545  /* is m not connected, allowed and closer? */
1546  if( g->mark[m] && !connected[m] && pathdist[m] > (pathdist[k] + cost[e]) )
1547  correctX(heap, state, &count, pathdist, pathedge, m, k, e, cost[e]);
1548  }
1549  } /* while( count > 0 ) */
1550  } /* nnodes > 1*/
1551 }
1552 
1553 /** Reduce given solution
1554  * Note that this function overwrites g->mark.
1555  * */
1557  SCIP* scip, /**< SCIP data structure */
1558  const GRAPH* g, /**< graph data structure */
1559  const SCIP_Real* cost, /**< edge costs */
1560  SCIP_Real* tmpnodeweight, /**< node weight array */
1561  int* result, /**< incoming arc array */
1562  int start, /**< start vertex */
1563  STP_Bool* connected /**< array to mark whether a vertex is part of computed Steiner tree */
1564  )
1565 {
1566  assert(tmpnodeweight != NULL);
1567  assert(result != NULL);
1568  assert(g != NULL);
1569  assert(start >= 0);
1570  assert(start < g->knots);
1571  assert(cost != NULL);
1572  assert(connected != NULL);
1573 
1574  for( int e = g->outbeg[start]; e != EAT_LAST; e = g->oeat[e] )
1575  {
1576  if( result[e] == CONNECT )
1577  {
1578  const int head = g->head[e];
1579 
1580  if( Is_term(g->term[head]) )
1581  continue;
1582 
1583  graph_path_st_pcmw_reduce(scip, g, cost, tmpnodeweight, result, head, connected);
1584 
1585  assert(connected[head]);
1586 
1587  if( SCIPisGE(scip, cost[e], tmpnodeweight[head]) )
1588  {
1589  connected[head] = FALSE;
1590  result[e] = UNKNOWN;
1591  }
1592  else
1593  {
1594  tmpnodeweight[start] += tmpnodeweight[head] - cost[e];
1595  }
1596  }
1597  }
1598 
1599  SCIPfreeBufferArray(scip, &tmpnodeweight);
1600 }
1601 
1602 
1603 
1604 /** Find a tree rooted in node 'start' and connecting
1605  * all positive vertices.
1606  * Note that this function overwrites g->mark.
1607  * */
1609  GRAPH* g, /**< graph data structure */
1610  const SCIP_Real* cost, /**< edge costs */
1611  SCIP_Real* pathdist, /**< distance array (on vertices) */
1612  int* pathedge, /**< predecessor edge array (on vertices) */
1613  int start, /**< start vertex */
1614  STP_Bool* connected /**< array to mark whether a vertex is part of computed Steiner tree */
1615  )
1616 {
1617  int* const heap = g->path_heap;
1618  int* const state = g->path_state;
1619  const int nnodes = g->knots;
1620  const int nterms = graph_pc_isRootedPcMw(g) ? g->terms : g->terms - 1;
1621 
1622  assert(start >= 0 && start < g->knots);
1623  assert(graph_pc_isPcMw(g));
1624  assert(g->extended);
1625 
1626  if( graph_pc_isRootedPcMw(g) )
1627  stRpcmwInit(g, pathdist, pathedge, connected, NULL);
1628  else
1629  stPcmwInit(g, pathdist, pathedge, connected, NULL);
1630 
1631  pathdist[start] = 0.0;
1632  connected[start] = TRUE;
1633 
1634  if( nnodes > 1 )
1635  {
1636  int heapsize = 1;
1637  int termscount = 0;
1638 
1639  /* add start vertex to heap */
1640  heap[heapsize] = start;
1641  state[start] = heapsize;
1642 
1643  if( Is_term(g->term[start]) || Is_pseudoTerm(g->term[start]) )
1644  termscount++;
1645 
1646  /* repeat until heap is empty */
1647  while( heapsize > 0 )
1648  {
1649  /* get closest node */
1650  const int k = nearestX(heap, state, &heapsize, pathdist);
1651  state[k] = UNKNOWN;
1652 
1653  /* if k is unconnected proper terminal, connect its path to current subtree */
1654  if( !connected[k] && (Is_term(g->term[k]) || Is_pseudoTerm(g->term[k])) )
1655  {
1656  connected[k] = TRUE;
1657  pathdist[k] = 0.0;
1658 
1659  assert(k != start);
1660  assert(pathedge[k] != -1);
1661 
1662  for( int node = g->tail[pathedge[k]]; !connected[node]; node = g->tail[pathedge[node]] )
1663  {
1664  connected[node] = TRUE;
1665  resetX(pathdist, heap, state, &heapsize, node, 0.0);
1666 
1667  assert(!Is_term(g->term[node]) && !Is_pseudoTerm(g->term[node]));
1668  assert(pathedge[node] != -1);
1669  }
1670 
1671  /* have all terminals been reached? */
1672  if( ++termscount == nterms )
1673  {
1674  break;
1675  }
1676  }
1677 
1678  /* update adjacent vertices */
1679  for( int e = g->outbeg[k]; e >= 0; e = g->oeat[e] )
1680  {
1681  const int m = g->head[e];
1682 
1683  assert(state[m]);
1684 
1685  /* is m not connected, allowed and closer (as close)? */
1686  if( !connected[m] && g->mark[m] && GT(pathdist[m], (pathdist[k] + cost[e])) )
1687  correctX(heap, state, &heapsize, pathdist, pathedge, m, k, e, cost[e]);
1688  }
1689  }
1690  }
1691 
1692 #ifndef NDEBUG
1693  if( graph_pc_isRootedPcMw(g) )
1694  {
1695  for( int k = 0; k < nnodes; k++ )
1696  {
1697  if( graph_pc_knotIsFixedTerm(g, k) )
1698  assert(connected[k]);
1699  }
1700  }
1701 #endif
1702 }
1703 
1704 
1705 /** greedy extension of a given tree for PC or MW problems */
1707  SCIP* scip, /**< SCIP data structure */
1708  const GRAPH* g, /**< graph data structure */
1709  const SCIP_Real* cost, /**< edge costs */
1710  SCIP_Bool breakearly, /**< finish computation early if no profitable extension possible? */
1711  PATH* path, /**< shortest paths data structure */
1712  STP_Bool* connected, /**< array to mark whether a vertex is part of computed Steiner tree */
1713  SCIP_Bool* extensions /**< extensions performed? */
1714  )
1715 {
1716  SCIP_Real maxprize;
1717  int count;
1718  int nnodes;
1719  int nstnodes;
1720  int outerterms;
1721  int* heap;
1722  int* state;
1723 
1724  assert(path != NULL);
1725  assert(g != NULL);
1726  assert(cost != NULL);
1727  assert(connected != NULL);
1728  assert(g->extended);
1729 
1730  maxprize = 0.0;
1731  count = 0;
1732  nstnodes = 0;
1733  nnodes = g->knots;
1734  heap = g->path_heap;
1735  state = g->path_state;
1736  *extensions = FALSE;
1737  outerterms = 0;
1738 
1739  /* initialize */
1740  for( int k = 0; k < nnodes; k++ )
1741  {
1742  g->mark[k] = ((g->grad[k] > 0) && !Is_term(g->term[k]));
1743  if( connected[k] && g->mark[k] )
1744  {
1745  /* add node to heap */
1746  nstnodes++;
1747  if( nnodes > 1 )
1748  heap[++count] = k;
1749 
1750  state[k] = count;
1751  path[k].dist = 0.0;
1752  assert(path[k].edge != UNKNOWN || k == g->source);
1753  }
1754  else
1755  {
1756  state[k] = UNKNOWN;
1757  path[k].dist = FARAWAY;
1758 
1759  if( Is_pseudoTerm(g->term[k]) && g->mark[k] )
1760  {
1761  outerterms++;
1762  if( g->prize[k] > maxprize )
1763  {
1764  maxprize = g->prize[k];
1765  }
1766  }
1767  }
1768 
1769  if( !connected[k] )
1770  path[k].edge = UNKNOWN;
1771  }
1772 
1773  /* nothing to extend? */
1774  if( nstnodes == 0 )
1775  return;
1776 
1777  if( nnodes > 1 )
1778  {
1779  int nterms = 0;
1780 
1781  /* repeat until heap is empty */
1782  while( count > 0 )
1783  {
1784  /* get closest node */
1785  const int k = pathheapGetNearest(heap, state, &count, path);
1786  state[k] = UNKNOWN;
1787 
1788  /* if k is positive vertex and close enough (or fixnode), connect its path to current subtree */
1789  if( !connected[k] && Is_pseudoTerm(g->term[k]) && SCIPisGE(scip, g->prize[k], path[k].dist) )
1790  {
1791  int node;
1792 
1793  nterms++;
1794  *extensions = TRUE;
1795  connected[k] = TRUE;
1796  path[k].dist = 0.0;
1797 
1798  assert(path[k].edge >= 0);
1799  node = g->tail[path[k].edge];
1800 
1801  while( !connected[node] )
1802  {
1803  assert(path[node].edge != UNKNOWN);
1804  connected[node] = TRUE;
1805  pathheapReset(path, heap, state, &count, node);
1806  assert(state[node]);
1807 
1808  if( Is_pseudoTerm(g->term[node]) )
1809  nterms++;
1810 
1811  node = g->tail[path[node].edge];
1812  }
1813 
1814  assert(path[node].dist == 0.0);
1815  assert(nterms <= outerterms);
1816 
1817  /* have all terminals been reached? */
1818  if( nterms == outerterms )
1819  break;
1820  }
1821  else if( breakearly && SCIPisGT(scip, path[k].dist, maxprize) )
1822  {
1823  break;
1824  }
1825 
1826  /* update adjacent vertices */
1827  for( int e = g->outbeg[k]; e >= 0; e = g->oeat[e] )
1828  {
1829  const int m = g->head[e];
1830 
1831  assert(state[m]);
1832  assert(e != EAT_LAST);
1833 
1834  /* is m not connected, allowed and closer (as close)? */
1835 
1836  if( !connected[m] && path[m].dist > (path[k].dist + cost[e]) && g->mark[m] )
1837  pathheapCorrect(heap, state, &count, path, m, k, e, cost[e], FSP_MODE);
1838  }
1839  }
1840  }
1841 }
1842 
1843 
1844 /** greedy extension of a given tree for PC or MW problems; path[i].edge needs to be initialized */
1846  SCIP* scip, /**< SCIP data structure */
1847  GRAPH* g, /**< graph data structure */
1848  const SCIP_Real* cost, /**< edge costs */
1849  const SCIP_Real* prize, /**< (possibly biased) prize */
1850  PATH* path, /**< shortest paths data structure with .edge initialized */
1851  STP_Bool* connected, /**< array to mark whether a vertex is part of computed Steiner tree */
1852  SCIP_Bool* extensions /**< extensions performed? */
1853  )
1854 {
1855  SCIP_Real maxprize;
1856  int count;
1857  int nstnodes;
1858  int outermscount;
1859  const int nnodes = g->knots;
1860  int* const heap = g->path_heap;
1861  int* const state = g->path_state;
1862 
1863  assert(path != NULL);
1864  assert(g != NULL);
1865  assert(cost != NULL);
1866  assert(connected != NULL);
1867  assert(g->extended);
1868 
1869  maxprize = 0.0;
1870  count = 0;
1871  nstnodes = 0;
1872  outermscount = 0;
1873 
1874  *extensions = FALSE;
1875 
1876  /* unmark dummy terminals */
1878  assert(graph_pc_knotIsFixedTerm(g, g->source));
1879 
1880  /* initialize */
1881  for( int k = 0; k < nnodes; k++ )
1882  {
1883  state[k] = UNKNOWN;
1884  path[k].dist = FARAWAY;
1885 
1886  if( !g->mark[k] )
1887  continue;
1888 
1889  if( connected[k] )
1890  {
1891  /* add node to heap */
1892  nstnodes++;
1893  if( nnodes > 1 )
1894  heap[++count] = k;
1895 
1896  state[k] = count;
1897  path[k].dist = 0.0;
1898  assert(path[k].edge != UNKNOWN || k == g->source);
1899  }
1900  else if( Is_pseudoTerm(g->term[k]) )
1901  {
1902  assert(g->mark[k]);
1903  outermscount++;
1904 
1905  if( prize[k] > maxprize )
1906  maxprize = prize[k];
1907 
1908  }
1909  }
1910 
1911  /* with at least two nodes and at least one in the solution? */
1912  if( nnodes > 1 && nstnodes > 0 )
1913  {
1914  int nterms = 0;
1915 
1916  /* repeat until heap is empty */
1917  while( count > 0 )
1918  {
1919  /* get closest node */
1920  const int k = pathheapGetNearest(heap, state, &count, path);
1921  state[k] = UNKNOWN;
1922 
1923  assert(g->mark[k]);
1924 
1925  /* if k is positive vertex and close enough (or fixnode), connect its path to current subtree */
1926  if( !connected[k] && Is_pseudoTerm(g->term[k]) && SCIPisGE(scip, prize[k], path[k].dist) )
1927  {
1928  int node;
1929 
1930  nterms++;
1931  *extensions = TRUE;
1932  connected[k] = TRUE;
1933  path[k].dist = 0.0;
1934 
1935  assert(path[k].edge >= 0);
1936  node = g->tail[path[k].edge];
1937 
1938  while( !connected[node] )
1939  {
1940  assert(g->mark[node]);
1941  assert(path[node].edge >= 0);
1942  connected[node] = TRUE;
1943  pathheapReset(path, heap, state, &count, node);
1944  assert(state[node]);
1945 
1946  if( Is_pseudoTerm(g->term[node]) )
1947  nterms++;
1948 
1949  node = g->tail[path[node].edge];
1950  }
1951 
1952  assert(path[k].dist == 0.0);
1953 
1954  assert(nterms <= outermscount);
1955 
1956  /* have all terminals been reached? */
1957  if( nterms == outermscount )
1958  break;
1959  }
1960  else if( path[k].dist > maxprize )
1961  {
1962  break;
1963  }
1964 
1965  /* update adjacent vertices */
1966  for( int e = g->outbeg[k]; e >= 0; e = g->oeat[e] )
1967  {
1968  const int m = g->head[e];
1969  assert(state[m]);
1970 
1971  if( connected[m] )
1972  continue;
1973 
1974  /* is m allowed and closer? */
1975  if( path[m].dist > (path[k].dist + cost[e]) && g->mark[m] )
1976  pathheapCorrect(heap, state, &count, path, m, k, e, cost[e], FSP_MODE);
1977  }
1978  }
1979  }
1980 }
1981 
1982 
1983 /** !!!LEGACY CODE!!!
1984  * Shortest path heuristic for the RMWCSP and RPCSPG
1985  * Find a directed tree rooted in node 'start' and connecting all terminals as well as all
1986  * positive vertices (as long as this is profitable).
1987  * */
1989  GRAPH* g, /**< graph data structure */
1990  SCIP_Real* orderedprizes, /**< legacy code */
1991  int* orderedprizes_id, /**< legacy code */
1992  const SCIP_Real* cost, /**< edge costs */
1993  const SCIP_Real* prize, /**< (possibly biased) prize */
1994  SCIP_Real* pathdist, /**< distance array (on vertices) */
1995  int* pathedge, /**< predecessor edge array (on vertices) */
1996  int start, /**< start vertex */
1997  STP_Bool* connected /**< array to mark whether a vertex is part of computed Steiner tree */
1998  )
1999 {
2000  const int nnodes = g->knots;
2001  int nrterms = -1;
2002  int* const heap = g->path_heap;
2003  int* const state = g->path_state;
2004  SPATHSPC spaths_pc = { .orderedprizes = orderedprizes, .orderedprizes_id = orderedprizes_id,
2005  .maxoutprize = -FARAWAY, .maxoutprize_idx = -1};
2006 
2007  assert(g && cost && prize && pathdist && pathedge && connected);
2008  assert(start >= 0);
2009  assert(start < g->knots);
2010  assert(g->extended);
2011  assert(graph_pc_isRootedPcMw(g));
2012 
2013  stRpcmwInit(g, pathdist, pathedge, connected, &nrterms);
2014 
2015  assert(nrterms >= 1);
2016  pathdist[start] = 0.0;
2017  connected[start] = TRUE;
2018 
2019  if( nnodes > 1 )
2020  {
2021  int count;
2022  const int nterms = g->terms;
2023  int termscount = 0;
2024  int rtermscount = 0;
2025 
2026  shortestpath_pcReset(&spaths_pc);
2027 
2028  /* add start vertex to heap */
2029  count = 1;
2030  heap[count] = start;
2031  state[start] = count;
2032 
2033  if( Is_anyTerm(g->term[start]) )
2034  {
2035  shortestpath_pcConnectNode(g, connected, start, &spaths_pc);
2036 
2037  termscount++;
2038  }
2039 
2040  if( Is_term(g->term[start]) )
2041  {
2042  assert(graph_pc_knotIsFixedTerm(g, start));
2043  rtermscount++;
2044  }
2045 
2046  /* repeat until heap is empty */
2047  while( count > 0 )
2048  {
2049  /* get closest node */
2050  const int k = nearestX(heap, state, &count, pathdist);
2051  state[k] = UNKNOWN;
2052 
2053  /* if k is fixed terminal positive vertex and close enough, connect its path to current subtree */
2054  if( Is_anyTerm(g->term[k]) && (Is_term(g->term[k]) || GE(prize[k], pathdist[k]))
2055  && !connected[k] )
2056  {
2057  int node;
2058 
2059  assert(k != start);
2060  assert(pathedge[k] != -1);
2061  assert(!graph_pc_knotIsDummyTerm(g, k));
2062  assert(graph_pc_knotIsFixedTerm(g, k) || GE(prize[k], pathdist[k]));
2063 
2064  if( !graph_pc_knotIsNonLeafTerm(g, k) )
2065  termscount++;
2066 
2067  if( Is_term(g->term[k]) )
2068  {
2069  assert(graph_pc_knotIsFixedTerm(g, k));
2070  rtermscount++;
2071  }
2072  else if( Is_pseudoTerm(g->term[k]) )
2073  {
2074  shortestpath_pcConnectNode(g, connected, k, &spaths_pc);
2075  }
2076 
2077  connected[k] = TRUE;
2078  pathdist[k] = 0.0;
2079 
2080  node = k;
2081 
2082  while( !connected[node = g->tail[pathedge[node]]] )
2083  {
2084  assert(pathedge[node] != -1);
2085  assert(!Is_term(g->term[node]));
2086  assert(!graph_pc_knotIsFixedTerm(g, node));
2087  assert(g->mark[node]);
2088 
2089  connected[node] = TRUE;
2090  resetX(pathdist, heap, state, &count, node, 0.0);
2091 
2092  if( Is_pseudoTerm(g->term[node]) )
2093  {
2094  termscount++;
2095  shortestpath_pcConnectNode(g, connected, node, &spaths_pc);
2096  }
2097  }
2098 
2099  assert(termscount <= nterms);
2100 
2101  /* have all terminals been reached? */
2102  if( termscount == nterms )
2103  {
2104  SCIPdebugMessage("all terminals reached \n");
2105  break;
2106  }
2107  }
2108  else if( rtermscount >= nrterms && pathdist[k] > spaths_pc.maxoutprize )
2109  {
2110  SCIPdebugMessage("all fixed terminals reached \n");
2111 
2112  assert(rtermscount == nrterms);
2113  break;
2114  }
2115 
2116  /* update adjacent vertices */
2117  for( int e = g->outbeg[k]; e >= 0; e = g->oeat[e] )
2118  {
2119  const int head = g->head[e];
2120 
2121  assert(state[head]);
2122 
2123  /* is m not connected, allowed and closer (as close)? */
2124  if( !connected[head] && g->mark[head] && pathdist[head] > (pathdist[k] + cost[e]) )
2125  correctX(heap, state, &count, pathdist, pathedge, head, k, e, cost[e]);
2126  }
2127  }
2128  }
2129 
2130 #ifndef NDEBUG
2131  for( int k = 0; k < nnodes; k++ )
2132  {
2133  if( graph_pc_knotIsFixedTerm(g, k) )
2134  {
2135  assert(connected[k]);
2136  }
2137  }
2138 #endif
2139 }
2140 
2141 
2142 
2143 /**
2144  * todo refactor, was copied from Henriette's branch
2145  */
2147  SCIP* scip, /**< SCIP data structure */
2148  GRAPH* g, /**< graph data structure */
2149  const SCIP_Real* prize, /**< (possibly biased) prize */
2150  SCIP_Real* pathdist, /**< distance array (on vertices) */
2151  int* pathedge, /**< predecessor edge array (on vertices) */
2152  int start, /**< start vertex */
2153  STP_Bool* connected, /**< array to mark whether a vertex is part of computed Steiner tree */
2154  SCIP_Bool* solfound /**< could a solution be found? */
2155  )
2156 {
2157 
2158  /* node utilities */
2159  const SCIP_Real* nodeweight = prize;
2160  /* node costs */
2161  const SCIP_Real* nodebudget = g->costbudget;
2162  /* given budget */
2163  const SCIP_Real budget = g->budget;
2164  /* number of nodes */
2165  const int nnodes = g->knots;
2166 
2167  /* number of terminals which are not part of the solution yet */
2168  int numberTerminals;
2169  /* current available budget */
2170  SCIP_Real newBudget;
2171  /* positive sum of all negative utilities */
2172  double smallestWeight;
2173  /* alpha (in [0,1]) is used by the key of the heap */
2174  double alpha;
2175 
2176  /* upper bound for node costs (pi) and the corresponding node utilities (my) */
2177  double* pi;
2178  double* my;
2179 
2180  int lookNeighbour;
2181 
2182  int* alreadyContained;
2183 
2184  // printf("\n\n start = %d \n", start+1);
2185 
2186  *solfound = TRUE;
2187 
2189 
2190  assert( pathdist != NULL );
2191  assert( pathedge != NULL );
2192  assert( g != NULL );
2193  assert( start >= 0 );
2194  assert( start < g->knots );
2195  assert( prize != NULL );
2196  assert( connected != NULL );
2197  assert( g->mark[start] );
2198  assert( Is_term( g->term[start] ) );
2199 
2200  SCIP_CALL( SCIPallocBufferArray( scip, &alreadyContained, nnodes ) );
2201  SCIP_CALL( SCIPallocBufferArray( scip, &my, nnodes ) );
2202  SCIP_CALL( SCIPallocBufferArray( scip, &pi, nnodes ) );
2203 
2204  numberTerminals = g->terms;
2205  newBudget = budget - nodebudget[start];
2206  smallestWeight = 1.0;
2207 
2208  for( int k = 0; k < nnodes; k++ )
2209  {
2210  /* node costs have to be positive */
2211  if( (nodebudget[k] < 0.0) && g->mark[k] )
2212  {
2213  printf("all costs have to be non-negativ! \n");
2214  SCIPfreeBufferArray(scip, &pi);
2215  SCIPfreeBufferArray(scip, &my);
2216  SCIPfreeBufferArray(scip, &alreadyContained);
2217  return SCIP_ERROR;
2218  }
2219 
2220  if( (nodeweight[k] < 0) && g->mark[k] )
2221  smallestWeight = smallestWeight + ((-1.0) * nodeweight[k]);
2222  }
2223 
2224  /* add start vertex to the solution */
2225  connected[start] = TRUE;
2226 
2227  /* at the beginning set alpha equal one */
2228  alpha = 1.0;
2229 
2230  /* first find a solution containing all terminals
2231  * second expand the solution by adding additional nodes until no further budget is available */
2232  while( ( (alpha >= 0.0) && (numberTerminals > 0) ) || ( (alpha >= 0.0) && (newBudget >= 0.0) ) )
2233  {
2234 
2235  /* construct a heap */
2236  int* heap = g->path_heap;
2237  int* state = g->path_state;
2238  int count = 0;
2239 
2240  /* calculate number of terminals again if alpha + 0.1 does not work for the key
2241  * and no feasible solution is found yet */
2242  if( numberTerminals > 0 )
2243  numberTerminals = g->terms;
2244 
2245  /* initialize heap and define node start as start solution
2246  * if no feasible solution is found yet */
2247  for( int k = 0; k < nnodes; k++ )
2248  {
2249  if( (k != start) && (numberTerminals > 0) )
2250  connected[k] = FALSE;
2251 
2252  alreadyContained[k] = FALSE;
2253 
2254  if( !g->mark[k] && (numberTerminals > 0) )
2255  numberTerminals--;
2256 
2257  state[k] = UNKNOWN;
2258  pathedge[k] = -1;
2259 
2260  if( connected[k] && (numberTerminals <= 0) )
2261  {
2262  pathdist[k] = 0.0;
2263  }else
2264  {
2265  pathdist[k] = FARAWAY;
2266  }
2267  }
2268 
2269  /* reduce number of searched terminals if start is a terminal and
2270  * no feasible solution is found yet */
2271  if( g->mark[start] && Is_term( g->term[start] ) && (numberTerminals > 0) )
2272  numberTerminals--;
2273 
2274  /* initialize pi and my and add nodes contained by the solution to the heap;
2275  * if a feasible solution is already found, then add all nodes to the heap */
2276  for( int k = 0; k < nnodes; k++ )
2277  {
2278  if( g->mark[k] )
2279  {
2280  if( connected[k] )
2281  {
2282  pi[k] = 0.0;
2283  my[k] = 0.0;
2284 
2285  resetX(pathdist, heap, state, &count, k, 0.0 );
2286  }else
2287  {
2288  if( Is_term( g->term[k] ) && (numberTerminals > 0) ){
2289  my[k] = 0.0;
2290  }else
2291  {
2292  my[k] = nodeweight[k];
2293  }
2294  pi[k] = DBL_MAX;
2295  if( numberTerminals <= 0 ){
2296  resetX(pathdist, heap, state, &count, k, pathdist[k] );
2297  }
2298  }
2299  }
2300  }
2301 
2302  /* return if the heap is empty */
2303  if( count == 0 )
2304  {
2305  SCIPfreeBufferArray( scip, &pi );
2306  SCIPfreeBufferArray( scip, &my );
2307  SCIPfreeBufferArray( scip, &alreadyContained );
2308  return SCIP_OKAY;
2309  }
2310 
2311  /* TRUE if we want to consider the neighbor nodes of node k */
2312  lookNeighbour = TRUE;
2313 
2314  /* repeat until the heap is empty */
2315  while( count > 0 )
2316  {
2317  /* get first node */
2318  int k = nearestX( heap, state, &count, pathdist );
2319  alreadyContained[k] = TRUE;
2320 
2321  /* TRUE if we want to consider the neighbor nodes of node k */
2322  lookNeighbour = TRUE;
2323 
2324  /*if( numberTerminals <= 0 )
2325  state[k] = UNKNOWN;*/
2326 
2327  /* if k is a terminal node that is not contained in the current solution,
2328  * add k and its path to the solution */
2329  if( ( numberTerminals > 0 ) && !connected[k] && Is_term( g->term[k] ) && g->mark[k] )
2330  { //numberTerminals>0 braucht man nicht eigentlich
2331 
2332  lookNeighbour = FALSE;
2333 
2334  /* if the costs of the path are greater than the current budget,
2335  * then no feasible solution exists for alpha, decrease alpha by 0.1 */
2336  if( ( newBudget - pi[k] ) < 0.0 )
2337  {
2338  alpha = alpha - 0.1;
2339  count = 0;
2340 
2341  /* if alpha smaller than zero, no feasible solution could be found */
2342  if( alpha < 0.0 )
2343  {
2344  // printf("No feasible solution found! \n" );
2345 
2346  *solfound = FALSE;
2347 
2348  SCIPfreeBufferArray( scip, &pi );
2349  SCIPfreeBufferArray( scip, &my );
2350  SCIPfreeBufferArray( scip, &alreadyContained );
2351 
2352  return SCIP_OKAY;
2353  }
2354  /* otherwise, add k and its path to the solution and update the current budget */
2355  }else
2356  {
2357  int v = k;
2358 
2359  newBudget = newBudget - pi[k];
2360 
2361  while( !connected[v] )
2362  {
2363  connected[v] = TRUE;
2364  pi[v] = 0.0;
2365  my[v] = 0.0;
2366  if( pathedge[v] != -1 )
2367  v = g->tail[pathedge[v]];
2368  }
2369 
2370 
2371  /* update the number of terminals */
2372  numberTerminals = numberTerminals - 1;
2373 
2374  /* neu */
2375  heap = g->path_heap;
2376  state = g->path_state;
2377  count = 0;
2378 
2379  /* initialize heap and define node start as start solution
2380  * if no feasible solution is found yet */
2381  for( int n = 0; n < nnodes; n++ )
2382  {
2383  state[n] = UNKNOWN;
2384  pathedge[n] = -1;
2385  alreadyContained[n] = FALSE;
2386 
2387  if( connected[n] )
2388  {
2389  pathdist[n] = 0.0;
2390  resetX(pathdist, heap, state, &count, n, 0.0);
2391  }
2392  else
2393  {
2394  pathdist[n] = FARAWAY;
2395  if( Is_term(g->term[n]) )
2396  {
2397  my[n] = 0.0;
2398  }
2399  else
2400  {
2401  my[n] = nodeweight[n];
2402  }
2403  pi[n] = DBL_MAX;
2404  }
2405  } /* bis hier ist der heap jetzt leer? */
2406 
2407  /* break the while-loop if all terminals are contained in the solution */
2408  if( numberTerminals == 0 )
2409  count = 0;
2410  }
2411  }
2412  /* iterate over incident edges */
2413  for( int e = g->outbeg[k]; lookNeighbour && e != EAT_LAST; e = g->oeat[e] )
2414  {
2415  /* get neighbor head of node k */
2416  const int head = g->head[e];
2417  assert( state[head] );
2418 
2419  /* calculate new key value for head if neighbor head is not contained in the solution
2420  * and no feasible solution is found yet or neighbor head is still part of the heap
2421  */
2422  //if( g->mark[head] && !connected[head] && ( ( numberTerminals > 0 ) || ( state[head] != UNKNOWN ) ) )
2423 //if( g->mark[head] && !connected[head] && ( ( numberTerminals > 0 ) || !alreadyContained[head] ) )
2424  if( g->mark[head] && !connected[head] && ( ( numberTerminals > 0 && pathedge[head]==-1 ) || !alreadyContained[head] ) )
2425  {
2426  int j = k;
2427  int isConnected = TRUE;
2428 
2429  double possibleUtility;
2430  if( Is_term( g->term[head] ) && (numberTerminals > 0) )
2431  {
2432  if( my[k] >= 0.0 )
2433  {
2434  possibleUtility = ( 1.0 - alpha ) * ( pi[k] + nodebudget[head] ) + ( alpha * ( pi[k] + nodebudget[head] ) /( my[k] + 1.0 ) );
2435  }else
2436  {
2437  possibleUtility = ( 1.0 - alpha ) * ( pi[k] + nodebudget[head] ) + ( alpha * ( pi[k] + nodebudget[head] ) / ( ( my[k] + smallestWeight ) / smallestWeight ) );
2438  }
2439  }else
2440  {
2441  if( ( my[k] + nodeweight[head] ) >= 0.0 )
2442  {
2443  possibleUtility = ( 1.0 - alpha ) * ( pi[k] + nodebudget[head] )
2444  + ( alpha * ( pi[k] + nodebudget[head] ) / ( my[k] + nodeweight[head] + 1.0 ) );
2445  }else
2446  {
2447  possibleUtility = ( 1.0 - alpha ) * ( pi[k] + nodebudget[head] )
2448  + ( alpha * ( pi[k] + nodebudget[head] ) / ( ( my[k] + nodeweight[head] + smallestWeight ) / smallestWeight ) );
2449  }
2450  }
2451 
2452  while( !connected[j] && isConnected && ( pathedge[j] != -1 ) )
2453  {
2454  if( j == head )
2455  isConnected = FALSE;
2456 
2457  if( pathedge[j] != -1 )
2458  j = g->tail[pathedge[j]];
2459  }
2460 
2461  /* if this the new key value is smaller than the current key value,
2462  * then update the pu, my, and the heap */
2463  if( ( pathdist[head] > possibleUtility ) && isConnected )
2464  {
2465  pi[head] = pi[k] + nodebudget[head];
2466 
2467 
2468 
2469  if( Is_term(g->term[head] ) )
2470  {
2471  my[head] = my[k];
2472  }else
2473  {
2474  my[head] = my[k] + nodeweight[head];
2475  }
2476  correctX( heap, state, &count, pathdist, pathedge, head, k, e, (-1.0) * pathdist[k] + possibleUtility );
2477  }
2478  }
2479  }
2480  }
2481  /* if a feasible solution is already found, then expand the solution by a suitable node and its path
2482  * If such a node cannot be found, then decrease alpha by 0.1 */
2483  if( numberTerminals <= 0 && lookNeighbour ) //lookNeighbor neu
2484  {
2485  int foundVertex = FALSE;
2486 
2487  /* add all nodes to the heap which are not contained in the solution */
2488  for( int n = 0; n < nnodes; n++ )
2489  {
2490  if( !connected[n] && g->mark[n] )
2491  resetX(pathdist, heap, state, &count, n, pathdist[n]);
2492  }
2493  /* find a suitable node */
2494 
2495  while( count > 0 && !foundVertex )
2496  {
2497  /* get first node n from the heap */
2498  int n = nearestX( heap, state, &count, pathdist );
2499 
2500  /* if the cost of node n are smaller than the current budget,
2501  * then add the node n and its path to the solution and update the
2502  * available budget */
2503  if( g->mark[n] && ( newBudget - pi[n] >= 0.0 ) && ( my[n] > 0.0 ) )
2504  {
2505  int v = n;
2506 
2507 //printf("budget=%f\n", newBudget);
2508  //printf("pi[%d]=%f\n",n, pi[n]);
2509  newBudget = newBudget - pi[n];
2510  foundVertex = TRUE;
2511 
2512  while( !connected[v] )
2513  {
2514 //printf("nodebudget[%d]=%f \n", v, nodebudget[v]);
2515  connected[v] = TRUE;
2516  if( pathedge[v] != -1 )
2517  v = g->tail[ pathedge[v] ];
2518  }
2519  }
2520  }
2521  /* decrease alpha by 0.1 if such a node cannot be found */
2522  if( !foundVertex )
2523  alpha = alpha - 0.1;
2524  }
2525  }
2526  SCIPfreeBufferArray( scip, &pi );
2527  SCIPfreeBufferArray( scip, &my );
2528  SCIPfreeBufferArray( scip, &alreadyContained );
2529 
2530  return SCIP_OKAY;
2531 }
int graph_get_nEdges(const GRAPH *)
Definition: graph_stats.c:548
static volatile int nterms
Definition: interrupt.c:38
int * visitlist
Definition: graphdefs.h:314
SCIP_Bool graph_pc_isMw(const GRAPH *)
int *RESTRICT head
Definition: graphdefs.h:224
int * head
Definition: graphdefs.h:141
int source
Definition: graphdefs.h:195
#define FSP_MODE
Definition: graphdefs.h:99
SCIP_Bool graph_pc_isRootedPcMw(const GRAPH *)
#define SCIPfreeMemoryArrayNull(scip, ptr)
Definition: scip_mem.h:72
#define Is_term(a)
Definition: graphdefs.h:102
signed int edge
Definition: graphdefs.h:287
Shortest path based algorithms for Steiner problems.
int terms
Definition: graphdefs.h:192
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip_mem.h:55
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
includes methods for Steiner tree problem solutions
int *RESTRICT maxdeg
Definition: graphdefs.h:206
void graph_knot_printInfo(const GRAPH *, int)
Definition: graph_stats.c:151
SCIP_RETCODE graph_path_init(SCIP *scip, GRAPH *g)
Definition: graph_path.c:480
#define FALSE
Definition: def.h:87
void graph_path_exec(SCIP *scip, const GRAPH *g, int mode, int start, const SCIP_Real *cost, PATH *path)
Definition: graph_path.c:541
int *RESTRICT inpbeg
Definition: graphdefs.h:202
SCIP_Real * cost
Definition: graphdefs.h:142
int *RESTRICT path_state
Definition: graphdefs.h:256
#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
#define STP_DCSTP
Definition: graphdefs.h:47
#define EAT_LAST
Definition: graphdefs.h:58
#define SCIPdebugMessage
Definition: pub_message.h:87
#define FARAWAY
Definition: graphdefs.h:89
static int nearestX(int *RESTRICT heap, int *RESTRICT state, int *RESTRICT count, const SCIP_Real *pathdist)
Definition: graphheaps.h:41
SCIP_Real * costbudget
Definition: graphdefs.h:211
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
int * start
Definition: graphdefs.h:140
static void correctX(int *RESTRICT heap, int *RESTRICT state, int *RESTRICT count, SCIP_Real *RESTRICT pathdist, int *RESTRICT pathedge, int l, int k, int e, SCIP_Real cost)
Definition: graphheaps.h:85
SCIP_Real * node_distance
Definition: graphdefs.h:316
CSR * csr_storage
Definition: graphdefs.h:270
void graph_path_execX(SCIP *scip, const GRAPH *g, int start, const SCIP_Real *cost, SCIP_Real *pathdist, int *pathedge)
Definition: graph_path.c:905
static void stPcmwConnectNode(int k, const GRAPH *g, SPATHSPC *spaths_pc, SCIP_Real *pathdist, int *pathedge, STP_Bool *connected, int *count, int *nterms)
Definition: graph_path.c:170
int *RESTRICT mark
Definition: graphdefs.h:198
int * position
Definition: graphdefs.h:305
int *RESTRICT oeat
Definition: graphdefs.h:231
#define GE(a, b)
Definition: portab.h:85
void graph_path_st_pcmw_extendOut(SCIP *scip, const GRAPH *g, int start, STP_Bool *connected, SCIP_Real *dist, int *pred, STP_Bool *connected_out, DHEAP *dheap, SCIP_Bool *success)
Definition: graph_path.c:1051
SCIP_Bool extended
Definition: graphdefs.h:267
int stp_type
Definition: graphdefs.h:264
static void stRpcmwInit(GRAPH *g, SCIP_Real *pathdist, int *pathedge, STP_Bool *connected, int *nrealterms)
Definition: graph_path.c:240
void graph_path_st_pcmw_reduce(SCIP *scip, const GRAPH *g, const SCIP_Real *cost, SCIP_Real *tmpnodeweight, int *result, int start, STP_Bool *connected)
Definition: graph_path.c:1556
DHEAP * dheap
Definition: graphdefs.h:315
SCIP_Real budget
Definition: graphdefs.h:212
void shortestpath_pcReset(SPATHSPC *sppc)
Definition: shortestpath.c:977
SCIP_Bool graph_path_exists(const GRAPH *g)
Definition: graph_path.c:497
static int pathheapGetNearest(int *RESTRICT heap, int *RESTRICT state, int *RESTRICT count, const PATH *path)
Definition: graph_path.c:91
void graph_path_exit(SCIP *scip, GRAPH *g)
Definition: graph_path.c:515
SCIP_Real * prize
Definition: graphdefs.h:210
SCIP_Real dist
Definition: graphdefs.h:286
int *RESTRICT grad
Definition: graphdefs.h:201
#define NULL
Definition: lpi_spx1.cpp:155
#define EQ(a, b)
Definition: portab.h:79
int knots
Definition: graphdefs.h:190
#define SCIP_CALL(x)
Definition: def.h:384
static void stPcmwInit(GRAPH *g, SCIP_Real *pathdist, int *pathedge, STP_Bool *connected, int *npseudoterms)
Definition: graph_path.c:209
#define MST_MODE
Definition: graphdefs.h:98
#define LT(a, b)
Definition: portab.h:81
SCIP_RETCODE graph_path_st_dc(SCIP *scip, const GRAPH *g, const SCIP_Real *cost, SCIP_Real *pathdist, int *pathedge, int start, STP_Bool *connected, int *result, STP_Bool *solFound)
Definition: graph_path.c:1299
unsigned char STP_Bool
Definition: portab.h:34
void graph_path_st_pcmw_extendBiased(SCIP *scip, GRAPH *g, const SCIP_Real *cost, const SCIP_Real *prize, PATH *path, STP_Bool *connected, SCIP_Bool *extensions)
Definition: graph_path.c:1845
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
#define GT(a, b)
Definition: portab.h:84
#define SCIP_Bool
Definition: def.h:84
int *RESTRICT ieat
Definition: graphdefs.h:230
int *RESTRICT path_heap
Definition: graphdefs.h:255
int *RESTRICT tail
Definition: graphdefs.h:223
int *RESTRICT term
Definition: graphdefs.h:196
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:127
void graph_pc_markOrgGraph(GRAPH *)
static void sdDcExtendTree(const GRAPH *g, const SCIP_Real *cost, int *heapsize, int *pathdeg_free, int *nodedeg_free, SCIP_Real *pathdist, int *pathedge, STP_Bool *connected, int *result, int *soldegfree, int *nsolterms)
Definition: graph_path.c:327
SCIP_Bool graph_pc_knotIsNonLeafTerm(const GRAPH *, int)
SCIP_Bool graph_pc_isPc(const GRAPH *)
#define CONNECT
Definition: graphdefs.h:87
Portable definitions.
SCIP_Bool graph_typeIsUndirected(const GRAPH *)
Definition: graph_stats.c:69
void graph_path_st_pcmw_extend(SCIP *scip, const GRAPH *g, const SCIP_Real *cost, SCIP_Bool breakearly, PATH *path, STP_Bool *connected, SCIP_Bool *extensions)
Definition: graph_path.c:1706
static SCIP_Bool stDcTermIsConnectable(const GRAPH *g, int term, const int *deg_free, const int *pathedge, const STP_Bool *connected)
Definition: graph_path.c:278
#define Is_pseudoTerm(a)
Definition: graphdefs.h:103
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool graph_pc_knotIsDummyTerm(const GRAPH *, int)
SCIP_Bool graph_pc_knotIsFixedTerm(const GRAPH *, int)
void graph_path_st_rpcmw(GRAPH *g, SCIP_Real *orderedprizes, int *orderedprizes_id, const SCIP_Real *cost, const SCIP_Real *prize, SCIP_Real *pathdist, int *pathedge, int start, STP_Bool *connected)
Definition: graph_path.c:1988
void graph_path_PcMwSd(SCIP *scip, const GRAPH *g, PATH *path, SCIP_Real *cost, SCIP_Real distlimit, int *pathmaxnode, int *heap, int *state, int *stateblock, int *memlbl, int *nlbl, int tail, int head, int limit)
Definition: graph_path.c:788
SCIP_Bool graph_pc_isPcMw(const GRAPH *)
#define SCIP_Real
Definition: def.h:177
int graph_heap_deleteMinReturnNode(DHEAP *)
Definition: graph_util.c:1076
int *RESTRICT outbeg
Definition: graphdefs.h:204
void graph_path_st_pcmw_full(GRAPH *g, const SCIP_Real *cost, SCIP_Real *pathdist, int *pathedge, int start, STP_Bool *connected)
Definition: graph_path.c:1608
STP_Bool * node_visited
Definition: graphdefs.h:317
void graph_path_st_pcmw(GRAPH *g, SCIP_Real *orderedprizes, int *orderedprizes_id, const SCIP_Real *cost, const SCIP_Real *prize, SCIP_Bool costIsBiased, SCIP_Real *pathdist, int *pathedge, int start, STP_Bool *connected)
Definition: graph_path.c:1430
void graph_sdPaths(const GRAPH *g, PATH *path, const SCIP_Real *cost, SCIP_Real distlimit, int *heap, int *state, int *memlbl, int *nlbl, int tail, int head, int limit)
Definition: graph_path.c:684
int graph_get_nNodes(const GRAPH *)
Definition: graph_stats.c:536
void shortestpath_pcConnectNode(const GRAPH *g, const STP_Bool *connected, int node_connected, SPATHSPC *sppc)
Definition: shortestpath.c:991
SCIP_Bool graph_knot_isInRange(const GRAPH *, int)
Definition: graph_node.c:52
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define UNKNOWN
Definition: sepa_mcf.c:4095
static void pathheapCorrect(int *RESTRICT heap, int *RESTRICT state, int *RESTRICT count, PATH *RESTRICT path, int l, int k, int edge, SCIP_Real cost, int mode)
Definition: graph_path.c:50
#define nnodes
Definition: gastrans.c:65
includes (inline) graph heap methods used for Steiner tree problems
void graph_pathInLimitedExec(const GRAPH *g, const SCIP_Real *edges_cost, const SCIP_Bool *nodes_abort, int startnode, DIJK *dijkdata, SCIP_Real *abortdistance)
Definition: graph_path.c:610
static void resetX(SCIP_Real *RESTRICT pathdist, int *RESTRICT heap, int *RESTRICT state, int *RESTRICT count, int node, SCIP_Real distnew)
Definition: graphheaps.h:132
#define Is_anyTerm(a)
Definition: graphdefs.h:105
void graph_path_invroot(SCIP *scip, const GRAPH *g, int start, const SCIP_Real *cost, SCIP_Real *pathdist, int *pathedge)
Definition: graph_path.c:973
void graph_pathHeapAdd(const PATH *path, int node, int *RESTRICT heap, int *RESTRICT state, int *count)
Definition: graph_path.c:442
SCIP_RETCODE graph_path_st_brmwcs(SCIP *scip, GRAPH *g, const SCIP_Real *prize, SCIP_Real *pathdist, int *pathedge, int start, STP_Bool *connected, SCIP_Bool *solfound)
Definition: graph_path.c:2146
#define STP_MWCSP
Definition: graphdefs.h:51
void graph_path_st(const GRAPH *g, const SCIP_Real *cost, SCIP_Real *pathdist, int *pathedge, int start, STP_Bool *connected)
Definition: graph_path.c:1199
void graph_heap_correct(int, SCIP_Real, DHEAP *)
Definition: graph_util.c:1166
static void pathheapReset(PATH *RESTRICT path, int *RESTRICT heap, int *RESTRICT state, int *RESTRICT count, int node)
Definition: graph_path.c:134