Scippy

SCIP

Solving Constraint Integer Programs

relax_stpenum.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_stpenum.c
17  * @brief Steiner tree enumeration relaxator
18  * @author Daniel Rehfeldt
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 //#define SCIP_DEBUG
23 #include <assert.h>
24 #include "relax_stpenum.h"
25 #include "probdata_stp.h"
26 #include "prop_stp.h"
27 #include "mst.h"
28 #include "solstp.h"
29 #include "relax_stpdp.h"
30 
31 #define RELAX_NAME "stpenum"
32 #define RELAX_DESC "enumeration relaxator for STP"
33 #define RELAX_PRIORITY 10
34 #define RELAX_FREQ 1
35 
36 #define ENUM_MAXNSTEINVERTS 8
37 
38 /*
39  * Data structures
40  */
41 
42 
43 /*
44  * Local methods
45  */
46 
47 
48 /** collects and returns all non-terminals */
49 static
50 STP_Vectype(int) getSteinerVertices(
51  SCIP* scip, /**< SCIP data structure */
52  const GRAPH* graph /**< graph data structure */
53 )
54 {
55  STP_Vectype(int) steinverts = NULL;
56  const int nnodes = graph_get_nNodes(graph);
57 
58  for( int i = 0; i < nnodes; i++ )
59  {
60  if( !Is_term(graph->term[i]) && graph->grad[i] > 0 )
61  StpVecPushBack(scip, steinverts, i);
62  }
63 
64  assert(StpVecGetSize(steinverts) <= ENUM_MAXNSTEINVERTS);
65 
66  return steinverts;
67 }
68 
69 
70 /** are all terminals visited by MST? */
71 static
73  const GRAPH* graph, /**< graph data structure */
74  const MST* mst /**< MST */
75 )
76 {
77  const int nnodes = graph_get_nNodes(graph);
78  const int* const terms = graph->term;
79  const int* const nodes_prededge = mst->nodes_predEdge;
80 
81  for( int i = 0; i < nnodes; i++ )
82  {
83  if( !Is_term(terms[i]) )
84  continue;
85 
86  if( nodes_prededge[i] == UNKNOWN && i != graph->source )
87  {
88  SCIPdebugMessage("terminal vertex %d not visited, solution is invalid! \n", i);
89  return FALSE;
90  }
91  }
92 
93  return TRUE;
94 }
95 
96 
97 /** do enumeration */
98 static
100  SCIP* scip, /**< SCIP data structure */
101  const GRAPH* graph, /**< graph data structure */
102  int* RESTRICT edges_solstat, /**< solution edges */
103  SCIP_Real* obj /**< optimal objective value */
104 )
105 {
106  MST* mst;
107  STP_Bool* nodes_isActive;
108  STP_Vectype(int) steinverts = getSteinerVertices(scip, graph);
109  const int nnodes = graph_get_nNodes(graph);
110  const uint32_t nsteinverts = (uint32_t) StpVecGetSize(steinverts);
111  const uint32_t powsize = (uint32_t) pow(2.0, nsteinverts);
112  *obj = FARAWAY;
113 
114  SCIP_CALL( mst_init(scip, graph, &mst) );
115  SCIP_CALL( SCIPallocMemoryArray(scip, &nodes_isActive, graph->knots) );
116 
117 #ifndef WITH_UG
118  printf("solving problem with enumeration (%u Steiner vertices) \n", nsteinverts);
119 #endif
120 
121  for( int i = 0; i < nnodes; i++ )
122  nodes_isActive[i] = (graph->grad[i] > 0);
123  nodes_isActive[graph->source] = TRUE;
124 
125  /* loop over all subsets of Steiner vertices */
126  for( uint32_t bitset = 0; bitset < powsize; bitset++ )
127  {
128  for( uint32_t i = 0; i < nsteinverts; i++ )
129  {
130  assert(nodes_isActive[steinverts[i]]);
131  if( (bitset & (1 << i)) )
132  nodes_isActive[steinverts[i]] = FALSE;
133  }
134 
135  mst_computeOnMarked(graph, nodes_isActive, graph->source, mst);
136 
137  if( allTermsAreVisited(graph, mst) )
138  {
139  const SCIP_Real obj_curr = mst_getObj(graph, mst);
140 
141  if( LT(obj_curr, *obj) )
142  {
143  *obj = obj_curr;
144  SCIPdebugMessage("updating MST objective to %f \n", obj_curr);
145  mst_getSoledges(graph, mst, edges_solstat);
146  assert(EQ(obj_curr, solstp_getObj(graph, edges_solstat, 0.0)));
147  assert(solstp_isValid(scip, graph, edges_solstat));
148  }
149  }
150 
151  /* reset */
152  for( uint32_t i = 0; i < nsteinverts; i++ )
153  nodes_isActive[steinverts[i]] = TRUE;
154  }
155 
156  StpVecFree(scip, steinverts);
157  mst_free(scip, &mst);
158  SCIPfreeMemoryArray(scip, &nodes_isActive);
159 
160  assert(LT(*obj, FARAWAY));
161  assert(solstp_isValid(scip, graph, edges_solstat));
162 
163  return SCIP_OKAY;
164 }
165 
166 
167 /** is enumeration promising? */
168 static
170  const GRAPH* graph /**< graph data structure */
171 )
172 {
173  int nsteinverts = 0;
174  const int nnodes = graph_get_nNodes(graph);
175  const int* const terms = graph->term;
176 
177  for( int i = 0; i < nnodes; i++ )
178  {
179  if( !Is_term(terms[i]) )
180  {
181  nsteinverts++;
182  if( nsteinverts > ENUM_MAXNSTEINVERTS )
183  {
184  SCIPdebugMessage("enumeration of Steiner vertices is not promising \n");
185  return FALSE;
186  }
187  }
188  }
189 
190  return TRUE;
191 }
192 
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(relaxFreeStpenum)
203 { /*lint --e{715}*/
204  SCIPrelaxSetData(relax, NULL);
205 
206  return SCIP_OKAY;
207 }
208 
209 
210 /** execution method of relaxator */
211 static
212 SCIP_DECL_RELAXEXEC(relaxExecStpenum)
213 { /*lint --e{715}*/
214  GRAPH* graph;
215  int* edges_solstat;
216  SCIP_Bool success;
217  SCIP_Longint graphnodenumber;
218  SCIP_Bool probisinfeas;
219  SCIP_Real offset = 0.0;
220 
221  *lowerbound = -SCIPinfinity(scip);
222  *result = SCIP_DIDNOTRUN;
223 
225  return SCIP_OKAY;
226 
228  return SCIP_OKAY;
229 
230  SCIP_CALL( SCIPStpPropGetGraph(scip, &graph, &graphnodenumber, &probisinfeas, &offset) );
231 
232  if( probisinfeas )
233  {
234  SCIPdebugMessage("STP enumeration relaxator found infeasibility \n");
235  *result = SCIP_CUTOFF;
236  return SCIP_OKAY;
237  }
238 
239  assert(graphnodenumber == SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
240 
241  if( !enumIsPromising(graph) )
242  return SCIP_OKAY;
243 
244  SCIP_CALL( SCIPallocMemoryArray(scip, &edges_solstat, graph->edges) );
245  SCIP_CALL( enumExec(scip, graph, edges_solstat, lowerbound) );
246 
247  SCIP_CALL( solstp_addSolToProb(scip, graph, edges_solstat, NULL, &success) );
248  SCIPfreeMemoryArray(scip, &edges_solstat);
249 
250  *lowerbound += offset;
251  *result = SCIP_SUCCESS;
252 
253  return SCIP_OKAY;
254 }
255 
256 
257 /*
258  * relaxator specific interface methods
259  */
260 
261 
262 /** is using the relaxator promising? */
264  const GRAPH* graph /**< graph */
265  )
266 {
267  assert(graph);
268 
269  return enumIsPromising(graph);
270 }
271 
272 
273 /** Solve instance by enumeration. Only call when promising. */
275  SCIP* scip, /**< SCIP data structure */
276  const GRAPH* graph, /**< graph data structure */
277  int* RESTRICT edges_solstat /**< solution edges */
278 )
279 {
280  SCIP_Real obj;
281 
282  if( !SCIPStpEnumRelaxIsPromising(graph) )
283  {
284  SCIPerrorMessage("cannot call enumeration algorithm with too many non-terminals! \n");
285  return SCIP_ERROR;
286  }
287 
288  SCIP_CALL( enumExec(scip, graph, edges_solstat, &obj) );
289  SCIPdebugMessage("enumeration found solution with objective %f \n", obj);
290 
291  return SCIP_OKAY;
292 }
293 
294 
295 /** creates the stp relaxator and includes it in SCIP */
297  SCIP* scip /**< SCIP data structure */
298  )
299 {
300  SCIP_RELAXDATA* relaxdata = NULL;
301  SCIP_RELAX* relax = NULL;
302 
303  /* include relaxator */
305  relaxExecStpenum, relaxdata) );
306  assert(relax != NULL);
307 
308  SCIP_CALL( SCIPsetRelaxFree(scip, relax, relaxFreeStpenum) );
309 
310  return SCIP_OKAY;
311 }
static SCIP_RETCODE enumExec(SCIP *scip, const GRAPH *graph, int *RESTRICT edges_solstat, SCIP_Real *obj)
Definition: relax_stpenum.c:99
#define StpVecGetSize(vec)
Definition: stpvector.h:139
SCIP_RETCODE solstp_addSolToProb(SCIP *scip, const GRAPH *g, const int *soledge, SCIP_HEUR *heur, SCIP_Bool *success)
Definition: solstp.c:1279
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:82
SCIP_Real mst_getObj(const GRAPH *g, const MST *mst)
Definition: mst.c:168
int source
Definition: graphdefs.h:195
#define Is_term(a)
Definition: graphdefs.h:102
#define ENUM_MAXNSTEINVERTS
Definition: relax_stpenum.c:36
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip_mem.h:71
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip_mem.h:55
includes methods for Steiner tree problem solutions
#define RELAX_DESC
Definition: relax_stpenum.c:32
#define FALSE
Definition: def.h:87
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)
Problem data for stp problem.
#define TRUE
Definition: def.h:86
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
int *RESTRICT nodes_predEdge
Definition: mst.h:46
SCIP_Bool SCIPStpDpRelaxIsActive(SCIP *scip)
Definition: relax_stpdp.c:293
minimum spanning tree based algorithms for Steiner problems
static STP_Vectype(int)
Definition: relax_stpenum.c:50
#define SCIPdebugMessage
Definition: pub_message.h:87
#define FARAWAY
Definition: graphdefs.h:89
#define RELAX_NAME
Definition: relax_stpenum.c:31
static SCIP_Bool allTermsAreVisited(const GRAPH *graph, const MST *mst)
Definition: relax_stpenum.c:72
void mst_computeOnMarked(const GRAPH *g, const STP_Bool *nodes_isMarked, int startnode, MST *mst)
Definition: mst.c:223
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7432
static SCIP_DECL_RELAXFREE(relaxFreeStpenum)
void mst_getSoledges(const GRAPH *g, const MST *mst, int *RESTRICT soledges)
Definition: mst.c:196
SCIP_RETCODE SCIPsetRelaxFree(SCIP *scip, SCIP_RELAX *relax, SCIP_DECL_RELAXFREE((*relaxfree)))
Definition: scip_relax.c:144
static SCIP_Bool enumIsPromising(const GRAPH *graph)
SCIP_RETCODE SCIPincludeRelaxStpenum(SCIP *scip)
#define SCIPerrorMessage
Definition: pub_message.h:55
static SCIP_DECL_RELAXEXEC(relaxExecStpenum)
SCIP_RETCODE SCIPStpPropGetGraph(SCIP *scip, GRAPH **graph, SCIP_Longint *graphnodenumber, SCIP_Bool *probisinfeas, SCIP_Real *offset)
Definition: prop_stp.c:2521
int *RESTRICT grad
Definition: graphdefs.h:201
#define NULL
Definition: lpi_spx1.cpp:155
Steiner tree enumeration relaxator.
#define EQ(a, b)
Definition: portab.h:79
int knots
Definition: graphdefs.h:190
#define SCIP_CALL(x)
Definition: def.h:384
#define LT(a, b)
Definition: portab.h:81
unsigned char STP_Bool
Definition: portab.h:34
propagator for Steiner tree problems, using the LP reduced costs
#define SCIP_Bool
Definition: def.h:84
SCIP_RETCODE SCIPStpEnumRelaxComputeSol(SCIP *scip, const GRAPH *graph, int *RESTRICT edges_solstat)
#define RELAX_PRIORITY
Definition: relax_stpenum.c:33
int *RESTRICT term
Definition: graphdefs.h:196
void SCIPrelaxSetData(SCIP_RELAX *relax, SCIP_RELAXDATA *relaxdata)
Definition: relax.c:450
void mst_free(SCIP *scip, MST **minspantree)
Definition: mst.c:145
struct SCIP_RelaxData SCIP_RELAXDATA
Definition: type_relax.h:38
#define SCIP_Real
Definition: def.h:177
SCIP_RETCODE mst_init(SCIP *scip, const GRAPH *g, MST **minspantree)
Definition: mst.c:118
#define StpVecFree(scip, vec)
Definition: stpvector.h:153
#define SCIP_Longint
Definition: def.h:162
int edges
Definition: graphdefs.h:219
SCIP_Bool SCIPStpEnumRelaxIsPromising(const GRAPH *graph)
int graph_get_nNodes(const GRAPH *)
Definition: graph_stats.c:536
#define UNKNOWN
Definition: sepa_mcf.c:4095
#define nnodes
Definition: gastrans.c:65
#define RELAX_FREQ
Definition: relax_stpenum.c:34
#define StpVecPushBack(scip, vec, value)
Definition: stpvector.h:167
SCIP_Bool solstp_isValid(SCIP *scip, const GRAPH *graph, const int *result)
Definition: solstp.c:1650
SCIP_Bool graph_typeIsSpgLike(const GRAPH *)
Definition: graph_stats.c:57
SCIP_Real solstp_getObj(const GRAPH *g, const int *soledge, SCIP_Real offset)
Definition: solstp.c:1859
GRAPH * SCIPprobdataGetGraph2(SCIP *scip)
Steiner tree dynamic programming relaxator.