Scippy

SCIP

Solving Constraint Integer Programs

nodesel_bfs.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-2014 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 email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file nodesel_bfs.c
17  * @brief node selector for best first search
18  * @author Tobias Achterberg
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 
26 #include "scip/nodesel_bfs.h"
27 
28 
29 #define NODESEL_NAME "bfs"
30 #define NODESEL_DESC "best first search"
31 #define NODESEL_STDPRIORITY 100000
32 #define NODESEL_MEMSAVEPRIORITY 0
33 
34 
35 /*
36  * Default parameter settings
37  */
38 
39 #define MINPLUNGEDEPTH -1 /**< minimal plunging depth, before new best node may be selected (-1 for dynamic setting) */
40 #define MAXPLUNGEDEPTH -1 /**< maximal plunging depth, before new best node is forced to be selected (-1 for dynamic setting) */
41 #define MAXPLUNGEQUOT 0.25 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
42  * where plunging is performed */
43 
44 
45 /** node selector data for best first search node selection */
46 struct SCIP_NodeselData
47 {
48  SCIP_Real maxplungequot; /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
49  * where plunging is performed */
50  int minplungedepth; /**< minimal plunging depth, before new best node may be selected
51  * (-1 for dynamic setting) */
52  int maxplungedepth; /**< maximal plunging depth, before new best node is forced to be selected
53  * (-1 for dynamic setting) */
54 };
55 
56 
57 /*
58  * Callback methods
59  */
60 
61 /** copy method for node selector plugins (called when SCIP copies plugins) */
62 static
63 SCIP_DECL_NODESELCOPY(nodeselCopyBfs)
64 { /*lint --e{715}*/
65  assert(scip != NULL);
66  assert(nodesel != NULL);
67  assert(strcmp(SCIPnodeselGetName(nodesel), NODESEL_NAME) == 0);
68 
69  /* call inclusion method of node selector */
71 
72  return SCIP_OKAY;
73 }
74 
75 /** destructor of node selector to free user data (called when SCIP is exiting) */
76 static
77 SCIP_DECL_NODESELFREE(nodeselFreeBfs)
78 { /*lint --e{715}*/
79  SCIP_NODESELDATA* nodeseldata;
80 
81  assert(nodesel != NULL);
82  assert(strcmp(SCIPnodeselGetName(nodesel), NODESEL_NAME) == 0);
83  assert(scip != NULL);
84 
85  /* free user data of node selector */
86  nodeseldata = SCIPnodeselGetData(nodesel);
87  assert(nodeseldata != NULL);
88  SCIPfreeMemory(scip, &nodeseldata);
89  SCIPnodeselSetData(nodesel, nodeseldata);
90 
91  return SCIP_OKAY;
92 }
93 
94 
95 /** node selection method of node selector */
96 static
97 SCIP_DECL_NODESELSELECT(nodeselSelectBfs)
98 { /*lint --e{715}*/
99  SCIP_NODESELDATA* nodeseldata;
100  int minplungedepth;
101  int maxplungedepth;
102  int plungedepth;
103  SCIP_Real maxplungequot;
104 
105  assert(nodesel != NULL);
106  assert(strcmp(SCIPnodeselGetName(nodesel), NODESEL_NAME) == 0);
107  assert(scip != NULL);
108  assert(selnode != NULL);
109 
110  *selnode = NULL;
111 
112  /* get node selector user data */
113  nodeseldata = SCIPnodeselGetData(nodesel);
114  assert(nodeseldata != NULL);
115 
116  /* calculate minimal and maximal plunging depth */
117  minplungedepth = nodeseldata->minplungedepth;
118  maxplungedepth = nodeseldata->maxplungedepth;
119  maxplungequot = nodeseldata->maxplungequot;
120  if( minplungedepth == -1 )
121  {
122  minplungedepth = SCIPgetMaxDepth(scip)/10;
124  minplungedepth += 10;
125  if( maxplungedepth >= 0 )
126  minplungedepth = MIN(minplungedepth, maxplungedepth);
127  }
128  if( maxplungedepth == -1 )
129  maxplungedepth = SCIPgetMaxDepth(scip)/2;
130  maxplungedepth = MAX(maxplungedepth, minplungedepth);
131 
132  /* check, if we exceeded the maximal plunging depth */
133  plungedepth = SCIPgetPlungeDepth(scip);
134  if( plungedepth > maxplungedepth )
135  {
136  /* we don't want to plunge again: select best node from the tree */
137  SCIPdebugMessage("plungedepth: [%d,%d], cur: %d -> abort plunging\n", minplungedepth, maxplungedepth, plungedepth);
138  *selnode = SCIPgetBestNode(scip);
139  SCIPdebugMessage(" -> best node : lower=%g\n",
140  *selnode != NULL ? SCIPnodeGetLowerbound(*selnode) : SCIPinfinity(scip));
141  }
142  else
143  {
144  SCIP_NODE* node;
145  SCIP_Real maxbound;
146 
147  /* check, if plunging is forced at the current depth */
148  if( plungedepth < minplungedepth )
149  {
150  maxbound = SCIPinfinity(scip);
151  SCIPdebugMessage("plungedepth: [%d,%d], cur: %d => maxbound: infinity\n",
152  minplungedepth, maxplungedepth, plungedepth);
153  }
154  else
155  {
156  SCIP_Real lowerbound;
157  SCIP_Real cutoffbound;
158  /* get global lower and cutoff bound */
159  lowerbound = SCIPgetLowerbound(scip);
160  cutoffbound = SCIPgetCutoffbound(scip);
161 
162  /* if we didn't find a solution yet, the cutoff bound is usually very bad:
163  * use only 20% of the gap as cutoff bound
164  */
165  if( SCIPgetNSolsFound(scip) == 0 )
166  cutoffbound = lowerbound + 0.2 * (cutoffbound - lowerbound);
167  /* calculate maximal plunging bound */
168  maxbound = lowerbound + maxplungequot * (cutoffbound - lowerbound);
169 
170  SCIPdebugMessage("plungedepth: [%d,%d], cur: %d, bounds: [%g,%g], maxbound: %g\n",
171  minplungedepth, maxplungedepth, plungedepth, lowerbound, cutoffbound, maxbound);
172  }
173 
174  /* we want to plunge again: prefer children over siblings, and siblings over leaves,
175  * but only select a child or sibling, if its dual bound is small enough;
176  * prefer using nodes with higher node selection priority assigned by the branching rule
177  */
178  node = SCIPgetPrioChild(scip);
179  if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
180  {
181  *selnode = node;
182  SCIPdebugMessage(" -> selected prio child: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
183  }
184  else
185  {
186  node = SCIPgetBestChild(scip);
187  if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
188  {
189  *selnode = node;
190  SCIPdebugMessage(" -> selected best child: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
191  }
192  else
193  {
194  node = SCIPgetPrioSibling(scip);
195  if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
196  {
197  *selnode = node;
198  SCIPdebugMessage(" -> selected prio sibling: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
199  }
200  else
201  {
202  node = SCIPgetBestSibling(scip);
203  if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
204  {
205  *selnode = node;
206  SCIPdebugMessage(" -> selected best sibling: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
207  }
208  else
209  {
210  *selnode = SCIPgetBestNode(scip);
211  SCIPdebugMessage(" -> selected best leaf: lower=%g\n",
212  *selnode != NULL ? SCIPnodeGetLowerbound(*selnode) : SCIPinfinity(scip));
213  }
214  }
215  }
216  }
217  }
218 
219  return SCIP_OKAY;
220 }
221 
222 
223 /** node comparison method of node selector */
224 static
225 SCIP_DECL_NODESELCOMP(nodeselCompBfs)
226 { /*lint --e{715}*/
227  SCIP_Real lowerbound1;
228  SCIP_Real lowerbound2;
229 
230  assert(nodesel != NULL);
231  assert(strcmp(SCIPnodeselGetName(nodesel), NODESEL_NAME) == 0);
232  assert(scip != NULL);
233 
234  lowerbound1 = SCIPnodeGetLowerbound(node1);
235  lowerbound2 = SCIPnodeGetLowerbound(node2);
236  if( SCIPisLT(scip, lowerbound1, lowerbound2) )
237  return -1;
238  else if( SCIPisGT(scip, lowerbound1, lowerbound2) )
239  return +1;
240  else
241  {
242  SCIP_Real estimate1;
243  SCIP_Real estimate2;
244 
245  estimate1 = SCIPnodeGetEstimate(node1);
246  estimate2 = SCIPnodeGetEstimate(node2);
247  if( (SCIPisInfinity(scip, estimate1) && SCIPisInfinity(scip, estimate2)) ||
248  (SCIPisInfinity(scip, -estimate1) && SCIPisInfinity(scip, -estimate2)) ||
249  SCIPisEQ(scip, estimate1, estimate2) )
250  {
251  SCIP_NODETYPE nodetype1;
252  SCIP_NODETYPE nodetype2;
253 
254  nodetype1 = SCIPnodeGetType(node1);
255  nodetype2 = SCIPnodeGetType(node2);
256  if( nodetype1 == SCIP_NODETYPE_CHILD && nodetype2 != SCIP_NODETYPE_CHILD )
257  return -1;
258  else if( nodetype1 != SCIP_NODETYPE_CHILD && nodetype2 == SCIP_NODETYPE_CHILD )
259  return +1;
260  else if( nodetype1 == SCIP_NODETYPE_SIBLING && nodetype2 != SCIP_NODETYPE_SIBLING )
261  return -1;
262  else if( nodetype1 != SCIP_NODETYPE_SIBLING && nodetype2 == SCIP_NODETYPE_SIBLING )
263  return +1;
264  else
265  {
266  int depth1;
267  int depth2;
268 
269  depth1 = SCIPnodeGetDepth(node1);
270  depth2 = SCIPnodeGetDepth(node2);
271  if( depth1 < depth2 )
272  return -1;
273  else if( depth1 > depth2 )
274  return +1;
275  else
276  return 0;
277  }
278  }
279 
280  if( SCIPisLT(scip, estimate1, estimate2) )
281  return -1;
282 
283  assert(SCIPisGT(scip, estimate1, estimate2));
284  return +1;
285  }
286 }
287 
288 
289 /*
290  * bfs specific interface methods
291  */
292 
293 /** creates the node selector for best first search and includes it in SCIP */
295  SCIP* scip /**< SCIP data structure */
296  )
297 {
298  SCIP_NODESELDATA* nodeseldata;
299  SCIP_NODESEL* nodesel;
300 
301  /* allocate and initialize node selector data; this has to be freed in the destructor */
302  SCIP_CALL( SCIPallocMemory(scip, &nodeseldata) );
303 
304  /* include node selector */
306  nodeselSelectBfs, nodeselCompBfs, nodeseldata) );
307 
308  assert(nodesel != NULL);
309 
310  SCIP_CALL( SCIPsetNodeselCopy(scip, nodesel, nodeselCopyBfs) );
311  SCIP_CALL( SCIPsetNodeselFree(scip, nodesel, nodeselFreeBfs) );
312 
313  /* add node selector parameters */
315  "nodeselection/bfs/minplungedepth",
316  "minimal plunging depth, before new best node may be selected (-1 for dynamic setting)",
317  &nodeseldata->minplungedepth, TRUE, MINPLUNGEDEPTH, -1, INT_MAX, NULL, NULL) );
319  "nodeselection/bfs/maxplungedepth",
320  "maximal plunging depth, before new best node is forced to be selected (-1 for dynamic setting)",
321  &nodeseldata->maxplungedepth, TRUE, MAXPLUNGEDEPTH, -1, INT_MAX, NULL, NULL) );
323  "nodeselection/bfs/maxplungequot",
324  "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where plunging is performed",
325  &nodeseldata->maxplungequot, TRUE, MAXPLUNGEQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
326 
327  return SCIP_OKAY;
328 }
329 
330