Scippy

SCIP

Solving Constraint Integer Programs

relax_stp.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 relax_stp.c
17  * @brief Steiner tree relaxator
18  * @author Daniel Rehfeldt
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <assert.h>
24 #include <string.h>
25 #include "relax_stp.h"
26 #include "prop_stp.h"
27 #include "dualascent.h"
28 #include "solstp.h"
29 
30 #define RELAX_NAME "stp"
31 #define RELAX_DESC "relaxator for STP"
32 #define RELAX_PRIORITY 0
33 #define RELAX_FREQ 1
34 
35 #define DA_MAXNROOTS 4
36 
37 /*
38  * Data structures
39  */
40 
41 /** relaxator data */
42 struct SCIP_RelaxData
43 {
44  SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
45  SCIP_Longint lastnodenumber; /**< node number of last call */
46  SCIP_Bool isActive; /**< is the relaxator being used? */
47 };
48 
49 
50 /*
51  * Local methods
52  */
53 
54 
55 
56 /** collects roots */
57 static inline
59  const GRAPH* graph, /**< graph data structure */
60  SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
61  int* terminals, /**< terminals array (of size graph->terms) */
62  int* nterms /**< number of terminals */
63 )
64 {
65  const int nnodes = graph_get_nNodes(graph);
66  const int maxnterms = DA_MAXNROOTS;
67  int termcount = 0;
68  const SCIP_Bool isRpcmw = graph_pc_isRootedPcMw(graph);
69 
70  assert(graph->stp_type != STP_PCSPG && graph->stp_type != STP_MWCSP);
71 
72  for( int i = 0; i < nnodes; i++ )
73  {
74  if( Is_term(graph->term[i]) )
75  {
76  if( isRpcmw && !graph_pc_knotIsFixedTerm(graph, i) )
77  {
78  continue;
79  }
80  terminals[termcount++] = i;
81  }
82  }
83 
84  assert(termcount == graph->terms || isRpcmw);
85  SCIPrandomPermuteIntArray(randnumgen, terminals, 0, termcount);
86 
87  *nterms = MIN(termcount, maxnterms);
88 
89  /*
90  for( int i = 0; i < *nterms; i++ )
91  {
92  if( terminals[i] == graph->source )
93  {
94  rootIsIncluded = TRUE;
95  break;
96  }
97  }
98 
99  if( !rootIsIncluded )
100  terminals[0] = graph->source;
101  */
102 }
103 
104 
105 
106 
107 /** computes lower bound */
108 static
110  SCIP* scip, /**< SCIP data structure */
111  GRAPH* graph, /**< the graph */
112  SCIP_RANDNUMGEN* randnumgen, /**< random number generator */
113  SCIP_Real* lowerbound /**< pointer to lower bound (OUT) */
114  )
115 {
116  const SCIP_Bool mw = (graph->stp_type == STP_MWCSP);
117  const SCIP_Bool pc = (graph->stp_type == STP_PCSPG);
118  const SCIP_Bool doAscendPrune = !TRUE; // todo?
119 
120  *lowerbound = -SCIPinfinity(scip);
121 
122  if( doAscendPrune )
123  {
124  SCIP_CALL( graph_path_init(scip, graph) );
125  }
126 
127  if( pc || mw )
128  {
129  SCIP_CALL( dualascent_execPcMw(scip, graph, NULL, lowerbound, FALSE, doAscendPrune, 1) );
130  }
131  else
132  {
133  int* terms;
134  int* soledges;
135  int nterms;
136 
137  SCIP_CALL( SCIPallocBufferArray(scip, &soledges, graph->edges) );
138  SCIP_CALL( SCIPallocBufferArray(scip, &terms, graph->terms) );
139  collectRoots(graph, randnumgen, terms, &nterms);
140 
141  for( int i = 0; i < nterms; i++ )
142  {
143  DAPARAMS daparams = { .addcuts = FALSE, .ascendandprune = doAscendPrune, .root = terms[i],
144  .is_pseudoroot = FALSE, .damaxdeviation = 0.1 };
145  SCIP_Real lowerbound_local;
146 
147  if( i > 0 )
148  daparams.ascendandprune = FALSE;
149 
150  if( SCIPrandomGetInt(randnumgen, 0, 1) == 0 || SCIPgetNSols(scip) == 0 )
151  {
152  printf("running without guiding solution ...");
153 
154  SCIP_CALL( dualascent_exec(scip, graph, NULL, &daparams, NULL, &lowerbound_local) );
155  }
156  else
157  {
158  SCIP_Bool isInfeas = FALSE;
159  solstp_getStpFromSCIPsol(scip, SCIPgetBestSol(scip), graph, soledges);
160 
161  printf("running WITH guiding solution ...");
162 
163  SCIP_CALL(solstp_rerootInfeas(scip, graph, soledges, daparams.root, &isInfeas));
164 
165  /* NOTE: might happen because of graph changes*/
166  if( isInfeas )
167  {
168  printf("is infeasible! \n");
169  }
170 
171  if( isInfeas )
172  SCIP_CALL( dualascent_exec(scip, graph, NULL, &daparams, NULL, &lowerbound_local) );
173  else
174  SCIP_CALL( dualascent_exec(scip, graph, soledges, &daparams, NULL, &lowerbound_local) );
175  }
176 
177  printf("run %d for root=%d ... ", i, terms[i]);
178  printf("bound=%f \n", lowerbound_local);
179 
180  if( lowerbound_local > *lowerbound )
181  *lowerbound = lowerbound_local;
182  }
183 
184  SCIPfreeBufferArray(scip, &terms);
185  SCIPfreeBufferArray(scip, &soledges);
186 
187  }
188 
189  if( doAscendPrune )
190  graph_path_exit(scip, graph);
191 
192  return SCIP_OKAY;
193 }
194 
195 /*
196  * Callback methods of relaxator
197  */
198 
199 
200 /** destructor of relaxator to free user data (called when SCIP is exiting) */
201 static
202 SCIP_DECL_RELAXFREE(relaxFreeStp)
203 { /*lint --e{715}*/
204  SCIP_RELAXDATA* relaxdata = SCIPrelaxGetData(relax);
205  assert(relaxdata);
206 
207  SCIPfreeRandom(scip, &(relaxdata->randnumgen));
208  SCIPfreeMemory(scip, &relaxdata);
209 
210  SCIPrelaxSetData(relax, NULL);
211 
212  return SCIP_OKAY;
213 }
214 
215 
216 /** solving process initialization method of relaxator (called when branch and bound process is about to begin) */
217 static
218 SCIP_DECL_RELAXINITSOL(relaxInitsolStp)
219 { /*lint --e{715}*/
220 
221  SCIP_Bool usedarelax;
222  SCIP_RELAXDATA* relaxdata = SCIPrelaxGetData(relax);
223  assert(relaxdata);
224 
225  SCIP_CALL( SCIPgetBoolParam(scip, "stp/usedarelax", &usedarelax) );
226 
227  relaxdata->lastnodenumber = -1;
228  relaxdata->isActive = usedarelax;
229 
230  if( usedarelax )
231  {
232  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
233  }
234 
235  return SCIP_OKAY;
236 }
237 
238 
239 
240 /** solving process deinitialization method of relaxator (called before branch and bound process data is freed) */
241 static
242 SCIP_DECL_RELAXEXITSOL(relaxExitsolStp)
243 { /*lint --e{715}*/
244 
245  return SCIP_OKAY;
246 }
247 
248 
249 
250 /** execution method of relaxator */
251 static
252 SCIP_DECL_RELAXEXEC(relaxExecStp)
253 { /*lint --e{715}*/
254  GRAPH* graph;
255  SCIP_RELAXDATA* const relaxdata = SCIPrelaxGetData(relax);
256  SCIP_Longint nodenumber;
257  SCIP_Longint graphnodenumber;
258  SCIP_Bool probisinfeas;
259  SCIP_Real offset = 0.0;
260 
261  *lowerbound = -SCIPinfinity(scip);
262  *result = SCIP_DIDNOTRUN;
263 
264  if( !relaxdata->isActive )
265  return SCIP_OKAY;
266 
267  /* NOTE node supported because might mess up the offset */
269  return SCIP_OKAY;
270 
272  if( nodenumber == relaxdata->lastnodenumber )
273  {
274  relaxdata->lastnodenumber = nodenumber;
275  printf("same node number (%lld), don't execute relaxator \n", nodenumber);
276 
277  return SCIP_OKAY;
278  }
279 
280  relaxdata->lastnodenumber = nodenumber;
281 
282  SCIP_CALL( SCIPStpPropGetGraph(scip, &graph, &graphnodenumber, &probisinfeas, &offset) );
283 
284  if( probisinfeas )
285  {
286  printf("STP relaxator found infeasibility \n");
287  *result = SCIP_CUTOFF;
288  }
289  else
290  {
291  assert(graph);
292  assert(graphnodenumber == nodenumber);
293 
294  SCIP_CALL( runDualAscent(scip, graph, relaxdata->randnumgen, lowerbound) );
295 
296  *lowerbound += offset;
297 
298  printf("offset=%f \n", offset);
299  printf("scip offset=%f \n", SCIPprobdataGetOffset(scip));
300 
301 
302 
303  printf("Stp lower bound = %f \n", *lowerbound);
304  *result = SCIP_SUCCESS;
305  }
306 
307  // todo possibly compute solution by ascend-prune and add it
308 
309  return SCIP_OKAY;
310 }
311 
312 
313 /*
314  * relaxator specific interface methods
315  */
316 
317 /** is the relaxator active? */
319  SCIP* scip /**< SCIP data structure */
320  )
321 {
322  SCIP_RELAX* relax = SCIPfindRelax(scip, "stp");
323  SCIP_RELAXDATA* relaxdata = SCIPrelaxGetData(relax);
324 
325  assert(relaxdata);
326 
327  return relaxdata->isActive;
328 }
329 
330 
331 /** creates the stp relaxator and includes it in SCIP */
333  SCIP* scip /**< SCIP data structure */
334  )
335 {
336  SCIP_RELAXDATA* relaxdata;
337  SCIP_RELAX* relax = NULL;
338 
339  SCIP_CALL( SCIPallocMemory(scip, &relaxdata) );
340 
341  /* include relaxator */
343  relaxExecStp, relaxdata) );
344  assert(relax != NULL);
345 
346  SCIP_CALL( SCIPsetRelaxInitsol(scip, relax, relaxInitsolStp) );
347  SCIP_CALL( SCIPsetRelaxExitsol(scip, relax, relaxExitsolStp) );
348  SCIP_CALL( SCIPsetRelaxFree(scip, relax, relaxFreeStp) );
349 
351  "stp/usedarelax",
352  "use dual ascent bounds only?",
353  NULL, FALSE, FALSE, NULL, NULL) );
354 
355  relaxdata->lastnodenumber = -1;
356  relaxdata->isActive = FALSE;
357 
358  SCIP_CALL( SCIPcreateRandom(scip, &relaxdata->randnumgen, 1, TRUE) );
359 
360  return SCIP_OKAY;
361 }
Steiner tree relaxator.
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
static volatile int nterms
Definition: interrupt.c:38
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:82
SCIP_Bool graph_pc_isRootedPcMw(const GRAPH *)
static SCIP_DECL_RELAXEXITSOL(relaxExitsolStp)
Definition: relax_stp.c:242
#define Is_term(a)
Definition: graphdefs.h:102
int terms
Definition: graphdefs.h:192
#define RELAX_NAME
Definition: relax_stp.c:30
includes methods for Steiner tree problem solutions
SCIP_RETCODE SCIPsetRelaxExitsol(SCIP *scip, SCIP_RELAX *relax, SCIP_DECL_RELAXEXITSOL((*relaxexitsol)))
Definition: scip_relax.c:208
SCIP_RETCODE graph_path_init(SCIP *, GRAPH *)
Definition: graph_path.c:480
#define FALSE
Definition: def.h:87
static SCIP_DECL_RELAXEXEC(relaxExecStp)
Definition: relax_stp.c:252
static SCIP_RETCODE runDualAscent(SCIP *scip, GRAPH *graph, SCIP_RANDNUMGEN *randnumgen, SCIP_Real *lowerbound)
Definition: relax_stp.c:109
Includes dual-ascent for classic Steiner tree and some variants.
SCIP_RETCODE SCIPincludeRelaxBasic(SCIP *scip, SCIP_RELAX **relaxptr, const char *name, const char *desc, int priority, int freq, SCIP_DECL_RELAXEXEC((*relaxexec)), SCIP_RELAXDATA *relaxdata)
Definition: scip_relax.c:94
SCIP_Real SCIPinfinity(SCIP *scip)
#define TRUE
Definition: def.h:86
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
#define DA_MAXNROOTS
Definition: relax_stp.c:35
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition: misc.c:10003
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
void solstp_getStpFromSCIPsol(SCIP *scip, SCIP_SOL *scipsol, const GRAPH *g, int *soledges)
Definition: solstp.c:1949
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
SCIP_RETCODE solstp_rerootInfeas(SCIP *scip, GRAPH *g, int *result, int newroot, SCIP_Bool *isInfeasible)
Definition: solstp.c:1579
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7432
SCIP_RETCODE SCIPsetRelaxFree(SCIP *scip, SCIP_RELAX *relax, SCIP_DECL_RELAXFREE((*relaxfree)))
Definition: scip_relax.c:144
int stp_type
Definition: graphdefs.h:264
SCIP_Real SCIPprobdataGetOffset(SCIP *scip)
SCIP_RETCODE SCIPStpPropGetGraph(SCIP *scip, GRAPH **graph, SCIP_Longint *graphnodenumber, SCIP_Bool *probisinfeas, SCIP_Real *offset)
Definition: prop_stp.c:2521
static SCIP_DECL_RELAXFREE(relaxFreeStp)
Definition: relax_stp.c:202
static void collectRoots(const GRAPH *graph, SCIP_RANDNUMGEN *randnumgen, int *terminals, int *nterms)
Definition: relax_stp.c:58
SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
Definition: scip_param.c:241
#define NULL
Definition: lpi_spx1.cpp:155
SCIP_RELAXDATA * SCIPrelaxGetData(SCIP_RELAX *relax)
Definition: relax.c:440
#define SCIP_CALL(x)
Definition: def.h:384
#define STP_PCSPG
Definition: graphdefs.h:44
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
propagator for Steiner tree problems, using the LP reduced costs
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
#define RELAX_FREQ
Definition: relax_stp.c:33
#define SCIP_Bool
Definition: def.h:84
SCIP_RETCODE SCIPincludeRelaxStp(SCIP *scip)
Definition: relax_stp.c:332
void SCIPrandomPermuteIntArray(SCIP_RANDNUMGEN *randnumgen, int *array, int begin, int end)
Definition: misc.c:10044
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:478
int SCIPgetNSols(SCIP *scip)
Definition: scip_sol.c:2205
int *RESTRICT term
Definition: graphdefs.h:196
void SCIPrelaxSetData(SCIP_RELAX *relax, SCIP_RELAXDATA *relaxdata)
Definition: relax.c:450
void graph_path_exit(SCIP *, GRAPH *)
Definition: graph_path.c:515
SCIP_Bool ascendandprune
Definition: dualascent.h:42
#define SCIPfreeMemory(scip, ptr)
Definition: scip_mem.h:69
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2304
struct SCIP_RelaxData SCIP_RELAXDATA
Definition: type_relax.h:38
#define RELAX_DESC
Definition: relax_stp.c:31
SCIP_Bool graph_pc_knotIsFixedTerm(const GRAPH *, int)
SCIP_Bool SCIPStpRelaxIsActive(SCIP *scip)
Definition: relax_stp.c:318
static SCIP_DECL_RELAXINITSOL(relaxInitsolStp)
Definition: relax_stp.c:218
SCIP_Bool graph_pc_isUnrootedPcMw(const GRAPH *)
#define SCIP_Real
Definition: def.h:177
#define SCIP_Longint
Definition: def.h:162
int edges
Definition: graphdefs.h:219
SCIP_RETCODE dualascent_execPcMw(SCIP *scip, GRAPH *g, SCIP_Real *redcost, SCIP_Real *objval, SCIP_Bool addcuts, SCIP_Bool ascendandprune, int nruns)
Definition: dualascent.c:1319
int graph_get_nNodes(const GRAPH *)
Definition: graph_stats.c:536
#define RELAX_PRIORITY
Definition: relax_stp.c:32
#define SCIPallocMemory(scip, ptr)
Definition: scip_mem.h:51
#define nnodes
Definition: gastrans.c:65
#define STP_MWCSP
Definition: graphdefs.h:51
GRAPH * SCIPprobdataGetGraph2(SCIP *scip)
SCIP_RETCODE SCIPsetRelaxInitsol(SCIP *scip, SCIP_RELAX *relax, SCIP_DECL_RELAXINITSOL((*relaxinitsol)))
Definition: scip_relax.c:192
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
SCIP_RELAX * SCIPfindRelax(SCIP *scip, const char *name)
Definition: scip_relax.c:225