Scippy

SCIP

Solving Constraint Integer Programs

heur_lurkprune.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 heur_lurkprune.c
17  * @brief lurking-bounds reduction based primal heuristic for Steiner problems
18  * @author Daniel Rehfeldt
19  *
20  * This file implements a reduction based heuristic for Steiner problems that makes use of lurking bounds.
21  *
22  * A list of all interface methods can be found in heur_lurkprune.h
23  *
24  */
25 
26 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
27 #define SCIP_DEBUG
28 #include <assert.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include "scip/scip.h"
32 #include "scip/scipdefplugins.h"
33 #include "scip/cons_linear.h"
34 #include "heur_lurkprune.h"
35 #include "heur_ascendprune.h"
36 #include "dualascent.h"
37 #include "heur_local.h"
38 #include "heur_prune.h"
39 #include "graph.h"
40 #include "reduce.h"
41 #include "heur_tm.h"
42 #include "solstp.h"
43 #include "cons_stp.h"
44 #include "probdata_stp.h"
45 #include "prop_stp.h"
46 
47 #define HEUR_NAME "lurkprune"
48 #define HEUR_DESC "Reduction based heuristic for Steiner problems"
49 #define HEUR_DISPCHAR 'L'
50 #define HEUR_PRIORITY 1
51 #define HEUR_FREQ 1
52 #define HEUR_FREQOFS 0
53 #define HEUR_MAXDEPTH -1
54 #define HEUR_TIMING (SCIP_HEURTIMING_DURINGLPLOOP | SCIP_HEURTIMING_AFTERLPLOOP | SCIP_HEURTIMING_AFTERNODE)
55 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
56 
57 #define DEFAULT_LURKPRUNE_MAXFREQ FALSE /**< executions of the heuristic at maximum frequency? */
58 #define LURKPRUNE_NTMRUNS 30 /**< TM heur runs */
59 #define LURKPRUNE_MINREDELIMS 10 /**< minimum number of eliminations for reduction package when called by lurk-and-prune heuristic */
60 #define LURKPRUNE_MAXREDROUNDS 10 /**< maximum number of reduction rounds in lurk-prune heuristic */
61 #define LURKPRUNE_MINLURKEDGE_RATIO 0.05
62 #define LURKPRUNE_MINSTALLPROPORTION 0.25 /**< minimum proportion of arcs to be fixed before restarting lurk-prune heuristic */
63 #define LURKPRUNE_MAXSTALLPROPORTION 0.5 /**< maximum proportion of arcs to be fixed before restarting lurk-prune heuristic */
64 #define LURK_MAXTOTNEDGES 5000
65 
66 /*
67  * Data structures
68  */
69 
70 /** primal heuristic data */
71 struct SCIP_HeurData
72 {
73  int lastnfixededges; /**< number of fixed edges before the previous run */
74  int nfailures; /**< number of failures since last successful call */
75  SCIP_Bool maxfreq; /**< should the heuristic be called at maximum frequency? */
76 };
77 
78 
79 /** data */
80 typedef struct lurking_prune
81 {
82  int* solnode;
83  int* soledge;
92 } LURKPRUNE;
93 
94 
95 
96 /*
97  * Local methods
98  */
99 
100 
101 /** initializes prune graph */
102 static
104  SCIP* scip, /**< SCIP data structure */
105  const GRAPH* g, /**< graph */
106  GRAPH** prunegraph /**< graph */
107 )
108 {
109  SCIP_CALL( graph_copy(scip, g, prunegraph) );
110  SCIP_CALL( graph_initHistory(scip, *prunegraph) );
111  if( graph_pc_isPcMw(g) )
112  (*prunegraph)->norgmodelknots = (*prunegraph)->knots;
113  SCIP_CALL( graph_path_init(scip, *prunegraph) );
114  graph_mark(*prunegraph);
115 
116  return SCIP_OKAY;
117 }
118 
119 
120 /** initializes */
121 static
123  SCIP* scip, /**< SCIP data structure */
124  const GRAPH* g, /**< graph */
125  const SCIP_Real* lurkingbounds, /**< lurking edge bounds */
126  int* soledge, /**< array to 1. provide and 2. return primal solution */
127  LURKPRUNE* lurkprune, /**< lurking-prune data */
128  GRAPH** prunegraph /**< graph */
129  )
130 {
131  SCIP_Real* lurkingbounds_half;
132  int* solnode;
133  int* globalsoledge;
134  const int nnodes = graph_get_nNodes(g);
135  const int nedges = graph_get_nEdges(g);
136  int nedges_red;
137 
138  SCIP_CALL( prunegraphInit(scip, g, prunegraph) );
139 
140  SCIP_CALL( SCIPallocBufferArray(scip, &globalsoledge, nedges) );
141  SCIP_CALL( SCIPallocBufferArray(scip, &lurkingbounds_half, nedges / 2) );
142  SCIP_CALL( SCIPallocBufferArray(scip, &solnode, nnodes) );
143 
144  BMScopyMemoryArray(globalsoledge, soledge, nedges);
145 
146  for( int k = 0; k < nnodes; k++ )
147  solnode[k] = UNKNOWN;
148 
149  for( int e = 0; e < nedges; e++ )
150  {
151  if( soledge[e] == UNKNOWN )
152  continue;
153 
154  assert(CONNECT == soledge[e]);
155 
156  solnode[g->tail[e]] = CONNECT;
157  solnode[g->head[e]] = CONNECT;
158  }
159 
160  for( int e = 0; e < nedges; e += 2 )
161  {
162  const SCIP_Real min = MIN(lurkingbounds[e], lurkingbounds[e + 1]);
163  assert(GE(min, 0.0) || EQ(min, -FARAWAY));
164 
165  lurkingbounds_half[e / 2] = min;
166  }
167 
168  graph_get_nVET(g, NULL, &nedges_red, NULL);
169 
170  lurkprune->minlurkelims = (nedges_red / 2) * LURKPRUNE_MINLURKEDGE_RATIO;
171  lurkprune->ubbest = solstp_getObjBounded(g, soledge, 0.0, nedges);
172  lurkprune->globalobj = lurkprune->ubbest;
173  lurkprune->offsetnew = 0.0;
174 
175  lurkprune->globalsoledge = globalsoledge;
176  lurkprune->lurkingbounds_half = lurkingbounds_half;
177  lurkprune->solnode = solnode;
178  lurkprune->soledge = soledge;
179  lurkprune->obj_old = solstp_getObj(g, soledge, 0.0);
180 
181 #ifdef SCIP_DEBUG
182  SCIPdebugMessage("lurking-prune starts \n");
184 #endif
185 
186  return SCIP_OKAY;
187 }
188 
189 
190 /** finalizes */
191 static
193  SCIP* scip, /**< SCIP data structure */
194  const GRAPH* g, /**< graph */
195  GRAPH* prunegraph, /**< graph */
196  int* soledge, /**< array to 1. provide and 2. return primal solution */
197  LURKPRUNE* lurkprune, /**< lurking-prune data */
198  SCIP_Bool* solimproved /**< could a better solution be found? */
199  )
200 {
201  const int nedges = graph_get_nEdges(prunegraph);
202  const SCIP_Real obj_new = solstp_getObj(g, lurkprune->globalsoledge, 0.0);
203  const SCIP_Real obj_old = lurkprune->obj_old;
204 
205  SCIPdebugMessage("lurk-prune: obj_old=%f obj_new=%f \n", obj_old, obj_new);
206  *solimproved = (LT(obj_new, obj_old));
207 
208  graph_path_exit(scip, prunegraph);
209  BMScopyMemoryArray(soledge, lurkprune->globalsoledge, nedges);
210 
211  graph_free(scip, &prunegraph, TRUE);
212  SCIPfreeBufferArray(scip, &(lurkprune->solnode));
213  SCIPfreeBufferArray(scip, &(lurkprune->lurkingbounds_half));
214  SCIPfreeBufferArray(scip, &(lurkprune->globalsoledge));
215 }
216 
217 
218 /** does exact reductions */
219 static
221  SCIP* scip, /**< SCIP data structure */
222  LURKPRUNE* lurkprune, /**< lurking-prune data */
223  GRAPH* prunegraph /**< graph data structure */
224  )
225 {
226  REDSOL* redsol;
227  PATH* vnoi;
228  PATH* path;
229  SCIP_Real* nodearrreal;
230  int* heap;
231  int* state;
232  int* vbase;
233  int* nodearrint;
234  int* edgearrint;
235  int* nodearrint2;
236  STP_Bool* nodearrchar;
237  const int nnodes = graph_get_nNodes(prunegraph);
238  const int nedges = graph_get_nEdges(prunegraph);
239 
240  SCIP_CALL( SCIPallocBufferArray(scip, &nodearrchar, nnodes + 1) );
241  SCIP_CALL( SCIPallocBufferArray(scip, &heap, nnodes + 1) );
242  SCIP_CALL( SCIPallocBufferArray(scip, &state, 4 * nnodes) );
243  SCIP_CALL( SCIPallocBufferArray(scip, &nodearrreal, nnodes) );
244  SCIP_CALL( SCIPallocBufferArray(scip, &vbase, 4 * nnodes) );
245  SCIP_CALL( SCIPallocBufferArray(scip, &nodearrint, nnodes + 1) );
246  SCIP_CALL( SCIPallocBufferArray(scip, &edgearrint, nedges) );
247  SCIP_CALL( SCIPallocBufferArray(scip, &nodearrint2, nnodes + 1) );
248  SCIP_CALL( SCIPallocBufferArray(scip, &vnoi, 4 * nnodes) );
249  SCIP_CALL( SCIPallocBufferArray(scip, &path, nnodes + 1) );
250 
251  SCIP_CALL( reduce_solInit(scip, prunegraph, FALSE, &(redsol)) );
252 
253  if( graph_pc_isPc(prunegraph) )
254  {
255  SCIP_CALL( reduce_redLoopPc(scip, redsol, prunegraph, vnoi, path, nodearrreal, heap, state,
256  vbase, nodearrint, edgearrint, nodearrint2, nodearrchar,
258  }
259  else if( graph_pc_isMw(prunegraph) )
260  {
261  SCIP_CALL( reduce_redLoopMw(scip, redsol, prunegraph, vnoi, nodearrreal, state,
262  vbase, nodearrint, nodearrchar,
264  }
265  else
266  {
267  RPARAMS parameters = { .dualascent = FALSE, .boundreduce = FALSE, .nodereplacing = TRUE, .reductbound_min = LURKPRUNE_MINREDELIMS,
268  .reductbound = LURKPRUNE_MINREDELIMS, .userec = FALSE, .fullreduce = FALSE, .usestrongreds = TRUE };
269 
270  REDBASE redbase = { .redparameters = &parameters, .bidecompparams = NULL,
271  .solnode = NULL, .redsol = redsol,
272  .vnoi = vnoi, .path = path, .heap = heap,
273  .nodearrreal = nodearrreal,
274  .state = state, .vbase = vbase, .nodearrint = nodearrint,
275  .edgearrint = edgearrint, .nodearrint2 = nodearrint2, .nodearrchar = nodearrchar };
276 
277  SCIP_CALL( reduce_redLoopStp(scip, prunegraph, &redbase) );
278  }
279 
280  (lurkprune->offsetnew) = reduce_solGetOffset(redsol);
281  reduce_solFree(scip, &(redsol));
282 
283  SCIPfreeBufferArray(scip, &path);
284  SCIPfreeBufferArray(scip, &vnoi);
285  SCIPfreeBufferArray(scip, &nodearrint2);
286  SCIPfreeBufferArray(scip, &edgearrint);
287  SCIPfreeBufferArray(scip, &nodearrint);
288  SCIPfreeBufferArray(scip, &vbase);
289  SCIPfreeBufferArray(scip, &nodearrreal);
290  SCIPfreeBufferArray(scip, &state);
291  SCIPfreeBufferArray(scip, &heap);
292  SCIPfreeBufferArray(scip, &nodearrchar);
293 
294  return SCIP_OKAY;
295 }
296 
297 
298 /** does heuristic reductions */
299 static
301  SCIP* scip, /**< SCIP data structure */
302  LURKPRUNE* lurkprune, /**< lurking-prune data */
303  GRAPH* prunegraph, /**< graph data structure */
304  SCIP_Bool* success /**< could enough edges be removed? */
305  )
306 {
307  IDX** ancestors = prunegraph->ancestors;
308  int* lurkhalfedges;
309  SCIP_Real* lurkingbounds_local;
310  const SCIP_Real* lurkingbounds_half = lurkprune->lurkingbounds_half;
311  const int* soledge = lurkprune->soledge;
312  const int nedges = graph_get_nEdges(prunegraph);
313  int i;
314  int nelims = 0;
315  const int nelims_min = lurkprune->minlurkelims;
316  const SCIP_Bool isPcMw = graph_pc_isPcMw(prunegraph);
317 
318  assert(ancestors && lurkingbounds_half && soledge);
319  assert(solstp_isValid(scip, prunegraph, soledge));
320 
321  *success = FALSE;
322 
323  SCIP_CALL( SCIPallocBufferArray(scip, &lurkhalfedges, nedges / 2) );
324  SCIP_CALL( SCIPallocBufferArray(scip, &lurkingbounds_local, nedges / 2) );
325 
326  /* get averaged lurking ancestor bounds */
327  for( i = 0; i < nedges / 2; i++ )
328  {
329  SCIP_Real bound = 0;
330  int nancestors = 0;
331  const int edge = i * 2;
332 
333  for( IDX* curr = ancestors[edge]; curr != NULL; curr = curr->parent )
334  {
335  const int edge_ancestor = curr->index;
336  assert(graph_edge_isInRange(prunegraph, edge_ancestor));
337 
338  bound += lurkingbounds_half[edge_ancestor / 2];
339  nancestors++;
340  }
341 
342  if( nancestors != 0 )
343  {
344  bound /= (SCIP_Real) nancestors;
345  }
346  else
347  {
348  assert(graph_edge_isDeleted(prunegraph, edge));
349  }
350 
351  lurkingbounds_local[i] = bound;
352  lurkhalfedges[i] = i;
353  }
354 
355  SCIPsortDownRealInt(lurkingbounds_local, lurkhalfedges, nedges / 2);
356 
357  SCIPdebugMessage("first/last %f %f \n", lurkingbounds_local[0], lurkingbounds_local[nedges / 2 - 1]);
358 
359  for( i = 0; i < nedges / 2; i++ )
360  {
361  const int edge = lurkhalfedges[i] * 2;
362  const int edge_rev = edge + 1;
363 
364  assert(flipedge(edge) == edge_rev);
365  assert(graph_edge_isDeleted(prunegraph, edge) == graph_edge_isDeleted(prunegraph, edge_rev));
366 
367  if( graph_edge_isDeleted(prunegraph, edge) )
368  continue;
369 
370  if( soledge[edge] == CONNECT || soledge[edge_rev] == CONNECT )
371  continue;
372 
373  if( isPcMw && graph_pc_edgeIsExtended(prunegraph, edge) )
374  continue;
375 
376  graph_edge_del(scip, prunegraph, edge, TRUE);
377  nelims++;
378 
379  if( nelims >= nelims_min )
380  {
381  *success = TRUE;
382  break;
383  }
384  }
385 
386  SCIP_CALL( reduce_unconnected(scip, prunegraph) );
387  assert(graph_valid(scip, prunegraph));
388 
389  SCIPfreeBufferArray(scip, &lurkingbounds_local);
390  SCIPfreeBufferArray(scip, &lurkhalfedges);
391 
392 #ifdef SCIP_DEBUG
393  SCIPdebugMessage("reduce-lurk: nelims=%d nelims_min=%d \n", nelims, nelims_min);
394  graph_printInfoReduced(prunegraph);
395 #endif
396 
397  return SCIP_OKAY;
398 }
399 
400 
401 /** delete fixed edges */
402 static
404  SCIP* scip, /**< SCIP data structure */
405  SCIP_VAR** vars, /**< problem variables or NULL */
406  const int* soledge, /**< primal solution */
407  GRAPH* prunegraph /**< graph data structure */
408  )
409 {
410  const int nedges = graph_get_nEdges(prunegraph);
411  int nfixededges = 0;
412  const SCIP_Bool isPcMw = graph_pc_isPcMw(prunegraph);
413 
414  /* delete fixed edges from the new graph */
415  for( int e = 0; e < nedges; e += 2 )
416  {
417  /* both e and its anti-parallel edge fixed to zero? */
418  if( SCIPvarGetUbLocal(vars[e]) < 0.5 && SCIPvarGetUbLocal(vars[e + 1]) < 0.5
419  && soledge[e] != CONNECT && soledge[e + 1] != CONNECT )
420  {
421  if( isPcMw && graph_pc_edgeIsExtended(prunegraph, e) )
422  continue;
423 
424  graph_edge_del(scip, prunegraph, e, TRUE);
425  nfixededges++;
426  }
427  }
428  SCIPdebugMessage("fixed edges in lurk and prune: %d \n", nfixededges);
429 }
430 
431 
432 /** updates */
433 static
435  SCIP* scip, /**< SCIP data structure */
436  GRAPH* g, /**< graph data structure */
437  LURKPRUNE* lurkprune, /**< lurking-prune data */
438  GRAPH* prunegraph /**< graph data structure */
439 )
440 {
441  /* compute potential new guiding solution */
442  //
443  SCIP_Bool success;
444  SCIP_Real obj;
445  int* soledge = lurkprune->soledge;
446  int* solnode = lurkprune->solnode;
447 
449  {
450  SCIP_Real* redcost;
451  DAPARAMS daparams = { .addcuts = FALSE, .ascendandprune = FALSE, .root = prunegraph->source,
452  .is_pseudoroot = FALSE, .damaxdeviation = -1.0 };
453  obj = 0.0;
454 
455 
456  SCIP_CALL( SCIPallocBufferArray(scip, &redcost, g->edges) );
457 
458  SCIP_CALL( dualascent_exec(scip, g, NULL, &daparams, redcost, &obj) );
459 
460  SCIP_CALL( SCIPStpHeurAscendPruneRun(scip, NULL, prunegraph, redcost, soledge, -1, &success, FALSE) );
461  {
462  // todo
463  // int todo; // do reducctions based on redcost
464  }
465  SCIPfreeBufferArray(scip, &redcost);
466  }
467  else
468  {
469  int* starts;
470  int nruns = LURKPRUNE_NTMRUNS;
471 
472  SCIP_CALL( SCIPallocBufferArray(scip, &starts, prunegraph->knots) );
473  SCIPStpHeurTMCompStarts(prunegraph, starts, &nruns);
474 
475  SCIP_CALL( SCIPStpHeurTMRun(scip, pcmode_fromheurdata, prunegraph, starts, NULL, soledge, nruns,
476  prunegraph->source, prunegraph->cost, prunegraph->cost, NULL, NULL, &success));
477 
478  SCIPfreeBufferArray(scip, &starts);
479  }
480 
481  SCIP_CALL( SCIPStpHeurLocalRun(scip, prunegraph, soledge) );
482 
483  assert(solstp_isValid(scip, prunegraph, soledge));
484 
485  SCIP_CALL( SCIPStpHeurPruneUpdateSols(scip, g, prunegraph, solnode, soledge,
486  lurkprune->globalsoledge, &(lurkprune->globalobj), TRUE, &success) );
487 
488  obj = solstp_getObj(prunegraph, soledge, lurkprune->offsetnew);
489 
490  /* obj < incumbent objective value? */
491  if( LT(obj, lurkprune->ubbest) )
492  lurkprune->ubbest = obj;
493 
494  SCIPdebugMessage("old solution: %f new solution %f \n\n", lurkprune->ubbest, obj);
495 
496  return SCIP_OKAY;
497 }
498 
499 
500 /*
501  * Callback methods of primal heuristic
502  */
503 
504 
505 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
506 static
507 SCIP_DECL_HEURCOPY(heurCopyLurkPrune)
508 { /*lint --e{715}*/
509  assert(scip != NULL);
510  assert(heur != NULL);
511  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
512 
513  /* call inclusion method of primal heuristic */
515 
516  return SCIP_OKAY;
517 }
518 
519 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
520 static
521 SCIP_DECL_HEURFREE(heurFreeLurkPrune)
522 { /*lint --e{715}*/
523  SCIP_HEURDATA* heurdata;
524 
525  assert(heur != NULL);
526  assert(scip != NULL);
527 
528  /* get heuristic data */
529  heurdata = SCIPheurGetData(heur);
530  assert(heurdata != NULL);
531 
532  /* free heuristic data */
533  SCIPfreeMemory(scip, &heurdata);
534  SCIPheurSetData(heur, NULL);
535 
536  return SCIP_OKAY;
537 }
538 
539 
540 /** initialization method of primal heuristic (called after problem was transformed) */
541 
542 static
543 SCIP_DECL_HEURINIT(heurInitLurkPrune)
544 { /*lint --e{715}*/
545 
546 
547  return SCIP_OKAY;
548 }
549 
550 
551 /** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
552 static
553 SCIP_DECL_HEURINITSOL(heurInitsolLurkPrune)
554 { /*lint --e{715}*/
555  SCIP_HEURDATA* heurdata;
556 
557  assert(heur != NULL);
558  assert(scip != NULL);
559 
560  /* get heuristic's data */
561  heurdata = SCIPheurGetData(heur);
562 
563  assert(heurdata != NULL);
564 
565  heurdata->nfailures = 0;
566  heurdata->lastnfixededges = -1;
567 
568  return SCIP_OKAY;
569 }
570 
571 
572 /** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
573 static
574 SCIP_DECL_HEUREXITSOL(heurExitsolLurkPrune)
575 { /*lint --e{715}*/
576 
577 
578  return SCIP_OKAY;
579 }
580 
581 
582 /** execution method of primal heuristic */
583 static
584 SCIP_DECL_HEUREXEC(heurExecLurkPrune)
585 { /*lint --e{715}*/
586  SCIP_HEURDATA* heurdata;
587  SCIP_PROBDATA* probdata;
588  SCIP_VAR** vars;
589  SCIP_SOL* bestsol;
590  GRAPH* graph;
591  SCIP_Real* xval;
592  SCIP_Bool success;
593  int nedges;
594  int* soledge;
595 
596  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
597 
598  heurdata = SCIPheurGetData(heur);
599  probdata = SCIPgetProbData(scip);
600  graph = SCIPprobdataGetGraph(probdata);
601 
602  assert(heurdata && probdata && graph);
603 
604  nedges = graph->edges;
605  *result = SCIP_DIDNOTRUN;
606 
607  return SCIP_OKAY;
608 
609  if( !graph_pc_isPcMw(graph) && !graph_typeIsSpgLike(graph) )
610  return SCIP_OKAY;
611 
612  if( !(heurdata->maxfreq) && heurdata->nfailures > 0 )
613  return SCIP_OKAY;
614 
615  bestsol = SCIPgetBestSol(scip);
616 
617  /* no solution available? */
618  if( bestsol == NULL )
619  return SCIP_OKAY;
620 
621  /* heuristic not at maximum or ...*/
622  if( !heurdata->maxfreq )
623  {
624  if( heurdata->lastnfixededges >= 0 )
625  {
626  SCIP_Real stallproportion;
627 
628  stallproportion = (1.0 + heurdata->nfailures) * LURKPRUNE_MINSTALLPROPORTION;
629 
630  if( SCIPisGT(scip, stallproportion, LURKPRUNE_MAXSTALLPROPORTION) )
631  stallproportion = LURKPRUNE_MAXSTALLPROPORTION;
632 
633  if( (SCIPStpNfixedEdges(scip) - heurdata->lastnfixededges) < (int) (stallproportion * nedges) )
634  return SCIP_OKAY;
635  }
636  }
637 
638  /* deactivate as expensive is too expensive to be reiterated todo: do this properly */
639  heurdata->nfailures = 1;
640 
641  xval = SCIPprobdataGetXval(scip, bestsol);
642 
643  if( xval == NULL )
644  return SCIP_OKAY;
645 
646  heurdata->lastnfixededges = SCIPStpNfixedEdges(scip);
647 
648  vars = SCIPprobdataGetVars(scip);
649  assert(vars != NULL);
650 
651  /* allocate array to store primal solution */
652  SCIP_CALL( SCIPallocBufferArray(scip, &soledge, nedges) );
653 
654  for( int e = 0; e < nedges; e++ )
655  {
656  if( EQ(xval[e], 1.0) )
657  soledge[e] = CONNECT;
658  else
659  soledge[e] = UNKNOWN;
660  }
661 
662  /* execute lurkprune heuristic */
663  SCIP_CALL( SCIPStpHeurLurkPruneRun(scip, vars, NULL, graph, FALSE, (graph->edges < LURK_MAXTOTNEDGES), soledge, &success) );
664 
665  /* solution found by lurkprune heuristic? */
666  if( success )
667  {
668  SCIP_Real pobj = 0.0;
669  SCIP_Real* nval;
670 
671  assert(SCIPprobdataGetNVars(scip) == nedges);
672 
673  /* allocate memory to store solution */
674  SCIP_CALL( SCIPallocBufferArray(scip, &nval, nedges) );
675 
676  for( int e = 0; e < nedges; e++ )
677  {
678  if( soledge[e] == CONNECT )
679  {
680  nval[e] = 1.0;
681  pobj += graph->cost[e];
682  }
683  else
684  {
685  nval[e] = 0.0;
686  }
687  }
688 
689  SCIPdebugMessage("SP final solution: best: old %f, new %f \n", SCIPgetSolOrigObj(scip, bestsol), pobj + SCIPprobdataGetOffset(scip));
690 
691  /* try to add new solution to pool */
692  SCIP_CALL( SCIPprobdataAddNewSol(scip, nval, heur, &success) );
693 
694  /* has solution been added? */
695  if( success )
696  {
697  SCIPdebugMessage("better solution added by LURKPRUNE %f \n", pobj + SCIPprobdataGetOffset(scip));
698  *result = SCIP_FOUNDSOL;
699  assert(solstp_isValid(scip, graph, soledge));
700 
701  /* is the solution the new incumbent? */
702  if( SCIPisLT(scip, SCIPgetSolOrigObj(scip, bestsol) - SCIPprobdataGetOffset(scip), pobj) )
703  success = FALSE;
704  }
705 
706  /* free memory */
707  SCIPfreeBufferArray(scip, &nval);
708  }
709  else
710  {
711  SCIPdebugMessage("lurk-prune: solution not valid \n");
712  }
713 
714  /* solution could not be found, added or is not best? */
715  if( !success )
716  heurdata->nfailures++;
717 
718  /* free memory */
719  SCIPfreeBufferArray(scip, &soledge);
720  SCIPdebugMessage("leaving lurk and prune heuristic \n");
721 
722  return SCIP_OKAY;
723 }
724 
725 
726 /*
727  * primal heuristic specific interface methods
728  */
729 
730 /** execute lurk-and-prune heuristic on given graph */
732  SCIP* scip, /**< SCIP data structure */
733  SCIP_VAR** vars, /**< problem variables or NULL */
734  const SCIP_Real* lurkingbounds, /**< lurking edge bounds */
735  GRAPH* g, /**< graph data structure */
736  SCIP_Bool initialreduce, /**< try to reduce graph initially? */
737  SCIP_Bool ascendprune, /**< use ascend-prune? */
738  int* soledge, /**< array to 1. provide and 2. return primal solution */
739  SCIP_Bool* solimproved /**< could a better solution be found? */
740  )
741 {
742  LURKPRUNE lurkprune;
743  GRAPH *prunegraph;
744 
745  assert(scip && soledge && solimproved && lurkingbounds);
746  assert(!graph_pc_isPcMw(g) || g->extended);
747  assert(solstp_isValid(scip, g, soledge));
748 
749  *solimproved = FALSE;
750  SCIP_CALL( lurkpruneInit(scip, g, lurkingbounds, soledge, &lurkprune, &prunegraph) );
751 
752  if( vars != NULL )
753  {
754  reduceFixedVars(scip, vars, soledge, prunegraph);
755  }
756 
757  /* perform initial reductions? */
758  if( initialreduce )
759  {
760  SCIP_CALL( reduceExact(scip, &lurkprune, prunegraph) );
761  SCIP_CALL( updateSolution(scip, g, &lurkprune, prunegraph) );
762  }
763 
764  /* main reduction loop */
765  for( int i = 0; i < LURKPRUNE_MAXREDROUNDS && g->terms > 2; i++ )
766  {
767  SCIP_Bool lurksuccess;
768 
769  SCIPdebugMessage("starting round %d \n", i);
770 
771  SCIP_CALL( reduceLurk(scip, &lurkprune, prunegraph, &lurksuccess) );
772  SCIP_CALL( reduceExact(scip, &lurkprune, prunegraph) );
773  SCIP_CALL( updateSolution(scip, g, &lurkprune, prunegraph) );
774 
775  if( !lurksuccess )
776  {
777  SCIPdebugMessage("breaking early \n");
778  break;
779  }
780  }
781 
782  lurkpruneFinalize(scip, g, prunegraph, soledge, &lurkprune, solimproved);
783  assert(solstp_isValid(scip, g, soledge));
784 
785  //exit(1);
786 
787  return SCIP_OKAY;
788 }
789 
790 
791 /** creates the lurkprune primal heuristic and includes it in SCIP */
793  SCIP* scip /**< SCIP data structure */
794  )
795 {
796  SCIP_HEURDATA* heurdata;
797  SCIP_HEUR* heur;
798 
799  /* create lurkprune primal heuristic data */
800  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
801 
802  /* include primal heuristic */
803  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
805  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecLurkPrune, heurdata) );
806 
807  assert(heur != NULL);
808 
809  /* set non fundamental callbacks via setter functions */
810  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyLurkPrune) );
811  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeLurkPrune) );
812  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitLurkPrune) );
813  SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolLurkPrune) );
814  SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolLurkPrune) );
815 
816  /* add lurkprune primal heuristic parameters */
817  SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/"HEUR_NAME"/maxfreq",
818  "should the heuristic be executed at maximum frequeny?",
819  &heurdata->maxfreq, FALSE, DEFAULT_LURKPRUNE_MAXFREQ, NULL, NULL) );
820 
821 
822  return SCIP_OKAY;
823 }
SCIP_RETCODE SCIPsetHeurExitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXITSOL((*heurexitsol)))
Definition: scip_heur.c:233
int graph_get_nEdges(const GRAPH *)
Definition: graph_stats.c:548
static SCIP_RETCODE prunegraphInit(SCIP *scip, const GRAPH *g, GRAPH **prunegraph)
SCIP_Real obj_old
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
int source
Definition: graphdefs.h:195
static SCIP_DECL_HEUREXITSOL(heurExitsolLurkPrune)
SCIP_Bool graph_pc_isRootedPcMw(const GRAPH *)
SCIP_RETCODE SCIPStpHeurPruneUpdateSols(SCIP *scip, GRAPH *g, GRAPH *prunegraph, int *solnode, int *soledge, int *globalsoledge, SCIP_Real *globalobj, SCIP_Bool incumbentgiven, SCIP_Bool *success)
Definition: heur_prune.c:489
Constraint handler for Steiner problems.
int SCIPStpNfixedEdges(SCIP *scip)
Definition: prop_stp.c:2467
SCIP_Bool graph_valid(SCIP *, const GRAPH *)
Definition: graph_base.c:1480
#define LURKPRUNE_NTMRUNS
SCIP_RETCODE reduce_solInit(SCIP *, const GRAPH *, SCIP_Bool, REDSOL **)
Definition: reduce_sol.c:687
int terms
Definition: graphdefs.h:192
static long bound
SCIP_VAR ** SCIPprobdataGetVars(SCIP *scip)
SCIP_RETCODE reduce_redLoopPc(SCIP *, REDSOL *, GRAPH *, PATH *, PATH *, SCIP_Real *, int *, int *, int *, int *, int *, int *, STP_Bool *, SCIP_Bool, SCIP_Bool, SCIP_Bool, int, SCIP_Bool, SCIP_Bool, SCIP_Bool)
Definition: reduce_base.c:1896
#define LURKPRUNE_MAXSTALLPROPORTION
void graph_mark(GRAPH *)
Definition: graph_base.c:1130
includes methods for Steiner tree problem solutions
SCIP_RETCODE SCIPStpHeurLurkPruneRun(SCIP *scip, SCIP_VAR **vars, const SCIP_Real *lurkingbounds, GRAPH *g, SCIP_Bool initialreduce, SCIP_Bool ascendprune, int *soledge, SCIP_Bool *solimproved)
SCIP_RETCODE SCIPStpHeurTMRun(SCIP *scip, enum PCMW_TmMode pcmw_tmmode, GRAPH *graph, int *starts, const SCIP_Real *prize, int *best_result, int runs, int bestincstart, SCIP_Real *cost, SCIP_Real *costrev, SCIP_Real *hopfactor, SCIP_Real *nodepriority, SCIP_Bool *success)
Definition: heur_tm.c:3418
reduction and dual-cost based primal heuristic for Steiner problems
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 FALSE
Definition: def.h:87
#define HEUR_TIMING
Includes dual-ascent for classic Steiner tree and some variants.
static SCIP_RETCODE reduceLurk(SCIP *scip, LURKPRUNE *lurkprune, GRAPH *prunegraph, SCIP_Bool *success)
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_redLoopMw(SCIP *, REDSOL *, GRAPH *, PATH *, SCIP_Real *, int *, int *, int *, STP_Bool *, STP_Bool, STP_Bool, STP_Bool, int, SCIP_Bool, SCIP_Bool)
Definition: reduce_base.c:1771
SCIP_Real ubnew
static SCIP_DECL_HEURCOPY(heurCopyLurkPrune)
int SCIPprobdataGetNVars(SCIP *scip)
#define DEFAULT_LURKPRUNE_MAXFREQ
static void lurkpruneFinalize(SCIP *scip, const GRAPH *g, GRAPH *prunegraph, int *soledge, LURKPRUNE *lurkprune, SCIP_Bool *solimproved)
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:67
SCIP_Real * lurkingbounds_half
SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, SCIP_HEURTIMING timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
Definition: scip_heur.c:108
#define SCIPdebugMessage
Definition: pub_message.h:87
#define FARAWAY
Definition: graphdefs.h:89
SCIP_Real globalobj
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
#define LURKPRUNE_MINSTALLPROPORTION
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur.c:1362
GRAPH * SCIPprobdataGetGraph(SCIP_PROBDATA *probdata)
SCIP_RETCODE dualascent_exec(SCIP *scip, const GRAPH *g, const int *result, const DAPARAMS *daparams, SCIP_Real *RESTRICT redcost, SCIP_Real *objval)
Definition: dualascent.c:1191
static SCIP_DECL_HEURINITSOL(heurInitsolLurkPrune)
#define HEUR_DISPCHAR
#define LURKPRUNE_MAXREDROUNDS
SCIP_Bool graph_pc_edgeIsExtended(const GRAPH *, int)
#define GE(a, b)
Definition: portab.h:85
SCIP_RETCODE SCIPsetHeurInitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINITSOL((*heurinitsol)))
Definition: scip_heur.c:217
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1441
SCIP_Bool extended
Definition: graphdefs.h:267
SCIP_RETCODE SCIPStpHeurAscendPruneRun(SCIP *scip, SCIP_HEUR *heur, const GRAPH *g, const SCIP_Real *redcosts, int *result, int root, SCIP_Bool *solfound, SCIP_Bool addsol)
IDX ** ancestors
Definition: graphdefs.h:234
void graph_get_nVET(const GRAPH *, int *, int *, int *)
Definition: graph_stats.c:571
SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
Definition: scip_heur.c:169
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPprobdataGetOffset(SCIP *scip)
#define HEUR_FREQOFS
#define LURK_MAXTOTNEDGES
void SCIPStpHeurTMCompStarts(GRAPH *graph, int *starts, int *runs)
Definition: heur_tm.c:2879
SCIP_RETCODE graph_initHistory(SCIP *, GRAPH *)
Definition: graph_base.c:695
SCIP_RETCODE SCIPprobdataAddNewSol(SCIP *scip, SCIP_Real *nval, SCIP_HEUR *heur, SCIP_Bool *success)
SCIP_RETCODE reduce_unconnected(SCIP *, GRAPH *)
SCIP_Bool dualascent
Definition: reducedefs.h:77
#define NULL
Definition: lpi_spx1.cpp:155
SCIP_Real reduce_solGetOffset(const REDSOL *)
Definition: reduce_sol.c:1137
SCIP_RETCODE SCIPStpHeurLocalRun(SCIP *scip, GRAPH *graph, int *solEdges)
Definition: heur_local.c:3899
#define HEUR_DESC
#define EQ(a, b)
Definition: portab.h:79
#define HEUR_USESSUBSCIP
int knots
Definition: graphdefs.h:190
#define SCIP_CALL(x)
Definition: def.h:384
void reduce_solFree(SCIP *, REDSOL **)
Definition: reduce_sol.c:818
#define LT(a, b)
Definition: portab.h:81
SCIP_RETCODE SCIPStpIncludeHeurLurkPrune(SCIP *scip)
Improvement heuristic for Steiner problems.
unsigned char STP_Bool
Definition: portab.h:34
reduction-based primal heuristic for Steiner problems
static SCIP_RETCODE lurkpruneInit(SCIP *scip, const GRAPH *g, const SCIP_Real *lurkingbounds, int *soledge, LURKPRUNE *lurkprune, GRAPH **prunegraph)
SCIP_Real solstp_getObjBounded(const GRAPH *g, const int *soledge, SCIP_Real offset, int nedges)
Definition: solstp.c:1833
static SCIP_DECL_HEUREXEC(heurExecLurkPrune)
propagator for Steiner tree problems, using the LP reduced costs
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
struct lurking_prune LURKPRUNE
SCIP_Real ubbest
#define SCIP_Bool
Definition: def.h:84
#define HEUR_MAXDEPTH
SCIP_Bool graph_edge_isDeleted(const GRAPH *, int)
Definition: graph_stats.c:121
static SCIP_DECL_HEURFREE(heurFreeLurkPrune)
int *RESTRICT tail
Definition: graphdefs.h:223
#define flipedge(edge)
Definition: graphdefs.h:84
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:127
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1435
Constraint handler for linear constraints in their most general form, .
void graph_path_exit(SCIP *, GRAPH *)
Definition: graph_path.c:515
SCIP_Bool graph_pc_isPc(const GRAPH *)
#define CONNECT
Definition: graphdefs.h:87
#define SCIPfreeMemory(scip, ptr)
Definition: scip_mem.h:69
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2304
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
struct SCIP_ProbData SCIP_PROBDATA
Definition: type_prob.h:44
#define HEUR_PRIORITY
SCIP_PROBDATA * SCIPgetProbData(SCIP *scip)
Definition: scip_prob.c:963
SCIP_Real * cost
Definition: graphdefs.h:221
SCIP_Bool graph_edge_isInRange(const GRAPH *, int)
Definition: graph_stats.c:110
#define LURKPRUNE_MINLURKEDGE_RATIO
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
Definition: scip_heur.c:185
SCIP_Bool graph_pc_isPcMw(const GRAPH *)
#define SCIP_Real
Definition: def.h:177
#define HEUR_FREQ
static SCIP_DECL_HEURINIT(heurInitLurkPrune)
#define LURKPRUNE_MINREDELIMS
SCIP_Real * SCIPprobdataGetXval(SCIP *scip, SCIP_SOL *sol)
SCIP_RETCODE graph_copy(SCIP *, const GRAPH *, GRAPH **)
Definition: graph_base.c:939
shortest paths based primal heuristics for Steiner problems
reduction based primal heuristic for Steiner problems
int edges
Definition: graphdefs.h:219
int graph_get_nNodes(const GRAPH *)
Definition: graph_stats.c:536
static void reduceFixedVars(SCIP *scip, SCIP_VAR **vars, const int *soledge, GRAPH *prunegraph)
#define SCIPallocMemory(scip, ptr)
Definition: scip_mem.h:51
RPARAMS * redparameters
Definition: reducedefs.h:102
#define UNKNOWN
Definition: sepa_mcf.c:4095
static SCIP_RETCODE updateSolution(SCIP *scip, GRAPH *g, LURKPRUNE *lurkprune, GRAPH *prunegraph)
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
Definition: scip_heur.c:153
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17976
#define nnodes
Definition: gastrans.c:65
#define HEUR_NAME
static SCIP_RETCODE reduceExact(SCIP *scip, LURKPRUNE *lurkprune, GRAPH *prunegraph)
SCIP_RETCODE reduce_redLoopStp(SCIP *, GRAPH *, REDBASE *)
Definition: reduce_base.c:2074
SCIP_Bool solstp_isValid(SCIP *scip, const GRAPH *graph, const int *result)
Definition: solstp.c:1650
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:1352
SCIP_Bool graph_typeIsSpgLike(const GRAPH *)
Definition: graph_stats.c:57
SCIP_Real offsetnew
includes various reduction methods for Steiner tree problems
default SCIP plugins
SCIP_Real solstp_getObj(const GRAPH *g, const int *soledge, SCIP_Real offset)
Definition: solstp.c:1859
void graph_printInfoReduced(const GRAPH *)
Definition: graph_stats.c:375
SCIP callable library.
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:48