SCIP Doxygen Documentation
Loading...
Searching...
No Matches
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-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file nodesel_bfs.c
26 * @ingroup DEFPLUGINS_NODESEL
27 * @brief node selector for best first search
28 * @author Tobias Achterberg
29 */
30
31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32
33#include "scip/nodesel_bfs.h"
34#include "scip/pub_message.h"
35#include "scip/pub_nodesel.h"
36#include "scip/pub_tree.h"
37#include "scip/scip_mem.h"
38#include "scip/scip_message.h"
39#include "scip/scip_nodesel.h"
40#include "scip/scip_numerics.h"
41#include "scip/scip_param.h"
43#include "scip/scip_tree.h"
44#include "scip/type_misc.h"
45
46
47#define NODESEL_NAME "bfs"
48#define NODESEL_DESC "best first search"
49#define NODESEL_STDPRIORITY 100000
50#define NODESEL_MEMSAVEPRIORITY 0
51
52
53/*
54 * Default parameter settings
55 */
56
57#define MINPLUNGEDEPTH -1 /**< minimal plunging depth, before new best node may be selected (-1 for dynamic setting) */
58#define MAXPLUNGEDEPTH -1 /**< maximal plunging depth, before new best node is forced to be selected (-1 for dynamic setting) */
59#define MAXPLUNGEQUOT 0.25 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
60 * where plunging is performed */
61
62
63/** node selector data for best first search node selection */
64struct SCIP_NodeselData
65{
66 SCIP_Real maxplungequot; /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
67 * where plunging is performed */
68 int minplungedepth; /**< minimal plunging depth, before new best node may be selected
69 * (-1 for dynamic setting) */
70 int maxplungedepth; /**< maximal plunging depth, before new best node is forced to be selected
71 * (-1 for dynamic setting) */
72};
73
74
75/*
76 * Callback methods
77 */
78
79/** copy method for node selector plugins (called when SCIP copies plugins) */
80static
81SCIP_DECL_NODESELCOPY(nodeselCopyBfs)
82{ /*lint --e{715}*/
83 assert(scip != NULL);
84 assert(nodesel != NULL);
85
87
88 /* call inclusion method of node selector */
90
91 return SCIP_OKAY;
92}
93
94/** destructor of node selector to free user data (called when SCIP is exiting) */
95/**! [SnippetNodeselFreeBfs] */
96static
97SCIP_DECL_NODESELFREE(nodeselFreeBfs)
98{ /*lint --e{715}*/
99 SCIP_NODESELDATA* nodeseldata;
100
101 assert(nodesel != NULL);
102 assert(scip != NULL);
103
105
106 /* free user data of node selector */
107 nodeseldata = SCIPnodeselGetData(nodesel);
108 assert(nodeseldata != NULL);
109 SCIPfreeBlockMemory(scip, &nodeseldata);
110 SCIPnodeselSetData(nodesel, nodeseldata);
111
112 return SCIP_OKAY;
113}
114/**! [SnippetNodeselFreeBfs] */
115
116
117/** node selection method of node selector */
118static
119SCIP_DECL_NODESELSELECT(nodeselSelectBfs)
120{ /*lint --e{715}*/
121 SCIP_NODESELDATA* nodeseldata;
122 int minplungedepth;
123 int maxplungedepth;
124 int plungedepth;
125 SCIP_Real maxplungequot;
126
127 assert(nodesel != NULL);
128 assert(scip != NULL);
129 assert(selnode != NULL);
130
132
133 *selnode = NULL;
134
135 /* get node selector user data */
136 nodeseldata = SCIPnodeselGetData(nodesel);
137 assert(nodeseldata != NULL);
138
139 /* calculate minimal and maximal plunging depth */
140 minplungedepth = nodeseldata->minplungedepth;
141 maxplungedepth = nodeseldata->maxplungedepth;
142 maxplungequot = nodeseldata->maxplungequot;
143 if( minplungedepth == -1 )
144 {
145 minplungedepth = SCIPgetMaxDepth(scip)/10;
147 minplungedepth += 10;
148 if( maxplungedepth >= 0 )
149 minplungedepth = MIN(minplungedepth, maxplungedepth);
150 }
151 if( maxplungedepth == -1 )
152 maxplungedepth = SCIPgetMaxDepth(scip)/2;
153 maxplungedepth = MAX(maxplungedepth, minplungedepth);
154
155 /* check, if we exceeded the maximal plunging depth */
156 plungedepth = SCIPgetPlungeDepth(scip);
157 if( plungedepth >= maxplungedepth )
158 {
159 /* we don't want to plunge again: select best node from the tree */
160 SCIPdebugMsg(scip, "plungedepth: [%d,%d], cur: %d -> abort plunging\n", minplungedepth, maxplungedepth, plungedepth);
161 *selnode = SCIPgetBestNode(scip);
162 SCIPdebugMsg(scip, " -> best node : lower=%g\n",
163 *selnode != NULL ? SCIPnodeGetLowerbound(*selnode) : SCIPinfinity(scip));
164 }
165 else
166 {
167 SCIP_NODE* node;
168 SCIP_Real maxbound;
169
170 /* check, if plunging is forced at the current depth */
171 if( plungedepth < minplungedepth )
172 {
173 maxbound = SCIPinfinity(scip);
174 SCIPdebugMsg(scip, "plungedepth: [%d,%d], cur: %d => maxbound: infinity\n",
175 minplungedepth, maxplungedepth, plungedepth);
176 }
177 else
178 {
179 SCIP_Real lowerbound;
180 SCIP_Real cutoffbound;
181 /* get global lower and cutoff bound */
182 lowerbound = SCIPgetLowerbound(scip);
183 cutoffbound = SCIPgetCutoffbound(scip);
184
185 /* if we didn't find a solution yet, the cutoff bound is usually very bad:
186 * use only 20% of the gap as cutoff bound
187 */
188 if( SCIPgetNSolsFound(scip) == 0 )
189 cutoffbound = lowerbound + 0.2 * (cutoffbound - lowerbound);
190 /* calculate maximal plunging bound */
191 maxbound = lowerbound + maxplungequot * (cutoffbound - lowerbound);
192
193 SCIPdebugMsg(scip, "plungedepth: [%d,%d], cur: %d, bounds: [%g,%g], maxbound: %g\n",
194 minplungedepth, maxplungedepth, plungedepth, lowerbound, cutoffbound, maxbound);
195 }
196
197 /* we want to plunge again: prefer children over siblings, and siblings over leaves,
198 * but only select a child or sibling, if its dual bound is small enough;
199 * prefer using nodes with higher node selection priority assigned by the branching rule
200 */
201 node = SCIPgetPrioChild(scip);
202 if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
203 {
204 *selnode = node;
205 SCIPdebugMsg(scip, " -> selected prio child: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
206 }
207 else
208 {
209 node = SCIPgetBestChild(scip);
210 if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
211 {
212 *selnode = node;
213 SCIPdebugMsg(scip, " -> selected best child: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
214 }
215 else
216 {
217 node = SCIPgetPrioSibling(scip);
218 if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
219 {
220 *selnode = node;
221 SCIPdebugMsg(scip, " -> selected prio sibling: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
222 }
223 else
224 {
225 node = SCIPgetBestSibling(scip);
226 if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
227 {
228 *selnode = node;
229 SCIPdebugMsg(scip, " -> selected best sibling: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
230 }
231 else
232 {
233 *selnode = SCIPgetBestNode(scip);
234 SCIPdebugMsg(scip, " -> selected best leaf: lower=%g\n",
235 *selnode != NULL ? SCIPnodeGetLowerbound(*selnode) : SCIPinfinity(scip));
236 }
237 }
238 }
239 }
240 }
241
242 return SCIP_OKAY;
243}
244
245
246/** node comparison method of node selector */
247static
249{ /*lint --e{715}*/
250 SCIP_Real lowerbound1;
251 SCIP_Real lowerbound2;
252
253 assert(nodesel != NULL);
254 assert(scip != NULL);
255
256 lowerbound1 = SCIPnodeGetLowerbound(node1);
257 lowerbound2 = SCIPnodeGetLowerbound(node2);
258 if( SCIPisLT(scip, lowerbound1, lowerbound2) )
259 return -1;
260 else if( SCIPisGT(scip, lowerbound1, lowerbound2) )
261 return +1;
262 else
263 {
264 SCIP_Real estimate1;
265 SCIP_Real estimate2;
266
267 estimate1 = SCIPnodeGetEstimate(node1);
268 estimate2 = SCIPnodeGetEstimate(node2);
269 if( (SCIPisInfinity(scip, estimate1) && SCIPisInfinity(scip, estimate2)) ||
270 (SCIPisInfinity(scip, -estimate1) && SCIPisInfinity(scip, -estimate2)) ||
271 SCIPisEQ(scip, estimate1, estimate2) )
272 {
273 SCIP_NODETYPE nodetype1;
274 SCIP_NODETYPE nodetype2;
275
276 nodetype1 = SCIPnodeGetType(node1);
277 nodetype2 = SCIPnodeGetType(node2);
278 if( nodetype1 == SCIP_NODETYPE_CHILD && nodetype2 != SCIP_NODETYPE_CHILD )
279 return -1;
280 else if( nodetype1 != SCIP_NODETYPE_CHILD && nodetype2 == SCIP_NODETYPE_CHILD )
281 return +1;
282 else if( nodetype1 == SCIP_NODETYPE_SIBLING && nodetype2 != SCIP_NODETYPE_SIBLING )
283 return -1;
284 else if( nodetype1 != SCIP_NODETYPE_SIBLING && nodetype2 == SCIP_NODETYPE_SIBLING )
285 return +1;
286 else
287 {
288 int depth1;
289 int depth2;
290
291 depth1 = SCIPnodeGetDepth(node1);
292 depth2 = SCIPnodeGetDepth(node2);
293 if( depth1 < depth2 )
294 return -1;
295 else if( depth1 > depth2 )
296 return +1;
297 else
298 return 0;
299 }
300 }
301
302 if( SCIPisLT(scip, estimate1, estimate2) )
303 return -1;
304
305 assert(SCIPisGT(scip, estimate1, estimate2));
306 return +1;
307 }
308}
309
310
311/*
312 * bfs specific interface methods
313 */
314
315/** creates the node selector for best first search and includes it in SCIP */
317 SCIP* scip /**< SCIP data structure */
318 )
319{
320 SCIP_NODESELDATA* nodeseldata;
321 SCIP_NODESEL* nodesel;
322
323 /* allocate and initialize node selector data; this has to be freed in the destructor */
324 SCIP_CALL( SCIPallocBlockMemory(scip, &nodeseldata) );
325
326 /* include node selector */
328 nodeselSelectBfs, nodeselCompBfs, nodeseldata) );
329
330 assert(nodesel != NULL);
331
332 SCIP_CALL( SCIPsetNodeselCopy(scip, nodesel, nodeselCopyBfs) );
333 SCIP_CALL( SCIPsetNodeselFree(scip, nodesel, nodeselFreeBfs) );
334
335 /* add node selector parameters */
337 "nodeselection/bfs/minplungedepth",
338 "minimal plunging depth, before new best node may be selected (-1 for dynamic setting)",
339 &nodeseldata->minplungedepth, TRUE, MINPLUNGEDEPTH, -1, INT_MAX, NULL, NULL) );
341 "nodeselection/bfs/maxplungedepth",
342 "maximal plunging depth, before new best node is forced to be selected (-1 for dynamic setting)",
343 &nodeseldata->maxplungedepth, TRUE, MAXPLUNGEDEPTH, -1, INT_MAX, NULL, NULL) );
345 "nodeselection/bfs/maxplungequot",
346 "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where plunging is performed",
347 &nodeseldata->maxplungequot, TRUE, MAXPLUNGEQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
348
349 return SCIP_OKAY;
350}
351
#define NULL
Definition def.h:257
#define SCIP_REAL_MAX
Definition def.h:167
#define MIN(x, y)
Definition def.h:233
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define MAX(x, y)
Definition def.h:229
#define SCIP_CALL(x)
Definition def.h:364
#define SCIPdebugMsg
SCIP_RETCODE SCIPincludeNodeselBfs(SCIP *scip)
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
SCIP_NODETYPE SCIPnodeGetType(SCIP_NODE *node)
Definition tree.c:8503
SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
Definition tree.c:8533
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition tree.c:8553
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition tree.c:8523
SCIP_RETCODE SCIPincludeNodeselBasic(SCIP *scip, SCIP_NODESEL **nodesel, const char *name, const char *desc, int stdpriority, int memsavepriority, SCIP_DECL_NODESELSELECT((*nodeselselect)), SCIP_DECL_NODESELCOMP((*nodeselcomp)), SCIP_NODESELDATA *nodeseldata)
void SCIPnodeselSetData(SCIP_NODESEL *nodesel, SCIP_NODESELDATA *nodeseldata)
Definition nodesel.c:1273
SCIP_RETCODE SCIPsetNodeselFree(SCIP *scip, SCIP_NODESEL *nodesel,)
SCIP_NODESELDATA * SCIPnodeselGetData(SCIP_NODESEL *nodesel)
Definition nodesel.c:1263
SCIP_RETCODE SCIPsetNodeselCopy(SCIP *scip, SCIP_NODESEL *nodesel,)
const char * SCIPnodeselGetName(SCIP_NODESEL *nodesel)
Definition nodesel.c:1195
SCIP_Longint SCIPgetNSolsFound(SCIP *scip)
int SCIPgetMaxDepth(SCIP *scip)
SCIP_Longint SCIPgetNStrongbranchLPIterations(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Longint SCIPgetNNodeLPIterations(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_NODE * SCIPgetBestSibling(SCIP *scip)
Definition scip_tree.c:336
SCIP_NODE * SCIPgetBestChild(SCIP *scip)
Definition scip_tree.c:320
SCIP_NODE * SCIPgetPrioSibling(SCIP *scip)
Definition scip_tree.c:304
SCIP_NODE * SCIPgetBestNode(SCIP *scip)
Definition scip_tree.c:368
int SCIPgetPlungeDepth(SCIP *scip)
Definition scip_tree.c:715
SCIP_NODE * SCIPgetPrioChild(SCIP *scip)
Definition scip_tree.c:288
return SCIP_OKAY
assert(minobj< SCIPgetCutoffbound(scip))
#define NODESEL_NAME
Definition nodesel_bfs.c:47
#define MAXPLUNGEQUOT
Definition nodesel_bfs.c:59
#define NODESEL_MEMSAVEPRIORITY
Definition nodesel_bfs.c:50
#define NODESEL_STDPRIORITY
Definition nodesel_bfs.c:49
#define NODESEL_DESC
Definition nodesel_bfs.c:48
#define MINPLUNGEDEPTH
Definition nodesel_bfs.c:57
#define MAXPLUNGEDEPTH
Definition nodesel_bfs.c:58
node selector for best first search
public methods for message output
public methods for node selectors
public methods for branch and bound tree
public methods for memory management
public methods for message handling
public methods for node selector plugins
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for querying solving statistics
public methods for the branch-and-bound tree
type definitions for miscellaneous datastructures
#define SCIP_DECL_NODESELCOMP(x)
struct SCIP_Nodesel SCIP_NODESEL
#define SCIP_DECL_NODESELCOPY(x)
#define SCIP_DECL_NODESELSELECT(x)
#define SCIP_DECL_NODESELFREE(x)
struct SCIP_NodeselData SCIP_NODESELDATA
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Node SCIP_NODE
Definition type_tree.h:63
enum SCIP_NodeType SCIP_NODETYPE
Definition type_tree.h:53
@ SCIP_NODETYPE_CHILD
Definition type_tree.h:44
@ SCIP_NODETYPE_SIBLING
Definition type_tree.h:43