Scippy

SCIP

Solving Constraint Integer Programs

reduce_alt.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 scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file reduce_alt.c
17  * @brief Altenative-based reduction tests for Steiner problems
18  * @author Daniel Rehfeldt
19  *
20  * This file implements alternative-based reduction techniques for several Steiner problems.
21  * Most tests can be found in "Combining NP-Hard Reduction Techniques and Strong Heuristics in an Exact Algorithm for the
22  * Maximum-Weight Connected Subgraph Problem" by Daniel Rehfeldt and Thorsten Koch,
23  * or in "Reduction Techniques for the Prize-Collecting Steiner Tree Problem and the Maximum-Weight Connected Subgraph Problem"
24  * by Daniel Rehfeldt et al.
25  * Note that special distance tests as well as extending (alternative) reduction techniques can
26  * be found in separate files.
27  *
28  * A list of all interface methods can be found in reduce.h.
29  *
30  */
31 
32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33 
34 //#define SCIP_DEBUG
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <assert.h>
40 #include "graph.h"
41 #include "reduce.h"
42 #include "misc_stp.h"
43 #include "probdata_stp.h"
44 #include "scip/scip.h"
45 #include "portab.h"
46 
47 
48 #define VERTEX_CONNECT 0
49 #define VERTEX_TEMPNEIGHBOR 1
50 #define VERTEX_NEIGHBOR 2
51 #define VERTEX_OTHER 3
52 #define STP_RED_CNSNN 25
53 #define STP_RED_ANSMAXCANDS 500
54 #define STP_RED_ANSEXMAXCANDS 50
55 #define STP_RED_ANSMAXNEIGHBORS 25
56 
57 
58 /** NSV test data */
60 {
61  const SD* sdistance; /**< NON-OWNED! */
65  int* RESTRICT candidates_edge;
67  int* RESTRICT candidates_tail;
68  int* RESTRICT candidates_head;
69  int* RESTRICT nodes_isBlocked;
70  STP_Vectype(int) edgesrecord; /**< NON-OWNED! */
71  int* RESTRICT solnode; /**< NON-OWNED! */
72  SCIP_Real* fixed; /**< NON-OWNED offset pointer */
73  int ncandidates;
74  SCIP_Bool useRecording;
75 } NSV;
76 
77 
78 /*
79  * Local methods
80  */
81 
82 
83 /** ans subtest */
84 static inline
86  SCIP* scip, /**< SCIP data structure */
87  GRAPH* g, /**< graph data structure */
88  int* RESTRICT marked, /**< nodes array */
89  int* RESTRICT nelims, /**< pointer to number of reductions */
90  int vertex /**< vertex */
91 )
92 {
93  assert(vertex >= 0 && vertex < g->knots);
94  assert(!Is_term(g->term[vertex]));
95  assert(!graph_pc_knotIsDummyTerm(g, vertex));
96 
97 #ifdef SCIP_DEBUG
98  printf("delete node with ANS: ");
99  graph_knot_printInfo(g, vertex);
100 #endif
101 
102  (*nelims) += g->grad[vertex];
103 
104  graph_knot_del(scip, g, vertex, TRUE);
105  g->mark[vertex] = FALSE;
106  marked[vertex] = FALSE;
107 }
108 
109 /** un-marks */
110 static inline
112  const GRAPH* g, /**< graph data structure */
113  int basenode, /**< base node */
114  const int* neighbarr, /**< array of neighbors */
115  int nNeigbors, /**< nNeigbors */
116  int* RESTRICT marked /**< nodes array */
117 )
118 {
119  const int* const gHead = g->head;
120  const int* const gOeat = g->oeat;
121 
122  assert(neighbarr || nNeigbors == 0);
123 
124 #ifndef NDEBUG
125  assert(marked[basenode]);
126 
127  for( int x = 0; x < nNeigbors; x++ )
128  {
129  const int neighbor = neighbarr[x];
130  assert(neighbor >= 0 && neighbor < g->knots);
131  assert(marked[neighbor]);
132  assert(g->grad[neighbor] > 0);
133  }
134 #endif
135 
136  for( int e = g->outbeg[basenode]; e >= 0; e = gOeat[e] )
137  marked[gHead[e]] = FALSE;
138 
139  for( int l = 0; l < nNeigbors; l++ )
140  {
141  const int neighbor = neighbarr[l];
142 
143  for( int e = g->outbeg[neighbor]; e >= 0; e = gOeat[e] )
144  marked[gHead[e]] = FALSE;
145  }
146 
147  marked[basenode] = FALSE;
148 
149 #ifndef NDEBUG
150  for( int k2 = 0; k2 < g->knots; k2++ )
151  assert(!marked[k2]);
152 #endif
153 }
154 
155 /** ANS submethod for the case that the candidate vertex has exactly one non-dominated neighbor
156  * and both vertices combined are dominated */
157 static inline
159  SCIP* scip, /**< SCIP data structure */
160  GRAPH* g, /**< graph data structure */
161  int* RESTRICT marked, /**< nodes array */
162  int* RESTRICT nelims, /**< pointer to number of reductions */
163  SCIP_Real maxprize, /**< value to not surpass */
164  int candvertex, /**< candidate */
165  int bridgeedge /**< edge to neighbor */
166 )
167 {
168  /* NOTE: terminals can be leafs in an optimal solution! Thus we need to be careful with terminals. */
169  int e3;
170  const int neighbor = g->head[bridgeedge];
171  const SCIP_Real setprize = g->prize[candvertex] + g->prize[neighbor];
172 
173  assert(LE(maxprize, 0.0));
174 
175  if( SCIPisGT(scip, setprize, maxprize) )
176  return;
177 
178  for( e3 = g->outbeg[neighbor]; e3 >= 0; e3 = g->oeat[e3] )
179  {
180  const int head = g->head[e3];
181 
182  if( !marked[head] )
183  break;
184  }
185 
186  /* is {candvertex, neighbor} dominated? */
187  if( e3 == EAT_LAST )
188  {
189  const SCIP_Bool candvertexIsSmall = SCIPisLE(scip, g->prize[candvertex], maxprize);
190  const SCIP_Bool neighborIsSmall = SCIPisLE(scip, g->prize[neighbor], maxprize);
191 
192  /* delete both vertices? */
193  if( candvertexIsSmall && neighborIsSmall )
194  {
195  SCIPdebugMessage("delete set of two nodes with ANS: %d %d \n", candvertex, neighbor);
196 
197  ansDeleteVertex(scip, g, marked, nelims, candvertex);
198  ansDeleteVertex(scip, g, marked, nelims, neighbor);
199  }
200  else
201  {
202  SCIPdebugMessage("delete edge with ANS: %d->%d\n", neighbor, candvertex);
203 
204  graph_edge_del(scip, g, bridgeedge, TRUE);
205 
206  /* now both candvertex and neighbor are dominated */
207 
208  if( candvertexIsSmall )
209  ansDeleteVertex(scip, g, marked, nelims, candvertex);
210 
211  if( neighborIsSmall )
212  ansDeleteVertex(scip, g, marked, nelims, neighbor);
213  }
214  }
215 }
216 
217 /** ANS subtest */
218 static
220  SCIP* scip, /**< SCIP data structure */
221  GRAPH* g, /**< graph data structure */
222  int* RESTRICT marked, /**< nodes array */
223  int* RESTRICT nelims, /**< pointer to number of reductions */
224  SCIP_Real maxprize, /**< value to not surpass */
225  int candvertex /**< candidate */
226 )
227 {
228  int bridgeedge = -1;
229  unsigned misses = 0;
230 
231  assert(g->mark[candvertex]);
232  assert(!graph_pc_knotIsDummyTerm(g, candvertex));
233  assert(LE(maxprize, 0.0));
234  assert(!Is_term(g->term[candvertex]));
235 
236  for( int e2 = g->outbeg[candvertex]; e2 >= 0; e2 = g->oeat[e2] )
237  {
238  if( !marked[g->head[e2]] )
239  {
240  misses++;
241 
242  if( misses >= 2 )
243  break;
244 
245  bridgeedge = e2;
246  }
247  }
248 
249  /* neighbors of candvertex subset of those of k? */
250  if( misses == 0 && SCIPisLE(scip, g->prize[candvertex], maxprize) )
251  {
252  SCIPdebugMessage("candvertex %d is fully dominated \n", candvertex);
253  ansDeleteVertex(scip, g, marked, nelims, candvertex);
254  }
255  else if( misses == 1 )
256  {
257  ansProcessCandidateWithBridge(scip, g, marked, nelims, maxprize, candvertex, bridgeedge);
258  }
259 }
260 
261 
262 /** initializes NSV test data */
263 static
265  SCIP* scip, /**< SCIP data structure */
266  const SD* sdistance, /**< special distances storage */
267  const GRAPH* g, /**< graph structure */
268  int* solnode, /**< node array to mark whether an node is part of a given solution (CONNECT) */
269  SCIP_Real* fixed, /**< offset pointer */
270  NSV* nsv /**< NSV */
271 )
272 {
273  const BLCTREE* const blctree = sdistance->blctree;
275  SCIP_Real* RESTRICT candidates_taildist;
276  SCIP_Real* RESTRICT candidates_headdist;
277  int* RESTRICT candidates_edge;
278  int* RESTRICT candidates_tail;
279  int* RESTRICT candidates_head;
280  int* RESTRICT nodes_isBlocked;
281  SCIP_Bool* RESTRICT candidates_isLink;
282  int ncandidates;
283  const int nnodes = graph_get_nNodes(g);
284 
285 
286  assert(blctree);
287  assert(sdistance->sdprofit);
288 
289  ncandidates = reduce_blctreeGetMstNedges(blctree);
290  assert(ncandidates > 0);
291 
292  SCIP_CALL( SCIPallocBufferArray(scip, &candidates_bottleneck, ncandidates) );
293  SCIP_CALL( SCIPallocBufferArray(scip, &candidates_taildist, ncandidates) );
294  SCIP_CALL( SCIPallocBufferArray(scip, &candidates_headdist, ncandidates) );
295  SCIP_CALL( SCIPallocBufferArray(scip, &candidates_edge, ncandidates) );
296  SCIP_CALL( SCIPallocBufferArray(scip, &candidates_isLink, ncandidates) );
297  SCIP_CALL( SCIPallocBufferArray(scip, &candidates_tail, ncandidates) );
298  SCIP_CALL( SCIPallocBufferArray(scip, &candidates_head, ncandidates) );
299  SCIP_CALL( SCIPallocBufferArray(scip, &nodes_isBlocked, nnodes) );
300 
301  reduce_blctreeGetMstEdges(g, blctree, candidates_edge);
302  reduce_blctreeGetMstEdgesState(g, blctree, candidates_isLink);
303  reduce_blctreeGetMstEdgesToCutDist(g, blctree, candidates_taildist, candidates_headdist);
304  reduce_blctreeGetMstBottlenecks(g, blctree, candidates_bottleneck);
305 
306  for( int i = 0; i < ncandidates; i++ )
307  {
308  const int edge = candidates_edge[i];
309  candidates_tail[i] = g->tail[edge];
310  candidates_head[i] = g->head[edge];
311  }
312 
313  for( int i = 0; i < nnodes; i++ )
314  nodes_isBlocked[i] = FALSE;
315 
316  nsv->sdistance = sdistance;
325  nsv->solnode = solnode;
326  nsv->fixed = fixed;
327  nsv->useRecording = FALSE;
328  nsv->edgesrecord = NULL;
329  nsv->ncandidates = ncandidates;
330 
331  return SCIP_OKAY;
332 }
333 
334 
335 /** initializes NSV recordings */
336 static
338  STP_Vectype(int) edgesrecord, /**< edges record */
339  NSV* nsv /**< NSV */
340 )
341 {
342  assert(nsv);
343  assert(!nsv->edgesrecord);
344  assert(!nsv->useRecording);
345 
346  nsv->useRecording = TRUE;
347  nsv->edgesrecord = edgesrecord;
348 }
349 
350 /** frees NSV test data */
351 static
353  SCIP* scip, /**< SCIP data structure */
354  NSV* nsv /**< NSV */
355 )
356 {
357  SCIPfreeBufferArray(scip, &(nsv->nodes_isBlocked));
358  SCIPfreeBufferArray(scip, &(nsv->candidates_head));
359  SCIPfreeBufferArray(scip, &(nsv->candidates_tail));
360  SCIPfreeBufferArray(scip, &(nsv->candidates_isLink));
361  SCIPfreeBufferArray(scip, &(nsv->candidates_edge));
365 }
366 
367 
368 /** edge in NSV test can possibly still be contracted? */
369 static inline
371  const GRAPH* g, /**< graph structure */
372  const NSV* nsv, /**< NSV data */
373  int edge /**< the edge */
374  )
375 {
376  assert(graph_edge_isInRange(g, edge));
377 
378  if( graph_edge_isDeleted(g, edge) )
379  {
380  return FALSE;
381  }
382  else
383  {
384  const int* const nodes_isBlocked = nsv->nodes_isBlocked;
385  const int tail = g->tail[edge];
386  const int head = g->head[edge];
387 
388  if( nodes_isBlocked[tail] || nodes_isBlocked[head] )
389  {
390  return FALSE;
391  }
392  }
393 
394  return TRUE;
395 }
396 
397 
398 /** get special implied distances to terminals from both endpoints of given edge */
399 static inline
401  const GRAPH* g, /**< graph structure */
402  const NSV* nsv, /**< NSV data */
403  int edge, /**< the edge */
404  int candidate_id, /**< id of candidate */
405  SCIP_Real* dist_tail, /**< distance from tail */
406  SCIP_Real* dist_head /**< distance from head */
407  )
408 {
409  SCIP_Real termdist[4];
410  int firstedges[4];
411  int neighbterms[4];
412  const SD* sd = nsv->sdistance;
413  int nnterms;
414  const int tail = g->tail[edge];
415  const int head = g->head[edge];
416  int term_tail = -1;
417  const SCIP_Real bottleneckdist = nsv->candidates_bottleneck[candidate_id];
418  const SCIP_Real upper_sdbound = bottleneckdist - g->cost[edge];
419 
420  assert(GT(bottleneckdist, 0.0));
421  assert(GE(upper_sdbound, 0.0));
422  assert(nsv->candidates_edge[candidate_id] == edge);
423 
424  *dist_tail = FARAWAY;
425  *dist_head = FARAWAY;
426 
427  if( Is_term(g->term[tail]) )
428  {
429  term_tail = tail;
430  *dist_tail = 0.0;
431  }
432  else
433  {
434  const SCIP_Real* const cutdists_tail = nsv->candidates_taildist;
435 
436  graph_tpathsGet4CloseTermsLE(g, sd->terminalpaths, tail, upper_sdbound, neighbterms, firstedges,
437  termdist, &nnterms);
438 
439  for( int i = 0; i < nnterms; i++ )
440  {
441  const int term = neighbterms[i];
442  assert(term != tail);
443 
444  if( term == head )
445  continue;
446 
447  if( (firstedges[i] / 2) == (edge / 2) )
448  continue;
449 
450  if( termdist[i] < *dist_tail )
451  {
452  *dist_tail = termdist[i];
453  term_tail = term;
454  }
455  }
456 
457  if( cutdists_tail[candidate_id] < *dist_tail )
458  *dist_tail = cutdists_tail[candidate_id];
459  }
460 
461  if( Is_term(g->term[head]) )
462  {
463  *dist_head = 0.0;
464  }
465  else
466  {
467  const SCIP_Real* const cutdists_head = nsv->candidates_headdist;
468 
469  graph_tpathsGet4CloseTermsLE(g, sd->terminalpaths, head, upper_sdbound, neighbterms, firstedges,
470  termdist, &nnterms);
471 
472  for( int i = 0; i < nnterms; i++ )
473  {
474  const int term = neighbterms[i];
475  assert(term != head);
476 
477  if( term == tail || term == term_tail )
478  continue;
479 
480  if( (firstedges[i] / 2) == (edge / 2) )
481  continue;
482  if( termdist[i] < *dist_head )
483  *dist_head = termdist[i];
484  }
485 
486  if( cutdists_head[candidate_id] < *dist_head )
487  *dist_head = cutdists_head[candidate_id];
488  }
489 
490  assert(GE(*dist_tail, 0.0));
491  assert(GE(*dist_head, 0.0));
492 }
493 
494 
495 /** contract edge in NSV test */
496 static inline
498  SCIP* scip, /**< SCIP data structure */
499  int edge, /**< the edge */
500  int end_remain, /**< survivor end node of edge */
501  int end_killed, /**< other end node */
502  GRAPH* g, /**< graph structure */
503  NSV* nsv, /**< NSV data */
504  int* nelims /**< number of eliminations */
505 )
506 {
507  int* RESTRICT nodes_isBlocked = nsv->nodes_isBlocked;
508 
509 #ifdef SCIP_DEBUG
510  graph_edge_printInfo(g, edge);
511 #endif
512 
513  nodes_isBlocked[end_remain] = TRUE;
514  nodes_isBlocked[end_killed] = TRUE;
515 
516  if( nsv->useRecording )
517  {
518  assert(!nelims);
519  StpVecPushBack(scip, nsv->edgesrecord, edge);
520  }
521  else
522  {
523  assert(nelims);
524  *(nsv->fixed) += g->cost[edge];
525  SCIP_CALL( graph_knot_contractFixed(scip, g, nsv->solnode, edge, end_remain, end_killed) );
526  graph_knot_chg(g, end_remain, STP_TERM);
527  (*nelims)++;
528  }
529 
530  return SCIP_OKAY;
531 }
532 
533 /** executes actual NSV test */
534 static
536  SCIP* scip, /**< SCIP data structure */
537  NSV* nsv, /**< NSV */
538  GRAPH* g, /**< graph structure */
539  int* nelims /**< number of eliminations */
540 )
541 {
542  const SDPROFIT* const sdprofit = nsv->sdistance->sdprofit;
543  const int ncandidates = nsv->ncandidates;
544  const int* const candidate_edges = nsv->candidates_edge;
545  const SCIP_Real* const candidate_bottlenecks = nsv->candidates_bottleneck;
546  const SCIP_Bool* const candidate_isLink = nsv->candidates_isLink;
547  assert(sdprofit);
548 
549  for( int i = 0; i < ncandidates; ++i )
550  {
551  const int edge = candidate_edges[i];
552 
553  if( nsvEdgeIsValid(g, nsv, edge) )
554  {
555  assert(graph_edge_isInRange(g, edge));
556  assert(LE(g->cost[edge], candidate_bottlenecks[i]));
557 
558  /* cut edge? */
559  if( EQ(candidate_bottlenecks[i], FARAWAY) )
560  {
561  SCIP_Bool pruned;
562  SCIP_CALL( reduce_cutEdgeTryPrune(scip, edge, g, &pruned) );
563 
564  if( !pruned )
565  {
566  SCIP_CALL( nsvEdgeContract(scip, edge, g->tail[edge], g->head[edge], g, nsv, nelims) );
567  }
568 
569  continue;
570  }
571 
572  if( candidate_isLink[i] )
573  {
574  const SCIP_Real edgecost = g->cost[edge];
575  const int tail = g->tail[edge];
576  const int head = g->head[edge];
577  const SCIP_Real profit_tail = reduce_sdprofitGetProfit(sdprofit, tail, head, -1);
578  const SCIP_Real profit_head = reduce_sdprofitGetProfit(sdprofit, head, tail, -1);
579  SCIP_Real dist_tail;
580  SCIP_Real dist_head;
581 
582  if( Is_term(g->term[tail]) && GE(profit_head, edgecost) )
583  {
584  SCIPdebugMessage("NSV contract implied profit end (%f >= %f) ... ", profit_head, edgecost);
585  SCIP_CALL( nsvEdgeContract(scip, edge, tail, head, g, nsv, nelims) );
586  continue;
587  }
588 
589  if( Is_term(g->term[head]) && GE(profit_tail, edgecost) )
590  {
591  SCIPdebugMessage("NSV contract implied profit end (%f >= %f) ... ", profit_tail, edgecost);
592  SCIP_CALL( nsvEdgeContract(scip, flipedge(edge), head, tail, g, nsv, nelims) );
593  continue;
594  }
595 
596  nsvEdgeGetTermDists(g, nsv, edge, i, &dist_tail, &dist_head);
597 
598  if( LE(dist_tail + edgecost + dist_head, candidate_bottlenecks[i]) )
599  {
600  SCIPdebugMessage("NSV contract default ... ");
601  SCIPdebugMessage("%f + %f + %f <= %f ... ", dist_tail, edgecost, dist_head, candidate_bottlenecks[i]);
602 
603  SCIP_CALL( nsvEdgeContract(scip, edge, tail, head, g, nsv, nelims) );
604  }
605  }
606  }
607  }
608 
609  assert(graph_valid(scip, g));
610 
611 
612  return SCIP_OKAY;
613 }
614 
615 
616 /*
617  * Interface methods
618  */
619 
620 /** implied version of NSV test */
622  SCIP* scip, /**< SCIP data structure */
623  const SD* sdistance, /**< special distances storage */
624  GRAPH* g, /**< graph structure */
625  int* solnode, /**< node array to mark whether an node is part of a given solution (CONNECT) */
626  SCIP_Real* fixed, /**< offset pointer */
627  int* nelims /**< number of eliminations */
628 )
629 {
630  NSV nsv;
631  assert(scip && sdistance && nelims && fixed);
632  assert(*nelims >= 0);
633 
634  SCIP_CALL( nsvInitData(scip, sdistance, g, solnode, fixed, &nsv) );
635  SCIP_CALL( nsvExec(scip, &nsv, g, nelims) );
636  nsvFreeData(scip, &nsv);
637 
638  return SCIP_OKAY;
639 }
640 
641 
642 /** implied version of NSV test. Does not perform the reductions, but rather records them */
644  SCIP* scip, /**< SCIP data structure */
645  const SD* sdistance, /**< special distances storage */
646  GRAPH* g, /**< graph structure */
647  STP_Vectype(int)* edgerecord /**< keeps number edges */
648 )
649 {
650  NSV nsv;
651  assert(scip && sdistance && edgerecord);
652 
653  SCIP_CALL( nsvInitData(scip, sdistance, g, NULL, NULL, &nsv) );
654  nsvInitRecording(*edgerecord, &nsv);
655  SCIP_CALL( nsvExec(scip, &nsv, g, NULL) );
656 
657  *edgerecord = nsv.edgesrecord;
658  nsvFreeData(scip, &nsv);
659 
660  return SCIP_OKAY;
661 }
662 
663 
664 /** shortest link reduction */
666  SCIP* scip, /**< SCIP data structure */
667  const int* edgestate, /**< for propagation or NULL */
668  GRAPH* g, /**< graph data structure */
669  PATH* vnoi, /**< Voronoi data structure */
670  SCIP_Real* fixed, /**< offset pointer */
671  int* vbase, /**< Voronoi/shortest path bases array */
672  int* vrnodes, /**< Voronoi/shortest path array */
673  STP_Bool* visited, /**< Voronoi/shortest path array */
674  int* solnode, /**< node array to mark whether an node is part of a given solution (CONNECT),
675  or NULL */
676  int* nelims /**< pointer to store number of eliminations */
677  )
678 {
679  STP_Vectype(int) queue = NULL;
680  SCIP_Bool* nodes_isTerm;
681  STP_Bool foundterms;
682  STP_Bool* forbidden;
683  STP_Bool* newterm;
684  const SCIP_Bool isPc = graph_pc_isPc(g);
685  const int nnodes = g->knots;
686 
687  assert(vnoi != NULL);
688  assert(vbase != NULL);
689  assert(vrnodes != NULL);
690  assert(visited != NULL);
691 
692  *nelims = 0;
693  foundterms = FALSE;
694 
695  if( g->terms <= 1 )
696  return SCIP_OKAY;
697 
698  if( g->terms <= 2 && graph_pc_isUnrootedPcMw(g) )
699  return SCIP_OKAY;
700 
701  SCIP_CALL( SCIPallocClearBufferArray(scip, &forbidden, nnodes) );
702  SCIP_CALL( SCIPallocClearBufferArray(scip, &newterm, nnodes) );
703  SCIP_CALL( SCIPallocBufferArray(scip, &nodes_isTerm, nnodes) );
704 
705  BMSclearMemoryArray(visited, nnodes);
706  graph_mark(g);
707  graph_getIsTermArray(g, nodes_isTerm);
708  graph_voronoiTerms(g, nodes_isTerm, vbase, vnoi);
709 
710 #ifndef NDEBUG
711  for( int i = 0; i < nnodes; i++ )
712  {
713  assert(!newterm[i]);
714  assert(!forbidden[i]);
715  assert(!visited[i]);
716  }
717 #endif
718 
719  for( int baseterm = 0; baseterm < nnodes; baseterm++ )
720  {
721  if( nodes_isTerm[baseterm] && g->mark[baseterm] && !forbidden[baseterm] )
722  {
723  SCIP_Real mincost2 = FARAWAY;
724  SCIP_Real mincost3 = FARAWAY;
725  SCIP_Real ttdist;
726  int mintail;
727  int minhead;
728  int minedge = UNKNOWN;
729  int vrcount = 1;
730 
731  assert(StpVecGetSize(queue) == 0);
732 
733  StpVecPushBack(scip, queue, baseterm);
734  vrnodes[0] = baseterm;
735  visited[baseterm] = TRUE;
736 
737  /* traverse Voronoi-region of "baseterm" */
738  while( StpVecGetSize(queue) != 0 )
739  {
740  const int qnode = queue[StpVecGetSize(queue) - 1];
741  StpVecPopBack(queue);
742 
743  for( int e = g->outbeg[qnode]; e != EAT_LAST; e = g->oeat[e] )
744  {
745  int headbase;
746  minhead = g->head[e];
747 
748  if( !g->mark[minhead] )
749  continue;
750 
751  headbase = vbase[minhead];
752  assert(headbase != UNKNOWN);
753 
754  if( !visited[minhead] && headbase == baseterm )
755  {
756  visited[minhead] = TRUE;
757  vrnodes[vrcount++] = minhead;
758  StpVecPushBack(scip, queue, minhead);
759  }
760  else if( headbase != baseterm )
761  /* update shortest and second shortest edge (cost) leaving the voronoi region */
762  {
763  const SCIP_Real edgecost = g->cost[e];
764  if( minedge == UNKNOWN )
765  {
766  minedge = e;
767  }
768  else if( LE(edgecost, g->cost[minedge]) )
769  {
770  mincost3 = mincost2;
771  mincost2 = g->cost[minedge];
772  minedge = e;
773  }
774  else if( LE(edgecost, mincost2) )
775  {
776  mincost3 = mincost2;
777  mincost2 = g->cost[e];
778  }
779  else if( LT(edgecost, mincost3) )
780  {
781  mincost3 = g->cost[e];
782  }
783  }
784  }
785  }
786  for( int j = 0; j < vrcount; j++ )
787  visited[vrnodes[j]] = FALSE;
788 
789 #ifndef NDEBUG
790  for( int j = 0; j < nnodes; j++ )
791  assert(!visited[j]);
792 #endif
793 
794  if( minedge == UNKNOWN )
795  continue;
796 
797  mintail = g->tail[minedge];
798  minhead = g->head[minedge];
799  assert(vbase[mintail] == baseterm);
800 
801  ttdist = vnoi[mintail].dist + g->cost[minedge] + vnoi[minhead].dist;
802 
803  if( isPc )
804  {
805  if( !nodes_isTerm[mintail] )
806  ttdist -= g->prize[mintail];
807 
808  if( !nodes_isTerm[minhead] )
809  ttdist -= g->prize[minhead];
810 
811  assert(GE(ttdist, 0.0) && LE(ttdist, vnoi[mintail].dist + g->cost[minedge] + vnoi[minhead].dist));
812  }
813 
814  /* check whether minedge can be removed */
815  if( SCIPisGE(scip, mincost2, ttdist) && (edgestate == NULL || edgestate[minedge] != EDGE_BLOCKED) )
816  {
817  int contractnode_in;
818  int contractnode_out;
819  int old;
820 
821  if( isPc )
822  {
823  assert(g->stp_type != STP_RPCSPG || EQ(g->prize[g->source], FARAWAY));
824 
825  if( !SCIPisLE(scip, ttdist, g->prize[vbase[minhead]]) )
826  continue;
827 
828  if( baseterm == mintail )
829  {
830  if( !SCIPisLE(scip, ttdist, g->prize[baseterm]) )
831  continue;
832  }
833  else
834  {
835  if( !SCIPisLT(scip, ttdist, g->prize[baseterm]) )
836  continue;
837  }
838 
839  if( nodes_isTerm[minhead] && nodes_isTerm[mintail] )
840  continue;
841  }
842 
843  assert(g->mark[mintail] && g->mark[minhead]);
844  assert(!Is_pseudoTerm(g->term[mintail]) && !Is_pseudoTerm(g->term[minhead]));
845 
846  if( nodes_isTerm[minhead] || (isPc && graph_pc_knotIsNonLeafTerm(g, mintail) ) )
847  {
848  contractnode_in = minhead;
849  contractnode_out = mintail;
850  }
851  else
852  {
853  contractnode_in = mintail;
854  contractnode_out = minhead;
855  }
856 
857  // NOTE: currently not supported for contraction operation
858  // todo
859  if( isPc && graph_pc_knotIsNonLeafTerm(g, contractnode_in) )
860  continue;
861 
862  *fixed += g->cost[minedge];
863  old = g->grad[contractnode_in] + g->grad[contractnode_out] - 1;
864 
865  // todo
866 #ifdef SCIP_DEBUG
867  printf("SL contract edge: \n");
868  graph_edge_printInfo(g, minedge);
869 #endif
870 
871  if( isPc )
872  {
873  SCIP_CALL( graph_pc_contractEdge(scip, g, solnode, contractnode_in, contractnode_out, baseterm) );
874  assert(g->grad[contractnode_in] > 0);
875  if( graph_pc_knotIsFixedTerm(g, baseterm) && !nodes_isTerm[contractnode_in] )
876  {
877  assert(!Is_anyTerm(g->term[contractnode_in]));
878  newterm[contractnode_in] = TRUE;
879  foundterms = TRUE;
880  }
881  }
882  else
883  {
884  SCIP_CALL( graph_knot_contractFixed(scip, g, solnode, minedge, contractnode_in, contractnode_out) );
885 
886  assert(g->grad[contractnode_out] == 0 && g->grad[contractnode_in] >= 0);
887 
888  if( !nodes_isTerm[contractnode_in] )
889  {
890  newterm[contractnode_in] = TRUE;
891  foundterms = TRUE;
892  }
893  }
894 
895  assert(old - g->grad[contractnode_in] - g->grad[contractnode_out] > 0);
896  (*nelims) += old - g->grad[contractnode_in] - g->grad[contractnode_out];
897  forbidden[vbase[contractnode_in]] = TRUE;
898  forbidden[vbase[contractnode_out]] = TRUE;
899  }
900  }
901  }
902 
903  if( foundterms )
904  {
905  for( int i = 0; i < nnodes; i++ )
906  {
907  if( newterm[i] && g->grad[i] > 0 )
908  {
909  if( isPc )
910  {
911  if( !graph_pc_knotIsFixedTerm(g, i) )
912  graph_pc_knotToFixedTerm(scip, g, i, NULL);
913  }
914  else if( !nodes_isTerm[i] )
915  {
916  graph_knot_chg(g, i, STP_TERM);
917  }
918  }
919  }
920  }
921 
922  StpVecFree(scip, queue);
923  SCIPfreeBufferArray(scip, &nodes_isTerm);
924  SCIPfreeBufferArray(scip, &newterm);
925  SCIPfreeBufferArray(scip, &forbidden);
926 
927  return SCIP_OKAY;
928 }
929 
930 
931 /* NV reduction from T. Polzin's "Algorithms for the Steiner problem in networks" */
933  SCIP* scip, /**< SCIP data structure */
934  GRAPH* g, /**< graph data structure */
935  PATH* vnoi, /**< Voronoi data structure */
936  SCIP_Real* fixed, /**< offset pointer */
937  int* edgearrint, /**< edge int array for internal computations */
938  int* vbase, /**< array for internal computations */
939  int* solnode, /**< node array to mark whether an node is part of a given solution (CONNECT),
940  or NULL */
941  int* nelims /**< pointer to store number of eliminations */
942  )
943 {
944  SCIP_Real* distance;
945  SCIP_Real min1;
946  SCIP_Real min2;
947  SCIP_Real pi;
948  SCIP_Real pt;
949  SCIP_Real ttdist;
950  int* term;
951  int* minedge1;
952  int* distnode;
953  int i;
954  int l;
955  int k;
956  int e;
957  int t;
958  int old;
959  int edge1;
960  int nnodes;
961  int nterms;
962  int mingrad;
963  int termcount;
964  SCIP_Bool pc;
965  assert(g != NULL);
966  assert(vnoi != NULL);
967  assert(vbase != NULL);
968 
969  t = 0;
970  termcount = 0;
971  *nelims = 0;
972  pi = 0;
973  pt = 0;
974 
975  nnodes = g->knots;
976  nterms = g->terms;
977  pc = (g->stp_type == STP_PCSPG) || (g->stp_type == STP_RPCSPG);
978  SCIP_CALL( SCIPallocBufferArray(scip, &term, nterms) );
979  SCIP_CALL( SCIPallocBufferArray(scip, &minedge1, nterms) );
980  SCIP_CALL( SCIPallocBufferArray(scip, &distance, nnodes) );
981 
982  /* minimal grad of a vertex to be scrutinized */
983  if( pc )
984  {
985  if( g->stp_type == STP_RPCSPG )
986  mingrad = 3;
987  else
988  mingrad = 4;
989 
990  SCIP_CALL( SCIPallocBufferArray(scip, &distnode, nnodes) );
991  }
992  else
993  {
994  mingrad = 2;
995  distnode = NULL;
996  for( i = 0; i < nnodes; i++ )
997  g->mark[i] = (g->grad[i] > 0);
998  }
999 
1000  for( i = 0; i < nnodes; i++ )
1001  {
1002  if( Is_term(g->term[i]) && g->mark[i] && g->grad[i] > 0 )
1003  {
1004  /* compute shortest incident edge */
1005  edge1 = UNKNOWN;
1006  if( g->grad[i] >= 1 )
1007  {
1008  min1 = FARAWAY;
1009 
1010  for( e = g->outbeg[i]; e != EAT_LAST; e = g->oeat[e] )
1011  {
1012  if( !g->mark[g->head[e]] )
1013  continue;
1014  if( SCIPisLE(scip, g->cost[e], min1) )
1015  {
1016  edge1 = e;
1017  min1 = g->cost[e];
1018  }
1019  }
1020  }
1021  minedge1[termcount] = edge1;
1022  term[termcount++] = i;
1023  }
1024  }
1025 
1026  /* compute Voronoi regions and distances */
1027  assert(0 && "does currently not work");
1028  SCIP_CALL( graph_voronoiWithDist(scip, g, NULL, g->cost, distance, edgearrint, vbase, minedge1, distnode, vnoi) );
1029 
1030  for( l = 0; l < termcount; l++ )
1031  {
1032  /* get l'th terminal */
1033  i = term[l];
1034 
1035  if( g->grad[i] < mingrad )
1036  continue;
1037 
1038  assert(minedge1[l] != UNKNOWN);
1039  /* get shortest two edges */
1040  edge1 = UNKNOWN;
1041  min2 = FARAWAY;
1042  min1 = FARAWAY;
1043  for( e = g->outbeg[i]; e != EAT_LAST; e = g->oeat[e] )
1044  {
1045  if( !g->mark[g->head[e]] )
1046  continue;
1047  if( SCIPisLE(scip, g->cost[e], min1) )
1048  {
1049  edge1 = e;
1050  min2 = min1;
1051  min1 = g->cost[e];
1052  }
1053  else if( SCIPisLE(scip, g->cost[e], min2) )
1054  {
1055  min2 = g->cost[e];
1056  }
1057  }
1058 
1059  assert(edge1 != UNKNOWN);
1060  assert(i == g->tail[edge1]);
1061  k = g->head[edge1];
1062 
1063  /* covered in degree test */
1064  if( Is_term(g->term[k]) )
1065  continue;
1066 
1067  if( vbase[k] != i )
1068  {
1069  if( pc )
1070  t = vbase[k];
1071  ttdist = g->cost[edge1] + vnoi[k].dist;
1072  }
1073  else
1074  {
1075  if( distnode != NULL )
1076  t = distnode[i];
1077  ttdist = distance[i];
1078  }
1079  if( pc )
1080  {
1081  if( i != g->source )
1082  pi = g->prize[i];
1083  else
1084  pi = FARAWAY;
1085 
1086  if( t != g->source )
1087  pt = g->prize[t];
1088  else
1089  pt = FARAWAY;
1090  }
1091 
1092  if( SCIPisGE(scip, min2, ttdist)
1093  && (!pc || (SCIPisLE(scip, g->cost[edge1], pi) && SCIPisLE(scip, ttdist, pt))) )
1094  {
1095  old = g->grad[i] + g->grad[k] - 1;
1096  *fixed += g->cost[edge1];
1097 
1098  if( pc )
1099  {
1100  SCIP_CALL( graph_pc_contractEdge(scip, g, solnode, i, k, i) );
1101  }
1102  else
1103  {
1104  SCIP_CALL( graph_knot_contractFixed(scip, g, solnode, edge1, i, k) );
1105  }
1106  assert(old - g->grad[i] - g->grad[k] > 0);
1107  (*nelims) += old - g->grad[i] - g->grad[k];
1108  }
1109  }
1110 
1111  SCIPfreeBufferArrayNull(scip, &distnode);
1112  SCIPfreeBufferArray(scip, &distance);
1113  SCIPfreeBufferArray(scip, &minedge1);
1114  SCIPfreeBufferArray(scip, &term);
1115 
1116  return SCIP_OKAY;
1117 }
1118 
1119 
1120 /* advanced NV reduction */
1122  SCIP* scip, /**< SCIP data structure */
1123  const int* edgestate, /**< for propagation or NULL */
1124  GRAPH* g, /**< graph data structure */
1125  PATH* vnoi, /**< Voronoi data structure */
1126  SCIP_Real* distance, /**< nodes-sized distance array */
1127  SCIP_Real* fixed, /**< offset pointer */
1128  int* edgearrint, /**< edges-sized array */
1129  int* vbase, /**< Voronoi base array */
1130  int* distnode, /**< nodes-sized distance array */
1131  int* solnode, /**< node array to mark whether an node is part of a given solution (CONNECT),
1132  or NULL */
1133  int* nelims /**< pointer to store number of eliminations */
1134  )
1135 {
1136  SCIP_Real baseprize;
1137  SCIP_Real nextprize;
1138  SCIP_Real ttdist;
1139  int* term;
1140  int* minedge1;
1141  SCIP_Bool* nodes_isTerm;
1142  int head1;
1143  int nextterm;
1144  int mingrad;
1145  int termcount;
1146  SCIP_Bool contract;
1147  const int nnodes = graph_get_nNodes(g);
1148  const int nterms = graph_get_nTerms(g);
1149  const SCIP_Bool pc = (g->stp_type == STP_PCSPG) || (g->stp_type == STP_RPCSPG);
1150 
1151  assert(vnoi != NULL);
1152  assert(vbase != NULL);
1153 
1154  baseprize = 0;
1155  nextprize = 0;
1156  *nelims = 0;
1157  termcount = 0;
1158 
1159  if( nterms <= 2 )
1160  return SCIP_OKAY;
1161 
1162  SCIP_CALL( SCIPallocBufferArray(scip, &term, nterms) );
1163  SCIP_CALL( SCIPallocBufferArray(scip, &minedge1, nterms) );
1164  SCIP_CALL( SCIPallocBufferArray(scip, &nodes_isTerm, nnodes) );
1165 
1166  graph_getIsTermArray(g, nodes_isTerm);
1167 
1168  /* set minimal grad of a vertex to be scrutinized */
1169  if( pc )
1170  {
1171  if( g->stp_type == STP_RPCSPG )
1172  mingrad = 3;
1173  else
1174  mingrad = 4;
1175 
1176  assert(distnode != NULL);
1177  assert(!g->extended);
1178  }
1179  else
1180  {
1181  mingrad = 2;
1182  }
1183 
1184  graph_mark(g);
1185 
1186  /* compute shortest incident edge to each terminal */
1187  for( int i = 0; i < nnodes; i++ )
1188  {
1189  if( nodes_isTerm[i] && g->mark[i] )
1190  {
1191  /* compute shortest incident edge */
1192  int edge1 = UNKNOWN;
1193 
1194  if( g->grad[i] >= 1 )
1195  {
1196  SCIP_Real min1 = FARAWAY;
1197 
1198  for( int e = g->outbeg[i]; e != EAT_LAST; e = g->oeat[e] )
1199  {
1200  if( g->mark[g->head[e]] && LE(g->cost[e], min1) )
1201  {
1202  edge1 = e;
1203  min1 = g->cost[e];
1204  }
1205  }
1206  }
1207 
1208  assert(!pc || !graph_pc_knotIsNonLeafTerm(g, i));
1209 
1210  minedge1[termcount] = edge1;
1211  term[termcount++] = i;
1212  }
1213  }
1214 
1215  assert(termcount <= nterms);
1216 
1217  if( termcount <= 1 )
1218  {
1219  assert(pc);
1220  SCIPfreeBufferArray(scip, &nodes_isTerm);
1221  SCIPfreeBufferArray(scip, &minedge1);
1222  SCIPfreeBufferArray(scip, &term);
1223 
1224  return SCIP_OKAY;
1225  }
1226 
1227  /* compute Voronoi regions and distances */
1228  SCIP_CALL( graph_voronoiWithDist(scip, g, nodes_isTerm, g->cost, distance, edgearrint, vbase, minedge1, distnode, vnoi) );
1229 
1230  /* main loop: try to contract (shortest) edges into terminals */
1231  for( int l = 0; l < termcount; l++ )
1232  {
1233  /* get l'th terminal */
1234  const int baseterm = term[l];
1235  SCIP_Real min1;
1236  SCIP_Real min2;
1237  SCIP_Real min3;
1238  int edge1;
1239  int edge2;
1240 
1241  if( g->grad[baseterm] < mingrad )
1242  continue;
1243 
1244  /* get shortest two edges */
1245 
1246  min3 = FARAWAY;
1247  min2 = FARAWAY;
1248  min1 = FARAWAY;
1249  edge1 = UNKNOWN;
1250  edge2 = UNKNOWN;
1251 
1252  for( int e = g->outbeg[baseterm]; e != EAT_LAST; e = g->oeat[e] )
1253  {
1254  if( !g->mark[g->head[e]] )
1255  continue;
1256 
1257  if( SCIPisLE(scip, g->cost[e], min1) )
1258  {
1259  edge2 = edge1;
1260  edge1 = e;
1261 
1262  min3 = min2;
1263  min2 = min1;
1264  min1 = g->cost[e];
1265  }
1266  else if( SCIPisLE(scip, g->cost[e], min2) )
1267  {
1268  edge2 = e;
1269 
1270  min3 = min2;
1271  min2 = g->cost[e];
1272  }
1273  else if( SCIPisLE(scip, g->cost[e], min3) )
1274  {
1275  min3 = g->cost[e];
1276  }
1277  }
1278 
1279  assert(edge1 != UNKNOWN);
1280  assert(baseterm == g->tail[edge1]);
1281 
1282  head1 = g->head[edge1];
1283 
1284  /* covered in degree test */
1285  if( nodes_isTerm[head1] )
1286  continue;
1287 
1288  if( vbase[head1] != baseterm )
1289  {
1290  ttdist = g->cost[edge1] + vnoi[head1].dist;
1291 
1292  if( pc )
1293  {
1294  if( !nodes_isTerm[head1] )
1295  {
1296  ttdist -= g->prize[head1];
1297  assert(GE(ttdist, 0.0) && LE(ttdist, g->cost[edge1] + vnoi[head1].dist));
1298  }
1299  nextterm = vbase[head1];
1300  }
1301  }
1302  else
1303  {
1304  if( pc )
1305  nextterm = distnode[baseterm];
1306 
1307  ttdist = distance[baseterm];
1308  }
1309 
1310  if( pc )
1311  {
1312  assert(baseterm != g->source || g->stp_type == STP_RPCSPG);
1313 
1314  if( nextterm == UNKNOWN )
1315  continue;
1316 
1317  if( g->grad[nextterm] == 0 )
1318  {
1319  assert(*nelims > 0);
1320  continue;
1321  }
1322 
1323  baseprize = g->prize[baseterm];
1324 
1325  if( nextterm == UNKNOWN )
1326  nextprize = -1.0;
1327  else
1328  nextprize = g->prize[nextterm];
1329  }
1330 
1331  contract = FALSE;
1332 
1333  if( edgestate != NULL && edgestate[edge1] == EDGE_BLOCKED )
1334  {
1335  contract = FALSE;
1336  }
1337  else if( SCIPisGE(scip, min2, ttdist) )
1338  {
1339  contract = TRUE;
1340  }
1341  else if( edge2 != UNKNOWN && !nodes_isTerm[g->head[edge2]] && SCIPisGE(scip, min3, ttdist) )
1342  {
1343  int e;
1344  nextterm = g->head[edge2];
1345  for( e = g->outbeg[nextterm]; e != EAT_LAST; e = g->oeat[e] )
1346  {
1347  if( e != flipedge(edge2) && SCIPisLT(scip, g->cost[e], ttdist) )/*&& !neighb[g->head[e]] ) */
1348  break;
1349  }
1350 
1351  if( e == EAT_LAST )
1352  contract = TRUE;
1353  }
1354 
1355  if( contract && (!pc || (SCIPisLE(scip, g->cost[edge1], baseprize) && SCIPisLE(scip, ttdist, nextprize))) )
1356  {
1357  (*nelims)++;
1358  SCIPdebugMessage("nvAdv contract \n");
1359 
1360  *fixed += g->cost[edge1];
1361 
1362  if( pc )
1363  {
1364  SCIP_CALL( graph_pc_contractEdge(scip, g, solnode, baseterm, head1, baseterm) );
1365  }
1366  else
1367  {
1368  SCIP_CALL( graph_knot_contractFixed(scip, g, solnode, edge1, baseterm, head1) );
1369  }
1370  }
1371  }
1372 
1373  SCIPfreeBufferArray(scip, &nodes_isTerm);
1374  SCIPfreeBufferArray(scip, &minedge1);
1375  SCIPfreeBufferArray(scip, &term);
1376 
1377  return SCIP_OKAY;
1378 }
1379 
1380 
1381 // todo finish
1382 #ifdef SCIP_DISABLED
1383 /** domination vertex reduction for the SPG */
1384 void reduce_alt_dv(
1385  SCIP* scip, /**< SCIP data structure */
1386  GRAPH* g, /**< graph data structure */
1387  STP_Bool* marked, /**< nodes array */
1388  int* count /**< pointer to number of reductions */
1389  )
1390 {
1391  const int nnodes = g->knots;
1392  int nreds = 0;
1393 
1394  assert(scip != NULL);
1395  assert(g != NULL);
1396  assert(count != NULL);
1397  assert(marked != NULL);
1398  assert(g->stp_type == STP_SPG);
1399 
1400  BMSclearMemoryArray(marked, nnodes);
1401 
1402  /* main loop */
1403  for( int k = 0; k < nnodes; k++ )
1404  {
1405  const SCIP_Real maxgrad = g->grad[k];
1406 
1407  if( maxgrad < 3 )
1408  continue;
1409 
1410  assert(g->mark[k]);
1411 
1412  /* mark adjacent vertices and k*/
1413  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
1414  marked[g->head[e]] = TRUE;
1415 
1416  marked[k] = TRUE;
1417 
1418  /* check all other nodes */
1419  for( int i = 0; i < nnodes; i++ )
1420  {
1421  /* valid candidate? */
1422  if( !Is_term(g->term[i]) && g->grad[i] <= maxgrad && g->mark[i] && k != i )
1423  {
1424  SCIP_Real min;
1425  int e2;
1426  for( e2 = g->outbeg[i]; e2 != EAT_LAST; e2 = g->oeat[e2] )
1427  if( !marked[g->head[e2]] )
1428  break;
1429 
1430  /* neighbors of j subset of those of k? */
1431  if( e2 == EAT_LAST )
1432  {
1433 #if 0
1434  int maxe = g->outbeg[i];
1435  for( e2 = g->outbeg[i]; e2 != EAT_LAST; e2 = g->oeat[e2] )
1436  if( g->cost[e] > g->cost[maxe] )
1437  maxe = e;
1438 
1439  min = 0.0;
1440 
1441 
1442 
1443 
1444  (*count) += g->grad[i];
1445  while( g->outbeg[i] != EAT_LAST )
1446  graph_edge_del(scip, g, g->outbeg[j] TRUE);
1447 
1448  g->mark[i] = FALSE;
1449  marked[i] = FALSE;
1450 #endif
1451  }
1452  }
1453  }
1454 
1455  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
1456  marked[g->head[e]] = FALSE;
1457 
1458  marked[k] = FALSE;
1459 
1460  for( int j = 0; j < nnodes; j++ )
1461  assert(marked[j] == FALSE);
1462  }
1463 
1464  *count += nreds;
1465 }
1466 
1467 #endif
1468 
1469 /** adjacent neighbourhood reduction for the MWCSP */
1471  SCIP* scip, /**< SCIP data structure */
1472  GRAPH* g, /**< graph data structure */
1473  int* nelims /**< pointer to number of reductions */
1474  )
1475 {
1476  int* marked;
1477  const int nnodes = graph_get_nNodes(g);
1478 
1479  assert(scip != NULL);
1480  assert(nelims != NULL);
1481  assert(graph_pc_isMw(g));
1482  assert(graph_valid(scip, g));
1483 
1484  *nelims = 0;
1485 
1486  SCIP_CALL( SCIPallocBufferArray(scip, &marked, nnodes) );
1487  graph_mark(g);
1488 
1489  /* unmark all nodes */
1490  for( int k = 0; k < nnodes; k++ )
1491  marked[k] = FALSE;
1492 
1493  /* check neighborhood of all nodes */
1494  for( int k = 0; k < nnodes; k++ )
1495  {
1496  SCIP_Real min;
1497  int e;
1498  int neighborcount = 0;
1499 
1500  if( !g->mark[k] )
1501  {
1502  assert(graph_pc_knotIsDummyTerm(g, k) || 0 == g->grad[k]);
1503  continue;
1504  }
1505 
1506  /* mark adjacent vertices and k*/
1507  for( e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
1508  marked[g->head[e]] = TRUE;
1509 
1510  marked[k] = TRUE;
1511 
1512  if( LT(g->prize[k], 0.0) )
1513  min = g->prize[k];
1514  else
1515  min = 0.0;
1516 
1517  SCIPdebugMessage("check ANS base node %d \n", k);
1518 
1519  /* check all neighbors of k */
1520  e = g->outbeg[k];
1521  while( e != EAT_LAST && neighborcount++ < STP_RED_ANSMAXNEIGHBORS )
1522  {
1523  const int j = g->head[e];
1524  e = g->oeat[e];
1525 
1526  /* valid candidate? */
1527  if( g->grad[j] <= g->grad[k] && !Is_term(g->term[j]) && g->mark[j] )
1528  {
1529  ansProcessCandidate(scip, g, marked, nelims, min, j);
1530  }
1531  }
1532 
1533  ansUnmark(g, k, NULL, 0, marked);
1534  }
1535 
1536  assert(graph_valid(scip, g));
1537 
1538  SCIPfreeBufferArray(scip, &marked);
1539 
1540  return SCIP_OKAY;
1541 }
1542 
1543 /** advanced adjacent neighbourhood reduction for the MWCSP */
1545  SCIP* scip, /**< SCIP data structure */
1546  GRAPH* g, /**< graph data structure */
1547  int* nelims, /**< pointer to number of performed reductions */
1548  SCIP_Bool extneigbhood /**< use extended neighbour hood */
1549  )
1550 {
1551  int* marked;
1552  int candidates[MAX(STP_RED_ANSMAXCANDS, STP_RED_ANSEXMAXCANDS)];
1553  int neighbarr[STP_RED_CNSNN];
1554  const int nnodes = graph_get_nNodes(g);
1555  int* const RESTRICT gHead = g->head;
1556  int* const RESTRICT gOeat = g->oeat;
1557 
1558  assert(scip != NULL);
1559  assert(nelims != NULL);
1560  assert(graph_pc_isMw(g));
1561 
1562  *nelims = 0;
1563 
1564  SCIP_CALL( SCIPallocBufferArray(scip, &marked, nnodes) );
1565 
1566  for( int k = 0; k < nnodes; k++ )
1567  marked[k] = FALSE;
1568 
1569  /* check neighborhood of all non-terminals of degree >= 2 */
1570  for( int k = 0; k < nnodes; k++ )
1571  {
1572  SCIP_Real maxprize;
1573  int nNeigbors;
1574  int nCands;
1575  int maxgrad;
1576 
1577  if( (!(g->mark[k])) || (g->grad[k] < 2) || Is_term(g->term[k]) )
1578  continue;
1579 
1580  nNeigbors = 0;
1581 
1582  /* mark adjacent vertices and k */
1583  for( int e = g->outbeg[k]; e >= 0; e = gOeat[e] )
1584  {
1585  const int j = gHead[e];
1586  marked[j] = TRUE;
1587 
1588  if( SCIPisGT(scip, g->prize[j], 0.0) && nNeigbors < STP_RED_CNSNN )
1589  {
1590  assert(Is_term(g->term[j]));
1591  assert(!graph_pc_knotIsDummyTerm(g, j));
1592 
1593  neighbarr[nNeigbors++] = j;
1594  }
1595  }
1596 
1597  marked[k] = TRUE;
1598  maxgrad = g->grad[k];
1599  nCands = 0;
1600 
1601  /* mark neighbors of the neighbors */
1602  for( int n = 0; n < nNeigbors; n++ )
1603  {
1604  for( int e = g->outbeg[neighbarr[n]]; e >= 0; e = gOeat[e] )
1605  {
1606  marked[gHead[e]] = TRUE;
1607  }
1608  maxgrad += g->grad[neighbarr[n]];
1609  }
1610 
1611  assert(SCIPisLE(scip, g->prize[k], 0.0));
1612 
1613  maxprize = g->prize[k];
1614 
1615  if( extneigbhood )
1616  {
1617  assert(0 && "implement me");
1618  }
1619  else
1620  {
1621  for( int e = g->outbeg[k]; e != EAT_LAST; e = gOeat[e] )
1622  {
1623  const int neighbor = gHead[e];
1624 
1625  if( g->grad[neighbor] <= maxgrad && !Is_term(g->term[neighbor]) )
1626  {
1627  assert(g->mark[neighbor]);
1628 
1629  candidates[nCands++] = neighbor;
1630  if( nCands >= STP_RED_ANSMAXCANDS )
1631  {
1632  SCIPdebugMessage("REACHED ANS LIMIT %d \n", nCands);
1633  break;
1634  }
1635  }
1636  }
1637  }
1638 
1639  /* now check all neighbors of k for elimination */
1640  for( int l = 0; l < nCands; l++ )
1641  ansProcessCandidate(scip, g, marked, nelims, maxprize, candidates[l]);
1642 
1643  /* clean-up */
1644  ansUnmark(g, k, neighbarr, nNeigbors, marked);
1645  }
1646 
1647  assert(graph_valid(scip, g));
1648 
1649  SCIPfreeBufferArray(scip, &marked);
1650 
1651  return SCIP_OKAY;
1652 }
1653 
1654 
1655 /** alternative advanced adjacent neighbourhood reduction for the MWCSP */
1657  SCIP* scip, /**< SCIP data structure */
1658  GRAPH* g, /**< graph data structure */
1659  int* nelims /**< pointer to number of reductions */
1660  )
1661 {
1662  int neighbarr[STP_RED_CNSNN + 1];
1663  int* marked;
1664  SCIP_Real min;
1665  const int nnodes = graph_get_nNodes(g);
1666 
1667  assert(scip != NULL);
1668  assert(nelims != NULL);
1669  assert(graph_pc_isMw(g));
1670 
1671  *nelims = 0;
1672 
1673  SCIP_CALL( SCIPallocBufferArray(scip, &marked, nnodes) );
1674 
1675  for( int k = 0; k < nnodes; k++ )
1676  marked[k] = FALSE;
1677 
1678  /* check neighborhood of all non-terminals of degree >= 2 */
1679  for( int k = 0; k < nnodes; k++ )
1680  {
1681  SCIP_Real maxSpecialNeighborPrize;
1682  int specialNeigborRound0;
1683 
1684  if( (!(g->mark[k])) || (g->grad[k] < 2) || Is_term(g->term[k]) )
1685  continue;
1686 
1687  maxSpecialNeighborPrize = g->prize[k];
1688  specialNeigborRound0 = -1;
1689 
1690  for( int run = 0; run < 2; run++ )
1691  {
1692  int e;
1693  int nNeighbors = 0;
1694  int specialNeighbor = UNKNOWN;
1695  int maxgrad = g->grad[k];
1696 
1697  /* mark (limited number of) adjacent vertices and k */
1698  for( e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
1699  {
1700  const int neighbor = g->head[e];
1701  marked[neighbor] = TRUE;
1702  if( SCIPisGE(scip, g->prize[neighbor], 0.0) && nNeighbors < STP_RED_CNSNN - 1 )
1703  {
1704  assert(!graph_pc_knotIsDummyTerm(g, neighbor));
1705 
1706  neighbarr[nNeighbors++] = neighbor;
1707  }
1708  else if( GT(g->prize[neighbor], maxSpecialNeighborPrize) && neighbor != specialNeigborRound0 )
1709  {
1710  assert(g->mark[neighbor]);
1711 
1712  maxSpecialNeighborPrize = g->prize[neighbor];
1713  specialNeighbor = neighbor;
1714  }
1715  }
1716 
1717  marked[k] = TRUE;
1718 
1719  /* we already take the special neighbor in round 1; it might still be updated in round 2 */
1720  if( run == 0 && specialNeighbor != UNKNOWN )
1721  neighbarr[nNeighbors++] = specialNeighbor;
1722 
1723  /* find a neighbor of the neighbors to add to the neighbor set */
1724  for( int l = 0; l < nNeighbors; l++ )
1725  {
1726  const int neighbor = neighbarr[l];
1727  for( e = g->outbeg[neighbor]; e != EAT_LAST; e = g->oeat[e] )
1728  {
1729  const int neighborNeighbor = g->head[e];
1730  if( run == 1 && g->mark[neighborNeighbor] && !Is_term(g->term[neighborNeighbor])
1731  && GT(g->prize[neighborNeighbor], maxSpecialNeighborPrize) && neighborNeighbor != specialNeigborRound0 )
1732  {
1733  maxSpecialNeighborPrize = g->prize[neighborNeighbor];
1734  specialNeighbor = neighborNeighbor;
1735  }
1736  marked[neighborNeighbor] = TRUE;
1737  }
1738 
1739  marked[neighbor] = VERTEX_NEIGHBOR;
1740  maxgrad += g->grad[neighbor];
1741  }
1742 
1743  if( run == 1 && specialNeighbor != UNKNOWN )
1744  {
1745  maxgrad += g->grad[specialNeighbor];
1746  neighbarr[nNeighbors++] = specialNeighbor;
1747 
1748  for( e = g->outbeg[specialNeighbor]; e != EAT_LAST; e = g->oeat[e] )
1749  marked[g->head[e]] = TRUE;
1750  }
1751 
1752  assert(SCIPisLE(scip, g->prize[k], 0.0));
1753 
1754  min = g->prize[k];
1755  if( specialNeighbor != UNKNOWN )
1756  {
1757  marked[specialNeighbor] = VERTEX_NEIGHBOR;
1758  specialNeigborRound0 = specialNeighbor;
1759 
1760  if( LT(g->prize[specialNeighbor], 0.0) )
1761  min += g->prize[specialNeighbor];
1762  }
1763 
1764  /* check all neighbors of k */
1765  e = g->outbeg[k];
1766  while( e != EAT_LAST )
1767  {
1768  const int neighbor = g->head[e];
1769  e = g->oeat[e];
1770 
1771  /* valid candidate? */
1772  if( g->grad[neighbor] <= maxgrad && !Is_term(g->term[neighbor]) && marked[neighbor] != VERTEX_NEIGHBOR )
1773  {
1774  assert(g->mark[neighbor]);
1775 
1776  ansProcessCandidate(scip, g, marked, nelims, min, neighbor);
1777  }
1778  }
1779 
1780  ansUnmark(g, k, neighbarr, nNeighbors, marked);
1781  }
1782  }
1783 
1784  assert(graph_valid(scip, g));
1785 
1786  SCIPfreeBufferArray(scip, &marked);
1787 
1788  return SCIP_OKAY;
1789 }
1790 
1791 
1792 /** advanced connected neighborhood subset reduction test for the MWCSP */
1794  SCIP* scip, /**< SCIP data structure */
1795  GRAPH* g, /**< graph data structure */
1796  int* marked, /**< nodes array for internal use */
1797  int* count /**< pointer to number of reductions */
1798  )
1799 {
1800  SCIP_Real min;
1801  SCIP_Real kprize;
1802  int neighbarr[STP_RED_CNSNN + 1];
1803  int neighbarr2[STP_RED_CNSNN + 1];
1804  int j;
1805  int e;
1806  int k2;
1807  int e2;
1808  int l;
1809  int nn;
1810  int nn2;
1811  int k2grad;
1812  int maxgrad;
1813  const int nnodes = graph_get_nNodes(g);
1814 
1815  assert(scip != NULL);
1816  assert(g != NULL);
1817  assert(count != NULL);
1818  assert(marked != NULL);
1819  assert(g->stp_type == STP_MWCSP);
1820 
1821  k2grad = 0;
1822  *count = 0;
1823 
1824  /* unmark all nodes */
1825  for( int k = 0; k < nnodes; k++ )
1826  marked[k] = VERTEX_OTHER;
1827 
1828  /* first run: consider node plus adjacent terminals */
1829 
1830  /* check neighborhood of all nodes */
1831  for( int k = 0; k < nnodes; k++ )
1832  {
1833  if( !(g->mark[k]) || (g->grad[k] < 2) )
1834  continue;
1835 
1836  nn = 0;
1837  k2 = UNKNOWN;
1838  nn2 = 0;
1839  kprize = g->prize[k];
1840  maxgrad = g->grad[k];
1841 
1842  /* mark adjacent vertices and k */
1843  for( e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
1844  {
1845  j = g->head[e];
1846 
1847  if( !g->mark[j] )
1848  continue;
1849 
1850  if( GE(g->prize[j], 0.0) && nn < STP_RED_CNSNN - 1 )
1851  {
1852  neighbarr[nn++] = j;
1853  marked[j] = VERTEX_CONNECT;
1854  }
1855  else
1856  {
1857  marked[j] = VERTEX_NEIGHBOR;
1858  }
1859  }
1860 
1861  marked[k] = VERTEX_CONNECT;
1862 
1863  /* traverse all connected non-negative nodes and mark their neighbors */
1864  for( l = 0; l < nn; l++ )
1865  {
1866  for( e = g->outbeg[neighbarr[l]]; e != EAT_LAST; e = g->oeat[e] )
1867  {
1868  j = g->head[e];
1869  if( !g->mark[j] )
1870  continue;
1871 
1872  if( marked[j] == VERTEX_OTHER )
1873  marked[j] = VERTEX_NEIGHBOR;
1874  }
1875  maxgrad += g->grad[neighbarr[l]] - 1;
1876  }
1877 
1878  if( Is_term(g->term[k]) )
1879  min = 0.0;
1880  else
1881  min = g->prize[k];
1882 
1883  /* traverse all vertices (main loop) */
1884  for( j = 0; j < nnodes; j++ )
1885  {
1886  /* vertex part of the current connected subset? Or terminal? Or belonging to the extension of the graph? */
1887  if( marked[j] != VERTEX_CONNECT && g->mark[j] && !Is_term(g->term[j])
1888  &&
1889  /* valid candidate? */
1890  g->grad[j] <= maxgrad && SCIPisLE(scip, g->prize[j], min) )
1891  {
1892  for( e2 = g->outbeg[j]; e2 != EAT_LAST; e2 = g->oeat[e2] )
1893  if( marked[g->head[e2]] == VERTEX_OTHER )
1894  break;
1895 
1896  /* neighbors of j subset of those of k? */
1897  if( e2 == EAT_LAST )
1898  {
1899  /* yes, delete vertex */
1900  while( g->outbeg[j] != EAT_LAST )
1901  {
1902  e2 = g->outbeg[j];
1903  (*count)++;
1904  graph_edge_del(scip, g, e2, TRUE);
1905  }
1906  g->mark[j] = FALSE;
1907  marked[j] = VERTEX_OTHER;
1908  }
1909  }
1910  }
1911 
1912  for( e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
1913  marked[g->head[e]] = VERTEX_OTHER;
1914 
1915  for( l = 0; l < nn; l++ )
1916  for( e = g->outbeg[neighbarr[l]]; e != EAT_LAST; e = g->oeat[e] )
1917  marked[g->head[e]] = VERTEX_OTHER;
1918 
1919  marked[k] = VERTEX_OTHER;
1920 
1921 #ifdef DEBUG
1922  for( l = 0; l < nnodes; l++ )
1923  assert(marked[l] == VERTEX_OTHER);
1924 #endif
1925 
1926  }
1927  /* second run: consider the same plus an additional (non-positive) vertex */
1928 
1929  for( int k = 0; k < nnodes; k++ )
1930  {
1931  if( !(g->mark[k]) || g->grad[k] < 2 || Is_term(g->term[k]) )
1932  continue;
1933 
1934  nn = 0;
1935  k2 = UNKNOWN;
1936  nn2 = 0;
1937  kprize = g->prize[k];
1938  maxgrad = g->grad[k];
1939 
1940  /* mark adjacent vertices and k */
1941  for( e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
1942  {
1943  j = g->head[e];
1944 
1945  if( !g->mark[j] )
1946  continue;
1947 
1948  if( SCIPisGE(scip, g->prize[j], 0.0) && nn < STP_RED_CNSNN - 1 )
1949  {
1950  neighbarr[nn++] = j;
1951  marked[j] = VERTEX_CONNECT;
1952  }
1953  else if( (SCIPisGT(scip, g->prize[j], kprize) && nn2 < STP_RED_CNSNN)
1954  || (SCIPisGE(scip, g->prize[j], kprize) && j > k && nn2 < 3) )
1955  {
1956  neighbarr2[nn2++] = j;
1957  marked[j] = VERTEX_NEIGHBOR;
1958  }
1959  else
1960  {
1961  marked[j] = VERTEX_NEIGHBOR;
1962  }
1963  }
1964 
1965  marked[k] = VERTEX_CONNECT;
1966 
1967  /* traverse all connected non-negative nodes and mark their neighbors */
1968  for( l = 0; l < nn; l++ )
1969  {
1970  for( e = g->outbeg[neighbarr[l]]; e != EAT_LAST; e = g->oeat[e] )
1971  {
1972  j = g->head[e];
1973  if( !g->mark[j] )
1974  continue;
1975 
1976  if( marked[j] == VERTEX_OTHER && nn2 < STP_RED_CNSNN
1977  && (SCIPisGT(scip, g->prize[j], kprize)
1978  || (SCIPisGE(scip, g->prize[j], kprize) && j > k
1979  && nn2 < 3)) )
1980  {
1981  neighbarr2[nn2++] = j;
1982  marked[j] = VERTEX_NEIGHBOR;
1983  }
1984  else if( marked[j] == VERTEX_OTHER )
1985  {
1986  marked[j] = VERTEX_NEIGHBOR;
1987  }
1988  }
1989  maxgrad += g->grad[neighbarr[l]] - 1;
1990  }
1991 
1992  if( Is_term(g->term[k]) )
1993  min = 0.0;
1994  else
1995  min = g->prize[k];
1996 
1997  for( l = 0; l < nn2; l++ )
1998  {
1999  k2 = neighbarr2[l];
2000 
2001  if( !g->mark[k2] )
2002  continue;
2003 
2004  for( e = g->outbeg[k2]; e != EAT_LAST; e = g->oeat[e] )
2005  if( marked[g->head[e]] == VERTEX_OTHER && g->mark[g->head[e]] )
2006  marked[g->head[e]] = VERTEX_TEMPNEIGHBOR;
2007  min += g->prize[k2];
2008  k2grad = g->grad[k2];
2009  maxgrad += k2grad - 1;
2010  assert(SCIPisLE(scip, g->prize[k2], 0.0));
2011 
2012  /* traverse all vertices (main loop) */
2013  for( j = 0; j < nnodes; j++ )
2014  {
2015  /* vertex part of the current connected subset? Or terminal? Or belonging to the extension of the graph? */
2016  if( marked[j] != VERTEX_CONNECT && g->mark[j]
2017  && !Is_term(g->term[j]) &&
2018  /* valid candidate? */
2019  g->grad[j] <= maxgrad && SCIPisLE(scip, g->prize[j], min) )
2020  {
2021  for( e2 = g->outbeg[j]; e2 != EAT_LAST; e2 = g->oeat[e2] )
2022  if( marked[g->head[e2]] == VERTEX_OTHER )
2023  break;
2024 
2025  /* neighbors of j subset of those of k? */
2026  if( e2 == EAT_LAST )
2027  {
2028  /* yes, delete vertex */
2029  while( g->outbeg[j] != EAT_LAST )
2030  {
2031  e2 = g->outbeg[j];
2032  (*count)++;
2033  graph_edge_del(scip, g, e2, TRUE);
2034  }
2035  g->mark[j] = FALSE;
2036  marked[j] = VERTEX_OTHER;
2037  }
2038  }
2039  }
2040  for( e = g->outbeg[k2]; e != EAT_LAST; e = g->oeat[e] )
2041  if( marked[g->head[e]] == VERTEX_TEMPNEIGHBOR
2042  && g->mark[g->head[e]] )
2043  marked[g->head[e]] = VERTEX_OTHER;
2044  min -= g->prize[k2];
2045  maxgrad -= k2grad - 1;
2046 
2047  }
2048  for( e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
2049  marked[g->head[e]] = VERTEX_OTHER;
2050 
2051  for( l = 0; l < nn; l++ )
2052  for( e = g->outbeg[neighbarr[l]]; e != EAT_LAST; e = g->oeat[e] )
2053  marked[g->head[e]] = VERTEX_OTHER;
2054 
2055  marked[k] = VERTEX_OTHER;
2056 #ifdef DEBUG
2057  for( l = 0; l < nnodes; l++ )
2058  assert(marked[l] == VERTEX_OTHER);
2059 #endif
2060  }
2061 
2062  return SCIP_OKAY;
2063 }
2064 
2065 
2066 /** non-positive vertex reduction for the MWCSP */
2068  SCIP* scip,
2069  GRAPH* g,
2070  PATH* pathtail,
2071  int* heap,
2072  int* statetail,
2073  int* statehead,
2074  int* nelims,
2075  int limit
2076  )
2077 {
2078  GRAPH* auxg;
2079  PATH mst[5];
2080  PATH* pathhead;
2081  int adjverts[5];
2082  int incedges[5];
2083  int* memlbltail;
2084  int* memlblhead;
2085  SCIP_Real prize;
2086  const int nnodes = graph_get_nNodes(g);
2087 
2088  assert(scip != NULL);
2089  assert(pathtail != NULL);
2090  assert(heap != NULL);
2091  assert(statetail != NULL);
2092  assert(statehead != NULL);
2093  assert(nelims != NULL);
2094  assert(limit > 0);
2095 
2096  /* NOTE: necessary because of erroneous compiler warning */
2097  incedges[0] = incedges[1] = incedges[2] = -1;
2098 
2099  *nelims = 0;
2100 
2101  SCIP_CALL( SCIPallocBufferArray(scip, &pathhead, nnodes + 1) );
2102  SCIP_CALL( SCIPallocBufferArray(scip, &memlbltail, nnodes + 1) );
2103  SCIP_CALL( SCIPallocBufferArray(scip, &memlblhead, nnodes + 1) );
2104 
2105  graph_mark(g);
2106 
2107  /* initialize arrays */
2108  for( int i = 0; i < nnodes; i++ )
2109  {
2110  statetail[i] = UNKNOWN;
2111  pathtail[i].dist = FARAWAY;
2112  pathtail[i].edge = UNKNOWN;
2113  statehead[i] = UNKNOWN;
2114  pathhead[i].dist = FARAWAY;
2115  pathhead[i].edge = UNKNOWN;
2116  }
2117 
2118 
2119  /* --- NPV3 test --- */
2120 
2121  /* try to eliminate non-positive vertices of degree 3 */
2122  for( int i = 0; i < nnodes; i++ )
2123  {
2124  int k;
2125  SCIP_Real sdist0;
2126  SCIP_Real sdist1;
2127  SCIP_Real sdist2;
2128 
2129  assert(g->grad[i] >= 0);
2130 
2131  /* only non-positive vertices of degree 3 */
2132  if( g->grad[i] != 3 || !g->mark[i] || Is_term(g->term[i]) )
2133  continue;
2134 
2135  k = 0;
2136  for( int e = g->outbeg[i]; e != EAT_LAST; e = g->oeat[e] )
2137  {
2138  assert(k < 3);
2139  assert(g->mark[g->head[e]]);
2140 
2141  incedges[k] = e;
2142  adjverts[k++] = g->head[e];
2143  }
2144 
2145  assert(k == 3);
2146 
2147  g->mark[i] = FALSE;
2148 
2149  prize = g->prize[i];
2150  SCIP_CALL( reduce_getSdByPaths(scip, g, pathtail, pathhead, &sdist0, -prize, heap, statetail, statehead, memlbltail, memlblhead, adjverts[0], adjverts[1], limit, FALSE, TRUE) );
2151  SCIP_CALL( reduce_getSdByPaths(scip, g, pathtail, pathhead, &sdist1, -prize, heap, statetail, statehead, memlbltail, memlblhead, adjverts[1], adjverts[2], limit, FALSE, TRUE) );
2152  SCIP_CALL( reduce_getSdByPaths(scip, g, pathtail, pathhead, &sdist2, -prize, heap, statetail, statehead, memlbltail, memlblhead, adjverts[2], adjverts[0], limit, FALSE, TRUE) );
2153 
2154  /* can vertex be deleted? */
2155  if( (SCIPisGE(scip, -sdist0 - sdist1, prize) && SCIPisGE(scip, -sdist2, prize))
2156  || (SCIPisGE(scip, -sdist1 - sdist2, prize) && SCIPisGE(scip, -sdist0, prize))
2157  || (SCIPisGE(scip, -sdist2 - sdist0, prize) && SCIPisGE(scip, -sdist1, prize))
2158  )
2159  {
2160  SCIPdebugMessage("npv3Reduction delete: %d (prize: %f) \n", i, g->prize[i]);
2161  (*nelims) += g->grad[i];
2162 
2163  graph_knot_del(scip, g, i, TRUE);
2164  }
2165  else
2166  {
2167  if( SCIPisGE(scip, -sdist0 - sdist1, prize) )
2168  {
2169  SCIPdebugMessage("npv3Reduction delete edge: %d \n", incedges[1]);
2170  graph_edge_del(scip, g, incedges[1], TRUE);
2171  (*nelims) += 1;
2172  }
2173  else if( SCIPisGE(scip, -sdist1 - sdist2, prize) )
2174  {
2175  SCIPdebugMessage("npv3Reduction delete edge: %d \n", incedges[2]);
2176  graph_edge_del(scip, g, incedges[2], TRUE);
2177  (*nelims) += 1;
2178  }
2179  else if( SCIPisGE(scip, -sdist2 - sdist0, prize) )
2180  {
2181  SCIPdebugMessage("npv3Reduction delete edge: %d \n", incedges[0]);
2182  graph_edge_del(scip, g, incedges[0], TRUE);
2183  (*nelims) += 1;
2184  }
2185 
2186  g->mark[i] = TRUE;
2187  assert(g->grad[i] >= 2);
2188  }
2189  }
2190 
2191  /* --- NPV4 test --- */
2192 
2193  /* initialize mst struct and new graph for further tests */
2194  SCIP_CALL( graph_init(scip, &auxg, 5, 40, 1) );
2195 
2196  for( int k = 0; k < 4; k++ )
2197  graph_knot_add(auxg, -1);
2198  for( int k = 0; k < 4; k++ )
2199  for( int k2 = k + 1; k2 < 4; k2++ )
2200  graph_edge_add(scip, auxg, k, k2, 1.0, 1.0);
2201 
2202  SCIP_CALL( graph_path_init(scip, auxg) );
2203 
2204  /* try to eliminate non-positive vertices of degree 4 */
2205  for( int i = 0; i < nnodes; i++ )
2206  {
2207  int e;
2208  int k;
2209 
2210  /* only non-positive vertices of degree 4 */
2211  if( g->grad[i] != 4 || !g->mark[i] || Is_term(g->term[i]) )
2212  continue;
2213 
2214  k = 0;
2215 
2216  /* store neighbours */
2217  for( e = g->outbeg[i]; e != EAT_LAST; e = g->oeat[e] )
2218  adjverts[k++] = g->head[e];
2219 
2220  assert(k == 4);
2221 
2222  g->mark[i] = FALSE;
2223  prize = g->prize[i];
2224 
2225  /* compute mw bottleneck distance to each pair of neighbours */
2226  for( k = 0; k < 4; k++ )
2227  {
2228  auxg->mark[k] = TRUE;
2229  for( e = auxg->outbeg[k]; e != EAT_LAST; e = auxg->oeat[e] )
2230  {
2231  const int k2 = auxg->head[e];
2232  if( k2 > k )
2233  {
2234  SCIP_Real sdist0;
2235  SCIP_CALL( reduce_getSdByPaths(scip, g, pathtail, pathhead, &(sdist0), -prize, heap, statetail, statehead, memlbltail, memlblhead, adjverts[k], adjverts[k2], limit, FALSE, TRUE) );
2236  auxg->cost[e] = sdist0;
2237  if( SCIPisGT(scip, prize, -auxg->cost[e]) )
2238  break;
2239 
2240  auxg->cost[flipedge(e)] = auxg->cost[e];
2241  }
2242  }
2243  if( e != EAT_LAST )
2244  break;
2245  }
2246 
2247  k = UNKNOWN;
2248  if( e == EAT_LAST )
2249  {
2250  SCIP_Real sdist0 = 0.0;
2251 
2252  /* compute mst on all neighbours */
2253  graph_path_exec(scip, auxg, MST_MODE, 0, auxg->cost, mst);
2254 
2255  /* calculate mst cost */
2256  for( int l = 1; l < 4; l++ )
2257  sdist0 += mst[l].dist;
2258 
2259  if( SCIPisLE(scip, prize, -sdist0) )
2260  {
2261  /* compute subset msts on all neighbours */
2262  for( k = 0; k < 4; k++ )
2263  {
2264  auxg->mark[k] = FALSE;
2265  sdist0 = 0.0;
2266  if( k != 0 )
2267  {
2268  graph_path_exec(scip, auxg, MST_MODE, 0, auxg->cost, mst);
2269  for( int l = 1; l < 4; l++ )
2270  if( auxg->mark[l] )
2271  sdist0 += mst[l].dist;
2272  }
2273  else
2274  {
2275  graph_path_exec(scip, auxg, MST_MODE, 1, auxg->cost, mst);
2276  for( int l = 2; l < 4; l++ )
2277  sdist0 += mst[l].dist;
2278  }
2279  auxg->mark[k] = TRUE;
2280  if( SCIPisGT(scip, prize, -sdist0) )
2281  break;
2282  }
2283  }
2284  }
2285 
2286  /* can node be eliminated? */
2287  if( k == 4 )
2288  {
2289  SCIPdebugMessage("npv4Reduction delete: %d (prize: %f) \n", i, g->prize[i]);
2290  (*nelims) += g->grad[i];
2291 
2292  graph_knot_del(scip, g, i, TRUE);
2293  }
2294  else
2295  {
2296  g->mark[i] = TRUE;
2297  }
2298  }
2299 
2300  /* --- NPV5 test --- */
2301 
2302  /* enlarge graph for NPV5 test*/
2303  graph_knot_add(auxg, -1);
2304  for( int k = 0; k < 4; k++ )
2305  graph_edge_add(scip, auxg, k, 4, 1.0, 1.0);
2306  graph_path_exit(scip, auxg);
2307  SCIP_CALL( graph_path_init(scip, auxg) );
2308 
2309  /* try to eliminate non-positive vertices of degree 5 */
2310  for( int i = 0; i < nnodes; i++ )
2311  {
2312  int e;
2313  int k;
2314 
2315  /* only non-positive vertices of degree 5 */
2316  if( g->grad[i] != 5 || !g->mark[i] || Is_term(g->term[i]) )
2317  continue;
2318  k = 0;
2319 
2320  /* store neighbours */
2321  for( e = g->outbeg[i]; e != EAT_LAST; e = g->oeat[e] )
2322  adjverts[k++] = g->head[e];
2323 
2324  assert(k == 5);
2325 
2326  g->mark[i] = FALSE;
2327  prize = g->prize[i];
2328 
2329  for( k = 0; k < 5; k++ )
2330  {
2331  auxg->mark[k] = TRUE;
2332  for( e = auxg->outbeg[k]; e != EAT_LAST; e = auxg->oeat[e] )
2333  {
2334  const int k2 = auxg->head[e];
2335  if( k2 > k )
2336  {
2337  SCIP_Real sdist0;
2338  SCIP_CALL( reduce_getSdByPaths(scip, g, pathtail, pathhead, &(sdist0), -prize, heap, statetail, statehead, memlbltail, memlblhead, adjverts[k], adjverts[k2], limit, FALSE, TRUE) );
2339  auxg->cost[e] = sdist0;
2340  if( SCIPisGT(scip, prize, -auxg->cost[e]) )
2341  break;
2342 
2343  auxg->cost[flipedge(e)] = auxg->cost[e];
2344  }
2345  }
2346  if( e != EAT_LAST )
2347  break;
2348  }
2349  k = UNKNOWN;
2350  if( e == EAT_LAST )
2351  {
2352  SCIP_Real sdist0 = 0.0;
2353 
2354  graph_path_exec(scip, auxg, MST_MODE, 0, auxg->cost, mst);
2355 
2356  for( int l = 1; l < 5; l++ )
2357  sdist0 += mst[l].dist;
2358 
2359  if( SCIPisLE(scip, prize, -sdist0) )
2360  {
2361  for( k = 0; k < 5; k++ )
2362  {
2363  int k2 = UNKNOWN;
2364  auxg->mark[k] = FALSE;
2365  sdist0 = 0.0;
2366  if( k != 0 )
2367  {
2368  graph_path_exec(scip, auxg, MST_MODE, 0, auxg->cost, mst);
2369  for( int l = 1; l < 5; l++ )
2370  if( auxg->mark[l] )
2371  sdist0 += mst[l].dist;
2372  }
2373  else
2374  {
2375  graph_path_exec(scip, auxg, MST_MODE, 1, auxg->cost, mst);
2376  for( int l = 2; l < 5; l++ )
2377  sdist0 += mst[l].dist;
2378  }
2379 
2380  if( SCIPisLE(scip, prize, -sdist0) )
2381  {
2382  for( k2 = k + 1; k2 < 5; k2++ )
2383  {
2384  if( k2 == k )
2385  continue;
2386  auxg->mark[k2] = FALSE;
2387  sdist0 = 0.0;
2388  if( k2 != 0 && k != 0)
2389  {
2390  graph_path_exec(scip, auxg, MST_MODE, 0, auxg->cost, mst);
2391  for( int l = 1; l < 5; l++ )
2392  if( auxg->mark[l] )
2393  sdist0 += mst[l].dist;
2394  }
2395  else
2396  {
2397  int s;
2398  if( k != 1 && k2 != 1 )
2399  s = 1;
2400  else
2401  s = 2;
2402  graph_path_exec(scip, auxg, MST_MODE, s, auxg->cost, mst);
2403  for( int l = 0; l < 5; l++ )
2404  if( auxg->mark[l] && l != s )
2405  sdist0 += mst[l].dist;
2406  }
2407  auxg->mark[k2] = TRUE;
2408  if( SCIPisGT(scip, prize, -sdist0) )
2409  break;
2410  }
2411  }
2412  auxg->mark[k] = TRUE;
2413  if( k2 != 5 )
2414  break;
2415  }
2416  }
2417  }
2418 
2419  if( k == 5 )
2420  {
2421  SCIPdebugMessage(" \n npv5Reduction delete: %d (prize: %f) \n", i, g->prize[i]);
2422  (*nelims) += g->grad[i];
2423 
2424  graph_knot_del(scip, g, i, TRUE);
2425  }
2426  else
2427  {
2428  g->mark[i] = TRUE;
2429  }
2430  }
2431 
2432  /* free memory*/
2433  graph_path_exit(scip, auxg);
2434  graph_free(scip, &auxg, TRUE);
2435 
2436  SCIPfreeBufferArray(scip, &memlblhead);
2437  SCIPfreeBufferArray(scip, &memlbltail);
2438  SCIPfreeBufferArray(scip, &pathhead);
2439 
2440  return SCIP_OKAY;
2441 }
2442 
2443 
2444 /** chain reduction (NPV_2) for the MWCSP */
2446  SCIP* scip,
2447  GRAPH* g,
2448  PATH* pathtail,
2449  int* heap,
2450  int* statetail,
2451  int* statehead,
2452  int* nelims,
2453  int limit
2454  )
2455 {
2456  PATH* pathhead;
2457  int* memlbltail;
2458  int* memlblhead;
2459  const int nnodes = graph_get_nNodes(g);
2460 
2461  assert(scip != NULL);
2462  assert(pathtail != NULL);
2463  assert(heap != NULL);
2464  assert(statetail != NULL);
2465  assert(statehead != NULL);
2466  assert(nelims != NULL);
2467 
2468  *nelims = 0;
2469 
2470  SCIP_CALL( SCIPallocBufferArray(scip, &pathhead, nnodes + 1) );
2471  SCIP_CALL( SCIPallocBufferArray(scip, &memlbltail, nnodes + 1) );
2472  SCIP_CALL( SCIPallocBufferArray(scip, &memlblhead, nnodes + 1) );
2473 
2474  /* initialize arrays */
2475  for( int i = 0; i < nnodes; i++ )
2476  {
2477  statetail[i] = UNKNOWN;
2478  pathtail[i].dist = FARAWAY;
2479  pathtail[i].edge = UNKNOWN;
2480  statehead[i] = UNKNOWN;
2481  pathhead[i].dist = FARAWAY;
2482  pathhead[i].edge = UNKNOWN;
2483  }
2484 
2485  /* main loop: try to eliminate non-positive vertices of degree two */
2486  for( int i = 0; i < nnodes; i++ )
2487  {
2488  SCIP_Real sdist;
2489  int i1;
2490  int i2;
2491  int e1;
2492  int e2;
2493 
2494  if( g->grad[i] != 2 || !g->mark[i] || Is_term(g->term[i]) )
2495  continue;
2496 
2497  /* non-positive chains */
2498  e1 = g->outbeg[i];
2499  e2 = g->oeat[e1];
2500  i1 = g->head[e1];
2501  i2 = g->head[e2];
2502 
2503  assert(e1 >= 0);
2504  assert(e2 >= 0);
2505  assert(g->mark[i1]);
2506  assert(g->mark[i2]);
2507 
2508  g->mark[i] = FALSE;
2509 
2510  SCIP_CALL( reduce_getSdByPaths(scip, g, pathtail, pathhead, &sdist, -(g->prize[i]), heap, statetail, statehead, memlbltail, memlblhead, i1, i2, limit, FALSE, TRUE) );
2511 
2512  if( SCIPisGE(scip, -sdist, g->prize[i]) )
2513  {
2514  SCIPdebugMessage("delete : %d prize: %f sd: %f \n", i, g->prize[i], -sdist );
2515  graph_edge_del(scip, g, e1, TRUE);
2516  graph_edge_del(scip, g, e2, TRUE);
2517  (*nelims) += 2;
2518  }
2519  else
2520  {
2521  g->mark[i] = TRUE;
2522  }
2523  }
2524 
2525  SCIPfreeBufferArray(scip, &memlblhead);
2526  SCIPfreeBufferArray(scip, &memlbltail);
2527  SCIPfreeBufferArray(scip, &pathhead);
2528 
2529  return SCIP_OKAY;
2530 }
2531 
2532 
2533 /** non-negative path reduction for the MWCSP */
2535  SCIP* scip, /**< SCIP data structure */
2536  GRAPH* g, /**< graph data structure */
2537  int* nelims /**< pointer to number of reductions */
2538  )
2539 {
2540  int* marked;
2541  int nelims_local = 0;
2542  const int nnodes = graph_get_nNodes(g);
2543 
2544  assert(scip != NULL);
2545  assert(nelims != NULL);
2546  assert(graph_pc_isMw(g));
2547 
2548  SCIP_CALL( SCIPallocBufferArray(scip, &marked, nnodes) );
2549 
2550  for( int k = 0; k < nnodes; k++ )
2551  marked[k] = FALSE;
2552 
2553  /* check neighborhood of terminals */
2554  for( int k = 0; k < nnodes; k++ )
2555  {
2556  if( !g->mark[k] || LT(g->prize[k], 0.0) )
2557  continue;
2558 
2559  /* mark adjacent vertices of k */
2560  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
2561  if( g->mark[g->head[e]] )
2562  marked[g->head[e]] = TRUE;
2563 
2564  /* ... and traverse them */
2565  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
2566  {
2567  const int j = g->head[e];
2568 
2569  if( marked[j] )
2570  {
2571  int e2 = g->outbeg[j];
2572 
2573  while( e2 != EAT_LAST )
2574  {
2575  const int candedge = e2;
2576  e2 = g->oeat[e2];
2577  if( marked[g->head[candedge]] )
2578  {
2579  graph_edge_del(scip, g, candedge, TRUE);
2580  nelims_local++;
2581  }
2582  }
2583  }
2584  }
2585 
2586  for( int e = g->outbeg[k]; e != EAT_LAST; e = g->oeat[e] )
2587  marked[g->head[e]] = FALSE;
2588 
2589 #ifndef NDEBUG
2590  for( int j = 0; j < nnodes; j++ )
2591  assert(FALSE == marked[j]);
2592 #endif
2593  }
2594 
2595  *nelims = nelims_local;
2596 
2597  assert(graph_valid(scip, g));
2598  SCIPfreeBufferArray(scip, &marked);
2599 
2600  return SCIP_OKAY;
2601 }
2602 
2603 
2604 /** Combined implied-profit based tests:
2605  * First elimination tests are used, afterwards
2606  * edge contraction test are applied.
2607  * NOTE: The expensive part is to build the bottleneck distances,
2608  * thus we always apply all other tests. */
2610  SCIP* scip, /**< SCIP data structure */
2611  int edgelimit, /**< limit for star test */
2612  GRAPH* g, /**< graph structure */
2613  int* solnode, /**< node array to mark whether an node is part of a given solution (CONNECT) */
2614  SCIP_Real* fixed, /**< offset pointer */
2615  int* nelims /**< number of eliminations */
2616 )
2617 {
2618  SD* sdistance;
2619  int nelimsnew = 0;
2620  const int isPcMw = graph_pc_isPcMw(g);
2621 
2622  assert(scip && g && nelims && fixed);
2623  assert(*nelims >= 0);
2624 
2625  if( g->terms <= 2 )
2626  return SCIP_OKAY;
2627 
2628  /* NOTE: pruning is necessary, because we need remaining graph to be connected */
2629  if( isPcMw )
2630  {
2631  reduce_unconnectedRpcRmw(scip, g, fixed);
2632  }
2633  else
2634  {
2635  SCIP_CALL( reduce_unconnected(scip, g) );
2636  }
2637 
2638  SCIP_CALL( reduce_sdInitBiasedBottleneck(scip, g, &sdistance) );
2639 
2640  /* first call edge elimination tests */
2641  if( !isPcMw )
2642  {
2643  SCIP_CALL( reduce_sdBiased(scip, sdistance, g, &nelimsnew) );
2644  }
2645  SCIP_CALL( reduce_sdStarBiasedWithProfit(scip, edgelimit, sdistance->sdprofit, TRUE, g, &nelimsnew) );
2646 
2647  if( nelimsnew > 0 )
2648  {
2649  SCIP_CALL( reduce_sdprofitBuildFromBLC(scip, g, sdistance->blctree, FALSE, sdistance->sdprofit) );
2650  SCIP_CALL( graph_tpathsRecomputeBiased(sdistance->sdprofit, g, sdistance->terminalpaths) );
2651  *nelims += nelimsnew;
2652  }
2653 
2654  /* now call edge contraction tests */
2655  SCIP_CALL( reduce_nsvImplied(scip, sdistance, g, solnode, fixed, nelims) );
2656 
2657  reduce_sdFree(scip, &sdistance);
2658 
2659  return SCIP_OKAY;
2660 }
2661 
2662 
2663 /** similar to above, but for rooted-prize collecting Steiner tree problem */
2665  SCIP* scip, /**< SCIP data structure */
2666  GRAPH* g, /**< graph structure */
2667  REDSOLLOCAL* redsollocal, /**< primal bound info */
2668  SCIP_Real* fixed, /**< offset pointer */
2669  int* nelims /**< number of eliminations */
2670 )
2671 {
2672  STP_Vectype(int) contractedges = NULL;
2673  GRAPH* graph_spg;
2674  SD* sdistance;
2675  int* edgemap_new2org;
2676  int* solnode = reduce_sollocalGetSolnode(redsollocal);
2677  SCIP_Real fixednew = 0.0;
2678  int nelimsnew = 0;
2679  SCIP_Real primalbound;
2680 
2681  assert(scip && g && nelims && fixed);
2682 
2683  assert(*nelims >= 0);
2684  assert(g->stp_type == STP_RPCSPG);
2685 
2686  if( g->terms <= 2 )
2687  return SCIP_OKAY;
2688 
2689  reduce_sollocalSetOffset(*fixed, redsollocal);
2690  SCIP_CALL( reduce_sollocalRebuildTry(scip, g, redsollocal) );
2691  primalbound = reduce_sollocalGetUpperBound(redsollocal);
2692 
2693  if( GE(primalbound, FARAWAY) )
2694  return SCIP_OKAY;
2695 
2696  if( !graph_transRpcToSpgIsStable(g, primalbound) )
2697  return SCIP_OKAY;
2698 
2699  /* NOTE: pruning is necessary, because we need remaining graph to be connected */
2700  reduce_unconnectedRpcRmw(scip, g, fixed);
2701 
2702  assert(graph_valid(scip, g));
2703 
2704  graph_mark(g);
2705  SCIP_CALL( graph_transRpcGetSpg(scip, g, primalbound, &fixednew, &edgemap_new2org, &graph_spg) );
2706 
2707  SCIP_CALL( graph_path_init(scip, graph_spg) );
2708  SCIP_CALL( reduce_sdInitBiasedBottleneck(scip, graph_spg, &sdistance) );
2709  SCIP_CALL( reduce_sdBiased(scip, sdistance, graph_spg, &nelimsnew) );
2710 
2711  if( nelimsnew > 0 )
2712  {
2713  for( int i = 0; i < graph_spg->edges; i += 2 )
2714  {
2715  if( graph_spg->oeat[i] == EAT_FREE )
2716  {
2717  const int orgedge = edgemap_new2org[i];
2718  if( orgedge == -1 )
2719  {
2720  assert(Is_term(graph_spg->term[graph_spg->tail[i]]) || Is_term(graph_spg->term[graph_spg->head[i]]));
2721  continue;
2722  }
2723  assert(graph_edge_isInRange(g, orgedge));
2724 
2725 #ifdef SCIP_DEBUG
2726  printf("delete %d \n", orgedge);
2727  graph_edge_printInfo(g, orgedge);
2728 #endif
2729 
2730  graph_edge_del(scip, g, orgedge, TRUE);
2731  (*nelims)++;
2732  }
2733  }
2734 
2735  assert(graph_valid(scip, g));
2736 
2737  SCIP_CALL( reduce_sdprofitBuildFromBLC(scip, graph_spg, sdistance->blctree, FALSE, sdistance->sdprofit) );
2738  SCIP_CALL( graph_tpathsRecomputeBiased(sdistance->sdprofit, graph_spg, sdistance->terminalpaths) );
2739  }
2740 
2741  /* now call edge contraction tests */
2742  SCIP_CALL( reduce_nsvImpliedRecord(scip, sdistance, graph_spg, &contractedges) );
2743 
2744  for( int i = 0; i < StpVecGetSize(contractedges); i++ )
2745  {
2746  const int edge = contractedges[i];
2747  assert(graph_edge_isInRange(graph_spg, edge));
2748 
2749  if( edgemap_new2org[edge] != -1 )
2750  {
2751  const int orgedge = edgemap_new2org[edge];
2752  const int orgtail = g->tail[orgedge];
2753  const int orghead = g->head[orgedge];
2754 
2755  assert(graph_edge_isInRange(g, orgedge));
2756 
2757 #ifdef SCIP_DEBUG
2758  printf("try \n");
2759  graph_edge_printInfo(g, orgedge);
2760 #endif
2761 
2762  if( (graph_pc_knotIsFixedTerm(g, orgtail) || graph_pc_knotIsPropPotTerm(g, orgtail)) && g->source != orghead )
2763  {
2764  SCIPdebugMessage("contract %d \n", orgedge);
2765  *fixed += g->cost[orgedge];
2766  SCIP_CALL(graph_pc_contractEdge(scip, g, solnode, orgtail, orghead, orgtail));
2767  (*nelims)++;
2768 
2769  continue;
2770  }
2771 
2772  if( graph_pc_knotIsFixedTerm(g, orghead) || graph_pc_knotIsPropPotTerm(g, orghead) )
2773  {
2774  SCIPdebugMessage("contract %d \n", orgedge);
2775  *fixed += g->cost[orgedge];
2776  SCIP_CALL(graph_pc_contractEdge(scip, g, solnode, orghead, orgtail, orghead));
2777  (*nelims)++;
2778 
2779  continue;
2780  }
2781  }
2782  }
2783 
2784  StpVecFree(scip, contractedges);
2785 
2786  SCIPfreeMemoryArray(scip, &edgemap_new2org);
2787  graph_path_exit(scip, graph_spg);
2788  graph_free(scip, &graph_spg, FALSE);
2789  reduce_sdFree(scip, &sdistance);
2790 
2791  return SCIP_OKAY;
2792 }
#define STP_Vectype(type)
Definition: stpvector.h:44
void graph_knot_chg(GRAPH *, int, int)
Definition: graph_node.c:86
static SCIP_RETCODE nsvEdgeContract(SCIP *scip, int edge, int end_remain, int end_killed, GRAPH *g, NSV *nsv, int *nelims)
Definition: reduce_alt.c:497
static volatile int nterms
Definition: interrupt.c:38
#define StpVecGetSize(vec)
Definition: stpvector.h:139
SCIP_Bool graph_pc_isMw(const GRAPH *)
int *RESTRICT head
Definition: graphdefs.h:224
void graph_edge_del(SCIP *, GRAPH *, int, SCIP_Bool)
Definition: graph_edge.c:368
SCIP_RETCODE graph_knot_contractFixed(SCIP *, GRAPH *, int *, int, int, int)
Definition: graph_node.c:521
int source
Definition: graphdefs.h:195
void reduce_blctreeGetMstEdges(const GRAPH *, const BLCTREE *, int *)
Definition: reduce_util.c:1230
#define Is_term(a)
Definition: graphdefs.h:102
SCIP_RETCODE graph_voronoiWithDist(SCIP *, const GRAPH *, const SCIP_Bool *, const SCIP_Real *, double *, int *, int *, int *, int *, PATH *)
SCIP_RETCODE reduce_nsvImpliedRecord(SCIP *scip, const SD *sdistance, GRAPH *g, STP_Vectype(int) *edgerecord)
Definition: reduce_alt.c:643
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:117
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip_mem.h:71
signed int edge
Definition: graphdefs.h:287
SCIP_Bool graph_valid(SCIP *, const GRAPH *)
Definition: graph_base.c:1480
#define VERTEX_CONNECT
Definition: reduce_alt.c:48
void graph_getIsTermArray(const GRAPH *, SCIP_Bool *)
Definition: graph_base.c:540
int terms
Definition: graphdefs.h:192
SCIP_RETCODE reduce_sl(SCIP *scip, const int *edgestate, GRAPH *g, PATH *vnoi, SCIP_Real *fixed, int *vbase, int *vrnodes, STP_Bool *visited, int *solnode, int *nelims)
Definition: reduce_alt.c:665
void reduce_sollocalSetOffset(SCIP_Real, REDSOLLOCAL *)
Definition: reduce_sol.c:488
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
void graph_mark(GRAPH *)
Definition: graph_base.c:1130
void graph_knot_printInfo(const GRAPH *, int)
Definition: graph_stats.c:151
void graph_free(SCIP *, GRAPH **, SCIP_Bool)
Definition: graph_base.c:796
SCIP_RETCODE graph_path_init(SCIP *, GRAPH *)
Definition: graph_path.c:480
#define EAT_FREE
Definition: graphdefs.h:57
#define FALSE
Definition: def.h:87
#define VERTEX_TEMPNEIGHBOR
Definition: reduce_alt.c:49
SCIP_RETCODE reduce_sdprofitBuildFromBLC(SCIP *, const GRAPH *, const BLCTREE *, SCIP_Bool, SDPROFIT *)
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
SCIP_RETCODE reduce_impliedProfitBased(SCIP *scip, int edgelimit, GRAPH *g, int *solnode, SCIP_Real *fixed, int *nelims)
Definition: reduce_alt.c:2609
SCIP_RETCODE reduce_cnsAdv(SCIP *scip, GRAPH *g, int *marked, int *count)
Definition: reduce_alt.c:1793
void reduce_blctreeGetMstEdgesState(const GRAPH *, const BLCTREE *, SCIP_Bool *)
Definition: reduce_util.c:1315
#define StpVecPopBack(vec)
Definition: stpvector.h:182
#define EAT_LAST
Definition: graphdefs.h:58
#define STP_SPG
Definition: graphdefs.h:42
#define SCIPdebugMessage
Definition: pub_message.h:87
#define STP_RED_CNSNN
Definition: reduce_alt.c:52
#define FARAWAY
Definition: graphdefs.h:89
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
SCIP_RETCODE reduce_sollocalRebuildTry(SCIP *, GRAPH *, REDSOLLOCAL *)
Definition: reduce_sol.c:507
static void ansProcessCandidateWithBridge(SCIP *scip, GRAPH *g, int *RESTRICT marked, int *RESTRICT nelims, SCIP_Real maxprize, int candvertex, int bridgeedge)
Definition: reduce_alt.c:158
SCIP_VAR ** x
Definition: circlepacking.c:54
SCIP_Bool *RESTRICT candidates_isLink
Definition: reduce_alt.c:66
SCIP_RETCODE graph_tpathsRecomputeBiased(const SDPROFIT *, GRAPH *, TPATHS *)
Definition: graph_tpath.c:1776
int *RESTRICT mark
Definition: graphdefs.h:198
#define VERTEX_NEIGHBOR
Definition: reduce_alt.c:50
#define STP_RED_ANSMAXNEIGHBORS
Definition: reduce_alt.c:55
static SCIP_RETCODE nsvInitData(SCIP *scip, const SD *sdistance, const GRAPH *g, int *solnode, SCIP_Real *fixed, NSV *nsv)
Definition: reduce_alt.c:264
int *RESTRICT oeat
Definition: graphdefs.h:231
SCIP_RETCODE reduce_nv(SCIP *scip, GRAPH *g, PATH *vnoi, SCIP_Real *fixed, int *edgearrint, int *vbase, int *solnode, int *nelims)
Definition: reduce_alt.c:932
#define LE(a, b)
Definition: portab.h:83
#define GE(a, b)
Definition: portab.h:85
miscellaneous methods used for solving Steiner problems
int graph_get_nTerms(const GRAPH *)
Definition: graph_stats.c:560
SCIP_RETCODE reduce_nnp(SCIP *scip, GRAPH *g, int *nelims)
Definition: reduce_alt.c:2534
SCIP_Bool extended
Definition: graphdefs.h:267
int stp_type
Definition: graphdefs.h:264
SCIP_Bool graph_transRpcToSpgIsStable(const GRAPH *, SCIP_Real)
Definition: graph_trans.c:1188
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int * reduce_sollocalGetSolnode(REDSOLLOCAL *)
Definition: reduce_sol.c:651
SCIP_Real *RESTRICT candidates_headdist
Definition: reduce_alt.c:64
SCIP_RETCODE reduce_nsvImplied(SCIP *scip, const SD *sdistance, GRAPH *g, int *solnode, SCIP_Real *fixed, int *nelims)
Definition: reduce_alt.c:621
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:128
SCIP_Real * prize
Definition: graphdefs.h:210
void graph_edge_add(SCIP *, GRAPH *, int, int, double, double)
SCIP_Real dist
Definition: graphdefs.h:286
int *RESTRICT grad
Definition: graphdefs.h:201
SCIP_RETCODE reduce_unconnected(SCIP *, GRAPH *)
void graph_knot_add(GRAPH *, int)
Definition: graph_node.c:64
#define NULL
Definition: lpi_spx1.cpp:155
SCIP_RETCODE reduce_ansAdv2(SCIP *scip, GRAPH *g, int *nelims)
Definition: reduce_alt.c:1656
#define EQ(a, b)
Definition: portab.h:79
SCIP_RETCODE reduce_sdBiased(SCIP *, SD *, GRAPH *, int *)
Definition: reduce_sd.c:1840
void graph_knot_del(SCIP *, GRAPH *, int, SCIP_Bool)
Definition: graph_node.c:111
int knots
Definition: graphdefs.h:190
#define SCIP_CALL(x)
Definition: def.h:384
SCIP_RETCODE reduce_ansAdv(SCIP *scip, GRAPH *g, int *nelims, SCIP_Bool extneigbhood)
Definition: reduce_alt.c:1544
void reduce_sdFree(SCIP *, SD **)
SCIP_RETCODE graph_pc_contractEdge(SCIP *, GRAPH *, int *, int, int, int)
#define MST_MODE
Definition: graphdefs.h:98
#define STP_PCSPG
Definition: graphdefs.h:44
static void nsvFreeData(SCIP *scip, NSV *nsv)
Definition: reduce_alt.c:352
#define LT(a, b)
Definition: portab.h:81
SCIP_Bool graph_pc_knotIsPropPotTerm(const GRAPH *, int)
SCIP_Real *RESTRICT candidates_taildist
Definition: reduce_alt.c:63
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
#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
SCIP_RETCODE reduce_ans(SCIP *scip, GRAPH *g, int *nelims)
Definition: reduce_alt.c:1470
SCIP_Bool graph_edge_isDeleted(const GRAPH *, int)
Definition: graph_stats.c:121
int *RESTRICT tail
Definition: graphdefs.h:223
SCIP_RETCODE reduce_cutEdgeTryPrune(SCIP *, int, GRAPH *, SCIP_Bool *)
#define flipedge(edge)
Definition: graphdefs.h:84
#define MAX(x, y)
Definition: tclique_def.h:83
SCIP_RETCODE reduce_getSdByPaths(SCIP *, GRAPH *, PATH *, PATH *, SCIP_Real *, SCIP_Real, int *, int *, int *, int *, int *, int, int, int, SCIP_Bool, SCIP_Bool)
Definition: reduce_sd.c:2299
void graph_voronoiTerms(const GRAPH *, const SCIP_Bool *, int *RESTRICT, PATH *RESTRICT)
#define STP_TERM
Definition: graphdefs.h:61
SCIP_RETCODE reduce_sdInitBiasedBottleneck(SCIP *, GRAPH *, SD **)
int *RESTRICT term
Definition: graphdefs.h:196
void graph_edge_printInfo(const GRAPH *, int)
Definition: graph_stats.c:133
SCIP_Bool graph_pc_knotIsNonLeafTerm(const GRAPH *, int)
#define EDGE_BLOCKED
Definition: graphdefs.h:95
static void ansDeleteVertex(SCIP *scip, GRAPH *g, int *RESTRICT marked, int *RESTRICT nelims, int vertex)
Definition: reduce_alt.c:85
void graph_path_exit(SCIP *, GRAPH *)
Definition: graph_path.c:515
SCIP_Bool graph_pc_isPc(const GRAPH *)
SCIP_RETCODE reduce_chain2(SCIP *scip, GRAPH *g, PATH *pathtail, int *heap, int *statetail, int *statehead, int *nelims, int limit)
Definition: reduce_alt.c:2445
Portable definitions.
SCIP_RETCODE reduce_npv(SCIP *scip, GRAPH *g, PATH *pathtail, int *heap, int *statetail, int *statehead, int *nelims, int limit)
Definition: reduce_alt.c:2067
#define Is_pseudoTerm(a)
Definition: graphdefs.h:103
struct nearest_special_distance_test_data NSV
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static void nsvInitRecording(STP_Vectype(int) edgesrecord, NSV *nsv)
Definition: reduce_alt.c:337
SCIP_Bool graph_pc_knotIsDummyTerm(const GRAPH *, int)
static SCIP_RETCODE nsvExec(SCIP *scip, NSV *nsv, GRAPH *g, int *nelims)
Definition: reduce_alt.c:535
void reduce_blctreeGetMstEdgesToCutDist(const GRAPH *, const BLCTREE *, SCIP_Real *RESTRICT, SCIP_Real *RESTRICT)
SCIP_Bool graph_pc_knotIsFixedTerm(const GRAPH *, int)
SCIP_RETCODE reduce_unconnectedRpcRmw(SCIP *, GRAPH *, SCIP_Real *)
SCIP_Real * cost
Definition: graphdefs.h:221
SCIP_Bool graph_edge_isInRange(const GRAPH *, int)
Definition: graph_stats.c:110
SCIP_Bool graph_pc_isUnrootedPcMw(const GRAPH *)
int reduce_blctreeGetMstNedges(const BLCTREE *)
Definition: reduce_util.c:1218
static void ansProcessCandidate(SCIP *scip, GRAPH *g, int *RESTRICT marked, int *RESTRICT nelims, SCIP_Real maxprize, int candvertex)
Definition: reduce_alt.c:219
SCIP_Bool graph_pc_isPcMw(const GRAPH *)
#define SCIP_Real
Definition: def.h:177
static SCIP_Bool nsvEdgeIsValid(const GRAPH *g, const NSV *nsv, int edge)
Definition: reduce_alt.c:370
#define StpVecFree(scip, vec)
Definition: stpvector.h:153
int *RESTRICT outbeg
Definition: graphdefs.h:204
static void ansUnmark(const GRAPH *g, int basenode, const int *neighbarr, int nNeigbors, int *RESTRICT marked)
Definition: reduce_alt.c:111
SCIP_RETCODE reduce_sdStarBiasedWithProfit(SCIP *, int, const SDPROFIT *, SCIP_Bool, GRAPH *, int *)
Definition: reduce_sd.c:3348
int edges
Definition: graphdefs.h:219
int graph_get_nNodes(const GRAPH *)
Definition: graph_stats.c:536
void graph_pc_knotToFixedTerm(SCIP *, GRAPH *, int, SCIP_Real *)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define UNKNOWN
Definition: sepa_mcf.c:4095
void graph_tpathsGet4CloseTermsLE(const GRAPH *, const TPATHS *, int, SCIP_Real, int *RESTRICT, int *RESTRICT, SCIP_Real *RESTRICT, int *RESTRICT)
#define STP_RED_ANSEXMAXCANDS
Definition: reduce_alt.c:54
#define nnodes
Definition: gastrans.c:65
#define StpVecPushBack(scip, vec, value)
Definition: stpvector.h:167
#define VERTEX_OTHER
Definition: reduce_alt.c:51
SCIP_RETCODE graph_init(SCIP *, GRAPH **, int, int, int)
Definition: graph_base.c:607
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:123
SCIP_RETCODE graph_transRpcGetSpg(SCIP *, const GRAPH *, SCIP_Real, SCIP_Real *, int **, GRAPH **)
Definition: graph_trans.c:1217
SCIP_RETCODE reduce_impliedProfitBasedRpc(SCIP *scip, GRAPH *g, REDSOLLOCAL *redsollocal, SCIP_Real *fixed, int *nelims)
Definition: reduce_alt.c:2664
static void nsvEdgeGetTermDists(const GRAPH *g, const NSV *nsv, int edge, int candidate_id, SCIP_Real *dist_tail, SCIP_Real *dist_head)
Definition: reduce_alt.c:400
#define Is_anyTerm(a)
Definition: graphdefs.h:105
SCIP_Real *RESTRICT candidates_bottleneck
Definition: reduce_alt.c:62
includes various reduction methods for Steiner tree problems
SCIP_Real reduce_sollocalGetUpperBound(const REDSOLLOCAL *)
Definition: reduce_sol.c:633
#define STP_RPCSPG
Definition: graphdefs.h:45
void reduce_blctreeGetMstBottlenecks(const GRAPH *, const BLCTREE *, SCIP_Real *)
Definition: reduce_util.c:1349
#define STP_MWCSP
Definition: graphdefs.h:51
SCIP callable library.
#define STP_RED_ANSMAXCANDS
Definition: reduce_alt.c:53
SCIP_RETCODE reduce_nvAdv(SCIP *scip, const int *edgestate, GRAPH *g, PATH *vnoi, SCIP_Real *distance, SCIP_Real *fixed, int *edgearrint, int *vbase, int *distnode, int *solnode, int *nelims)
Definition: reduce_alt.c:1121