Scippy

SCIP

Solving Constraint Integer Programs

branch_lookahead.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-2025 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 branch_lookahead.c
26 * @ingroup DEFPLUGINS_BRANCH
27 * @ingroup BRANCHINGRULES
28 * @brief lookahead LP branching rule
29 * @author Christoph Schubert
30 * @author Gerald Gamrath
31 *
32 * The (multi-level) lookahead branching rule applies strong branching to every fractional value of the LP solution
33 * at the current node of the branch-and-bound tree, as well as recursivly to every temporary child problem created by this
34 * strong branching. The rule selects the candidate with the best proven dual bound.
35 *
36 * The branching rule was motivated by the following technical report:
37 *
38 * @par
39 * Wasu Glankwamdee and Jeff Linderoth@n
40 * Lookahead Branching for Mixed Integer Programming@n
41 * Technical Report 06T-004, Department of Industrial and Systems Engineering, Lehigh University.
42 *
43 * For a more mathematical description and a comparison between lookahead branching and other branching rules
44 * in SCIP, we refer to
45 *
46 * @par
47 * Christoph Schubert@n
48 * Multi-Level Lookahead Branching@n
49 * Master Thesis, Technische Universität Berlin, 2017@n
50 */
51
52/* Supported defines:
53 * PRINTNODECONS: prints the binary constraints added
54 * SCIP_DEBUG: prints detailed execution information
55 * SCIP_STATISTIC: prints some statistics after the branching rule is freed */
56
57/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
58
60#include "lpi/lpi.h"
62#include "scip/cons_logicor.h"
63#include "scip/pub_branch.h"
64#include "scip/pub_message.h"
65#include "scip/pub_misc.h"
66#include "scip/pub_tree.h"
67#include "scip/pub_var.h"
68#include "scip/scip_branch.h"
69#include "scip/scip_cons.h"
70#include "scip/scip_exact.h"
71#include "scip/scip_general.h"
72#include "scip/scip_lp.h"
73#include "scip/scip_mem.h"
74#include "scip/scip_message.h"
75#include "scip/scip_numerics.h"
76#include "scip/scip_param.h"
77#include "scip/scip_prob.h"
78#include "scip/scip_probing.h"
79#include "scip/scip_sol.h"
81#include "scip/scip_tree.h"
82#include "scip/scip_var.h"
83#include <string.h>
84
85#define BRANCHRULE_NAME "lookahead"
86#define BRANCHRULE_DESC "full strong branching over multiple levels"
87#define BRANCHRULE_PRIORITY 0
88#define BRANCHRULE_MAXDEPTH -1
89#define BRANCHRULE_MAXBOUNDDIST 1.0
90
91#define DEFAULT_USEBINARYCONSTRAINTS FALSE /**< should binary constraints be collected and applied? */
92#define DEFAULT_ADDCLIQUE FALSE /**< add binary constraints with two variables found at the root node also as a clique? */
93#define DEFAULT_ADDBINCONSROW 0 /**< should binary constraints be added as rows to the base LP?
94 * (0: no, 1: separate, 2: as initial rows) */
95#define DEFAULT_USEDOMAINREDUCTION TRUE /**< Should domain reductions be collected and applied? */
96#define DEFAULT_MERGEDOMAINREDUCTIONS FALSE /**< should domain reductions of feasible siblings should be merged? */
97#define DEFAULT_PREFERSIMPLEBOUNDS FALSE /**< should domain reductions only be applied if there are simple bound changes? */
98#define DEFAULT_ONLYVIOLDOMREDS FALSE /**< Should only domain reductions that violate the LP solution be applied? */
99#define DEFAULT_MAXNVIOLATEDCONS 1 /**< How many constraints that are violated by the base lp solution
100 * should be gathered until the rule is stopped and they are added? */
101#define DEFAULT_MAXNVIOLATEDBINCONS 0 /**< How many binary constraints that are violated by the base lp
102 * solution should be gathered until the rule is stopped and they are
103 * added? */
104#define DEFAULT_MAXNVIOLATEDDOMREDS 1 /**< How many domain reductions that are violated by the base lp solution
105 * should be gathered until the rule is stopped and they are added? */
106#define DEFAULT_STOREUNVIOLATEDSOL TRUE /**< If only non violating constraints are added, should the branching
107 * decision be stored till the next call? */
108#define DEFAULT_REEVALAGE 10LL /**< Max number of LPs solved after which a previous prob branching
109 * result is recalculated. */
110#define DEFAULT_REEVALAGEFSB 10LL /**< Max number of LPs solved after which a previous FSB scoring
111 * result is recalculated. */
112#define DEFAULT_RECURSIONDEPTH 2 /**< The max depth of LAB. */
113#define DEFAULT_ADDNONVIOCONS FALSE /**< Should binary constraints, that are not violated by the base LP, be
114 * collected and added? */
115#define DEFAULT_PROPAGATE TRUE /**< Should domain propagation be executed before each temporary node is
116 * solved? */
117#define DEFAULT_USELEVEL2DATA TRUE /**< should branching data generated at depth level 2 be stored for re-using it? */
118#define DEFAULT_APPLYCHILDBOUNDS FALSE /**< should bounds known for child nodes be applied? */
119#define DEFAULT_ENFORCEMAXDOMREDS FALSE /**< should the maximum number of domain reductions maxnviolateddomreds be enforced? */
120#define DEFAULT_UPDATEBRANCHINGRESULTS FALSE /**< should branching results (and scores) be updated w.r.t. proven dual bounds? */
121#define DEFAULT_MAXPROPROUNDS 0 /**< maximum number of propagation rounds to perform at temporary
122 * nodes (-1: unlimited, 0: SCIP default) */
123#define DEFAULT_ABBREVIATED TRUE /**< Toggles the abbreviated LAB. */
124#define DEFAULT_MAXNCANDS 4 /**< If abbreviated: The max number of candidates to consider at the base node */
125#define DEFAULT_MAXNDEEPERCANDS 2 /**< If abbreviated: The max number of candidates to consider per deeper node
126 * (0: same as base node) */
127#define DEFAULT_REUSEBASIS TRUE /**< If abbreviated: Should the information gathered to obtain the best
128 * candidates be reused? */
129#define DEFAULT_ABBREVPSEUDO FALSE /**< If abbreviated: Use pseudo costs to estimate the score of a
130 * candidate. */
131#define DEFAULT_LEVEL2AVGSCORE FALSE /**< should the average score be used for uninitialized scores in level 2? */
132#define DEFAULT_LEVEL2ZEROSCORE FALSE /**< should uninitialized scores be set to 0? */
133#define DEFAULT_SCORINGFUNCTION 'a' /**< scoring function to be used at the base level */
134#define DEFAULT_DEEPERSCORINGFUNCTION 'x' /**< scoring function to be used at deeper levels */
135#define DEFAULT_SCORINGSCORINGFUNCTION 'd' /**< scoring function to be used for FSB scoring */
136#define DEFAULT_MINWEIGHT 0.8 /**< default value for the weight of the minimum in the convex combination of two
137 * child gains (taken from the paper) */
138#define DEFAULT_WORSEFACTOR -1.0 /**< if the FSB score is of a candidate is worse than the best by this factor, skip this candidate (-1: disable) */
139#define DEFAULT_FILTERBYMAXGAIN FALSE /**< should lookahead branching only be applied if the max gain in level 1 is not uniquely that of the best candidate? */
140
141#ifdef SCIP_DEBUG
142/* Adjusted debug message that also prints the current probing depth. */
143#define LABdebugMessage(scip,lvl,...) do \
144 { \
145 SCIP_STAGE stage; \
146 SCIPverbMessage(scip, lvl, NULL, "[%s:%-4d] ", __FILE__, __LINE__); \
147 stage = SCIPgetStage(scip); \
148 if( stage == SCIP_STAGE_INIT ) \
149 { \
150 SCIPverbMessage(scip, lvl, NULL, "Init : "); \
151 } \
152 else if( stage == SCIP_STAGE_FREE ) \
153 { \
154 SCIPverbMessage(scip, lvl, NULL, "Free : "); \
155 } \
156 else if( SCIPinProbing(scip) ) \
157 { \
158 SCIPverbMessage(scip, lvl, NULL, "%*sDepth %i: ", \
159 2 * SCIPgetProbingDepth(scip), "", SCIPgetProbingDepth(scip)); \
160 } \
161 else \
162 { \
163 SCIPverbMessage(scip, lvl, NULL, "Base : "); \
164 } \
165 SCIPverbMessage(scip, lvl, NULL, __VA_ARGS__); \
166 } \
167 while( FALSE )
168
169/* Writes a debug message without the leading information. Can be used to append something to an output of LABdebugMessage*/
170#define LABdebugMessagePrint(scip,lvl,...) do \
171 { \
172 SCIPverbMessage(scip, lvl, NULL, __VA_ARGS__); \
173 } \
174 while( FALSE )
175#else
176#define LABdebugMessage(scip,lvl,...) /**/
177/*#define LABdebugMessagePrint(scip,lvl,...) only used with SCIP_DEBUG defined */
178#endif
179
180/*
181 * Data structures
182 */
183
184/** A struct holding information to speed up the solving time for solving a problem again. This is filled by the FSB
185 * scoring routine that is run to get the best candidates. It is then read by the actual ALAB routine. */
186typedef struct
187{
188 SCIP_LPISTATE* lpistate; /**< the basis information that may be set before another solve lp call */
189 SCIP_LPINORMS* lpinorms; /**< the norms that may be set before another solve lp call */
190 SCIP_Bool primalfeas; /**< indicates whether the solution was primal feasible */
191 SCIP_Bool dualfeas; /**< indicates whether the solution was dual feasible */
193
194/** Allocates the warm start information on the buffer and initializes it with default values. */
195static
197 SCIP* scip, /**< SCIP data structure */
198 WARMSTARTINFO** warmstartinfo /**< the warmstartinfo to allocate and initialize */
199 )
200{
201 assert(scip != NULL);
202 assert(warmstartinfo != NULL);
203
204 SCIP_CALL( SCIPallocBlockMemory(scip, warmstartinfo) );
205
206 (*warmstartinfo)->lpistate = NULL;
207 (*warmstartinfo)->lpinorms = NULL;
208 (*warmstartinfo)->primalfeas = FALSE;
209 (*warmstartinfo)->dualfeas = FALSE;
210
211 return SCIP_OKAY;
212}
213
214/** checks that the warm start info can be read into the lp solver. */
215static
217 WARMSTARTINFO* warmstartinfo /**< the warm start info to check (may be NULL) */
218 )
219{
220 return warmstartinfo != NULL && warmstartinfo->lpistate != NULL;
221}
222
223/** Frees the allocated buffer memory of the warm start info. */
224static
226 SCIP* scip, /**< SCIP data structure */
227 WARMSTARTINFO** warmstartinfo /**< the warm start info to free */
228 )
229{
230 SCIP_LPI* lpi;
231 BMS_BLKMEM* blkmem;
232
233 assert(scip != NULL);
234 assert(warmstartinfo != NULL);
235
236 SCIP_CALL( SCIPgetLPI(scip, &lpi) );
237 blkmem = SCIPblkmem(scip);
238
239 if( (*warmstartinfo)->lpistate != NULL )
240 {
241 SCIP_CALL( SCIPlpiFreeState(lpi, blkmem, &(*warmstartinfo)->lpistate) );
242 }
243
244 if( (*warmstartinfo)->lpinorms != NULL )
245 {
246 SCIP_CALL( SCIPlpiFreeNorms(lpi, blkmem, &(*warmstartinfo)->lpinorms) );
247 }
248
249 SCIPfreeBlockMemory(scip, warmstartinfo);
250
251 return SCIP_OKAY;
252}
253
254/** A struct containing all information needed to branch on a variable. */
255typedef struct
256{
257 SCIP_VAR* branchvar; /**< the variable to branch on */
258 SCIP_Real branchval; /**< the fractional value to branch on */
259 SCIP_Real fracval; /**< the fractional part of the value to branch on (val - floor(val)) */
260 WARMSTARTINFO* downwarmstartinfo; /**< the warm start info containing the lp data from a previous down branch */
261 WARMSTARTINFO* upwarmstartinfo; /**< the warm start info containing the lp data from a previous up branch */
262} CANDIDATE;
263
264/** Allocates the candidate on the buffer and initializes it with default values. */
265static
267 SCIP* scip, /**< SCIP data structure */
268 CANDIDATE** candidate /**< the candidate to allocate and initialize */
269 )
270{
271 assert(scip != NULL);
272 assert(candidate != NULL);
273
274 SCIP_CALL( SCIPallocBlockMemory(scip, candidate) );
275
276 (*candidate)->downwarmstartinfo = NULL;
277 (*candidate)->upwarmstartinfo = NULL;
278 (*candidate)->branchvar = NULL;
279
280 return SCIP_OKAY;
281}
282
283/** free the warm starting information for the given candidate */
284static
286 SCIP* scip, /**< SCIP data structure */
287 CANDIDATE* candidate /**< the candidate to free the warm starting information for */
288 )
289{
290 assert(scip != NULL);
291 assert(candidate != NULL);
292
293 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "freeing warmstart info of candidate <%s>(%u/%u)...\n",
294 SCIPvarGetName(candidate->branchvar),
295 candidate->upwarmstartinfo != NULL, candidate->downwarmstartinfo != NULL);
296
297 if( candidate->upwarmstartinfo != NULL )
298 {
300 }
301 if( candidate->downwarmstartinfo != NULL )
302 {
304 }
305
306 return SCIP_OKAY;
307}
308
309
310/** Frees the allocated buffer memory of the candidate and clears the contained lpi memories. */
311static
313 SCIP* scip, /**< SCIP data structure */
314 CANDIDATE** candidate /**< the candidate to free */
315 )
316{
317 assert(scip != NULL);
318 assert(candidate != NULL);
319
320 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "freeing candidate <%s>(%u/%u)...\n",
321 (*candidate) != NULL ? SCIPvarGetName((*candidate)->branchvar) : "none",
322 (*candidate)->upwarmstartinfo != NULL, (*candidate)->downwarmstartinfo != NULL);
323
324 /* if a candidate is freed, we no longer need the content of the warm start info */
326
327 SCIPfreeBlockMemory(scip, candidate);
328 return SCIP_OKAY;
329}
330
331/** Store the current lp solution in the warm start info for further usage. */
332static
334 SCIP* scip, /**< SCIP data structure */
335 CANDIDATE* candidate, /**< the branching candidate */
336 SCIP_Bool down /**< is the info for down branching? */
337 )
338{
339 SCIP_LPI* lpi;
340 BMS_BLKMEM* blkmem;
341 WARMSTARTINFO* warmstartinfo;
342
343 assert(scip != NULL);
344 assert(candidate != NULL);
345
346 SCIP_CALL( SCIPgetLPI(scip, &lpi) );
347 blkmem = SCIPblkmem(scip);
348
349 if( down )
350 {
351 if( candidate->downwarmstartinfo == NULL )
352 {
354 }
355 warmstartinfo = candidate->downwarmstartinfo;
356 }
357 else
358 {
359 if( candidate->upwarmstartinfo == NULL )
360 {
362 }
363 warmstartinfo = candidate->upwarmstartinfo;
364 }
365
366 SCIP_CALL( SCIPlpiGetState(lpi, blkmem, &warmstartinfo->lpistate) );
367
368 SCIP_CALL( SCIPlpiGetNorms(lpi, blkmem, &warmstartinfo->lpinorms) );
369
370 warmstartinfo->primalfeas = SCIPlpiIsPrimalFeasible(lpi);
371 warmstartinfo->dualfeas = SCIPlpiIsDualFeasible(lpi);
372
373 assert(warmstartinfo->lpistate != NULL);
374 /* warmstartinfo->lpinorms may be NULL */
375
376 return SCIP_OKAY;
377}
378
379/** returns whether the candidate has stored warm starting information for the given direction */
380static
382 CANDIDATE* candidate, /**< the branching candidate */
383 SCIP_Bool down /**< is the info for down branching? */
384 )
385{
386 assert(candidate != NULL);
387
388 return warmStartInfoIsAvailable(down ? candidate->downwarmstartinfo : candidate->upwarmstartinfo);
389}
390
391
392/** loads the warm starting information of the candidate for the given direction */
393static
395 SCIP* scip, /**< SCIP data structure */
396 CANDIDATE* candidate, /**< the branching candidate */
397 SCIP_Bool down /**< is the info for down branching? */
398 )
399{
400 WARMSTARTINFO* warmstartinfo;
401
402 assert(scip != NULL);
403 assert(candidate != NULL);
404
405 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "loading basis...\n");
406
407 if( down )
408 warmstartinfo = candidate->downwarmstartinfo;
409 else
410 warmstartinfo = candidate->upwarmstartinfo;
411
412 /* As we solved the very same LP some time earlier and stored the state (the basis) and the norms, we can now set those in
413 * the LP solver, such that the solution does not (in best case) need any further calculation.
414 * Some iterations may occur, as the conflict analysis may have added some constraints in the meantime. */
415 SCIP_CALL( SCIPsetProbingLPState(scip, &(warmstartinfo->lpistate), &(warmstartinfo->lpinorms), warmstartinfo->primalfeas,
416 warmstartinfo->dualfeas) );
417
418 /* The state and norms will be freed later by the SCIP framework. Therefore they are set to NULL to enforce that we won't
419 * free them on our own. */
420 assert(warmstartinfo->lpistate == NULL);
421 assert(warmstartinfo->lpinorms == NULL);
422
423 return SCIP_OKAY;
424}
425
426
427/** Holds the information needed for branching on a variable. */
428typedef struct
429{
430 SCIP_VAR* branchvar; /**< the variable to branch on, may be NULL */
431 SCIP_Real branchval; /**< the fractional value to branch on */
432 SCIP_Real* downlowerbounds; /**< variable lower bounds for down child */
433 SCIP_Real* downupperbounds; /**< variable upper bounds for down child */
434 SCIP_Real* uplowerbounds; /**< variable lower bounds for up child */
435 SCIP_Real* upupperbounds; /**< variable upper bounds for up child */
436 SCIP_Real downdb; /**< dual bound for down branch */
437 SCIP_Real updb; /**< dual bound for the up branch */
438 SCIP_Real proveddb; /**< proven dual bound for the current node */
439 SCIP_Real score; /**< score of the branching decision */
440 SCIP_Bool downdbvalid; /**< Indicator for the validity of the downdb value. Is FALSE, if no actual
441 * branching occurred or the value was determined by an LP not solved to
442 * optimality. */
443 SCIP_Bool updbvalid; /**< Indicator for the validity of the updb value. Is FALSE, if no actual
444 * branching occurred or the value was determined by an LP not solved to
445 * optimality. */
446 SCIP_Bool boundsvalid; /**< are variable bounds for down and up child valid? */
447 int boundssize; /**< size of bounds arrays */
449
450/** initialize a branching decsion with default values */
451static
453 SCIP* scip, /**< SCIP data structure */
454 BRANCHINGDECISION* decision /**< the decision to initialize */
455 )
456{
457 assert(scip != NULL);
458 assert(decision != NULL);
459
460 decision->branchvar = NULL;
461 decision->branchval = SCIP_INVALID;
462 decision->downlowerbounds = NULL;
463 decision->downupperbounds = NULL;
464 decision->uplowerbounds = NULL;
465 decision->upupperbounds = NULL;
466 decision->downdb = -SCIPinfinity(scip);
467 decision->downdbvalid = FALSE;
468 decision->updb = -SCIPinfinity(scip);
469 decision->updbvalid = FALSE;
470 decision->boundsvalid = FALSE;
471 decision->proveddb = -SCIPinfinity(scip);
472 decision->score = -SCIPinfinity(scip);
473 decision->boundssize = 0;
474}
475
476
477/** allocates a branching decision in the buffer and initializes it with default values. */
478static
480 SCIP* scip, /**< SCIP data structure */
481 BRANCHINGDECISION** decision /**< pointer to the decision to allocate and initialize */
482 )
483{
484 assert(scip != NULL);
485 assert(decision != NULL);
486
487 SCIP_CALL( SCIPallocBuffer(scip, decision) );
488
489 branchingDecisionInit(scip, *decision);
490
491 return SCIP_OKAY;
492}
493
494/** copies the data from the source branching decision storage to the target storage;
495 * this is used to store the most important information (i.e., the dual bounds obtained) so that it can be used in a
496 * subsequent call in case the LP solution did not change because we only added bound changes that did not forbid the
497 * current LP solution;
498 * however, we do not want to store all the domain changes for the two potential child nodes for this rare case, they
499 * will be identified when processing the child nodes anyway
500 */
501static
503 BRANCHINGDECISION* sourcedecision, /**< the source branching decision */
504 BRANCHINGDECISION* targetdecision /**< the target branching decision */
505 )
506{
507 assert(sourcedecision != NULL);
508 assert(targetdecision != NULL);
509
510 targetdecision->branchvar = sourcedecision->branchvar;
511 targetdecision->branchval = sourcedecision->branchval;
512 targetdecision->downdb = sourcedecision->downdb;
513 targetdecision->downdbvalid = sourcedecision->downdbvalid;
514 targetdecision->updb = sourcedecision->updb;
515 targetdecision->updbvalid = sourcedecision->updbvalid;
516 targetdecision->proveddb = sourcedecision->proveddb;
517 targetdecision->score = sourcedecision->score;
518
519 assert(targetdecision->downlowerbounds == NULL);
520 assert(targetdecision->downupperbounds == NULL);
521 assert(targetdecision->uplowerbounds == NULL);
522 assert(targetdecision->upupperbounds == NULL);
523 assert(targetdecision->boundsvalid == FALSE);
524 assert(targetdecision->boundssize == 0);
525}
526
527/** Checks whether the given branching decision can be used to branch on. */
528static
530 BRANCHINGDECISION* decision /**< the branching decision to check */
531 )
532{
533 assert(decision != NULL);
534
535 /* a branching decision is deemed valid, if the var pointer is not on the default NULL value (see the allocate method) */
536 return decision->branchvar != NULL;
537}
538
539/* ensure that the array that stores the bounds for both child nodes is large enough */
540static
542 SCIP* scip, /**< SCIP data structure */
543 BRANCHINGDECISION* decision, /**< branching decision */
544 int nvars /**< number of problem variables */
545 )
546{
547 assert(decision != NULL);
548
549 if( decision->boundssize == 0 )
550 {
551 decision->boundssize = nvars;
556 }
557 assert(decision->boundssize == nvars);
558
559 return SCIP_OKAY;
560}
561
562/** Frees the allocated memory of the branching decision. */
563static
565 SCIP* scip, /**< SCIP data structure */
566 BRANCHINGDECISION** decision /**< pointer to the decision to be freed */
567 )
568{
569 assert(scip != NULL);
570 assert(decision != NULL);
571
572 if( (*decision)->boundssize != 0 )
573 {
574 assert((*decision)->downlowerbounds != NULL);
575 assert((*decision)->downupperbounds != NULL);
576 assert((*decision)->uplowerbounds != NULL);
577 assert((*decision)->upupperbounds != NULL);
578
579 SCIPfreeBlockMemoryArray(scip, &(*decision)->downlowerbounds, (*decision)->boundssize);
580 SCIPfreeBlockMemoryArray(scip, &(*decision)->downupperbounds, (*decision)->boundssize);
581 SCIPfreeBlockMemoryArray(scip, &(*decision)->uplowerbounds, (*decision)->boundssize);
582 SCIPfreeBlockMemoryArray(scip, &(*decision)->upupperbounds, (*decision)->boundssize);
583 }
584
585 SCIPfreeBuffer(scip, decision);
586}
587
588/** A container to hold the result of a branching. */
589typedef struct
590{
591 SCIP_Real objval; /**< The objective value of the solved lp. Only contains meaningful data, if
592 * cutoff == FALSE. */
593 SCIP_Real dualbound; /**< The best dual bound for this branching, may be changed by deeper level
594 * branchings. */
595 SCIP_Longint niterations; /**< The number of probing iterations needed in sub branch. */
596 SCIP_Bool cutoff; /**< Indicates whether the node was infeasible and was cutoff. */
597 SCIP_Bool dualboundvalid; /**< Is the value of the dual bound valid? That means, was the according LP
598 * or the sub problems solved to optimality? */
599 int ndeepestcutoffs; /**< number of cutoffs on the lowest level below this child */
600 SCIP_Real deeperscore; /**< best score computed for the deeper lookahead level */
601 SCIP_Real bestgain; /**< best gain (w.r.t. to the base lp) on the lowest level below this child */
602 SCIP_Real totalgains; /**< sum over all gains that are valid in both children */
603 int ntotalgains; /**< number of gains summed in totalgains */
604 int ndeepestnodes; /**< number of nodes processed in the deepest level */
606
607/** Allocates a branching result in the buffer. */
608static
610 SCIP* scip, /**< SCIP data structure */
611 BRANCHINGRESULTDATA** resultdata /**< pointer to the result to be allocated */
612 )
613{
614 assert(scip != NULL);
615 assert(resultdata != NULL);
616
617 SCIP_CALL( SCIPallocBuffer(scip, resultdata) );
618
619 return SCIP_OKAY;
620}
621
622/** Initiates the branching result with default values. */
623static
625 SCIP* scip, /**< SCIP data structure */
626 BRANCHINGRESULTDATA* resultdata /**< pointer to the result to be initialized */
627 )
628{
629 assert(scip != NULL);
630 assert(resultdata != NULL);
631
632 resultdata->objval = -SCIPinfinity(scip);
633 resultdata->dualbound = -SCIPinfinity(scip);
634 resultdata->cutoff = FALSE;
635 resultdata->dualboundvalid = FALSE;
636 resultdata->niterations = 0;
637 resultdata->ndeepestcutoffs = 0;
638 resultdata->deeperscore = -SCIPinfinity(scip);
639 resultdata->bestgain = 0.;
640 resultdata->totalgains = 0.;
641 resultdata->ntotalgains = 0;
642 resultdata->ndeepestnodes = 0;
643}
644
645/** Copies the data from the source to the target. */
646static
648 BRANCHINGRESULTDATA* sourcedata, /**< the source branching result */
649 BRANCHINGRESULTDATA* targetdata /**< the target branching result */
650 )
651{
652 assert(sourcedata != NULL);
653 assert(targetdata != NULL);
654
655 targetdata->cutoff = sourcedata->cutoff;
656 targetdata->objval = sourcedata->objval;
657 targetdata->dualbound = sourcedata->dualbound;
658 targetdata->dualboundvalid = sourcedata->dualboundvalid;
659 targetdata->niterations = sourcedata->niterations;
660 targetdata->ndeepestcutoffs = sourcedata->ndeepestcutoffs;
661 targetdata->deeperscore = sourcedata->deeperscore;
662 targetdata->bestgain = sourcedata->bestgain;
663 targetdata->totalgains = sourcedata->totalgains;
664 targetdata->ntotalgains = sourcedata->ntotalgains;
665 targetdata->ndeepestnodes = sourcedata->ndeepestnodes;
666}
667
668/** Frees the allocated buffer memory of the branching result. */
669static
671 SCIP* scip, /**< SCIP data structure */
672 BRANCHINGRESULTDATA** resultdata /**< pointer to the result to be freed */
673 )
674{
675 assert(scip != NULL);
676 assert(resultdata != NULL);
677
678 SCIPfreeBuffer(scip, resultdata);
679}
680
681/** a container to hold the result of a second-level LP */
682typedef struct
683{
684 SCIP_Real lpobjval; /**< the objective value of the solved lp; only contains meaningful data, if
685 * cutoff == FALSE. */
686 SCIP_Real branchval1; /**< new bound for first branching variable */
687 SCIP_Real branchval2; /**< new bound for second branching variable */
688 unsigned int branchvar1:30; /**< problem index of first branching variable */
689 unsigned int branchvar2:30; /**< problem index of second branching variable */
690 unsigned int branchdir1:1; /**< branching direction for first branching variable (0:down, 1:up) */
691 unsigned int branchdir2:1; /**< branching direction for second branching variable (0:down, 1:up) */
692 unsigned int cutoff:1; /**< indicates whether the node was infeasible and was cut off. */
693 unsigned int valid:1; /**< is the lpobjval a valid dual bound? */
695
696/** a container to hold the results of all second-level LPs */
697typedef struct
698{
699 LEVEL2RESULT** level2results; /**< array with all level2 results */
700 SCIP_Real branchval1; /**< new bound for first branching variable */
701 SCIP_Real branchval2; /**< new bound for second branching variable */
702 int nlevel2results; /**< number of level2 results stored */
703 int level2resultssize; /**< size of level2results array */
704 unsigned int branchvar1:30; /**< problem index of first branching variable */
705 unsigned int branchvar2:30; /**< problem index of second branching variable */
706 unsigned int branchdir1:1; /**< branching direction for first branching variable (0:down, 1:up) */
707 unsigned int branchdir2:1; /**< branching direction for second branching variable (0:down, 1:up) */
708} LEVEL2DATA;
709
710/** allocates a double branching result in the memory and fills it with the information stored in the level 2 data */
711static
713 SCIP* scip, /**< SCIP data structure */
714 LEVEL2DATA* data, /**< level2 data */
715 LEVEL2RESULT** result /**< pointer to the result to be allocated */
716 )
717{
718 assert(scip != NULL);
719 assert(data != NULL);
720 assert(result != NULL);
721
723
724 if( data->branchvar1 < data->branchvar2 )
725 {
726 (*result)->branchval1 = data->branchval1;
727 (*result)->branchval2 = data->branchval2;
728 (*result)->branchvar1 = data->branchvar1; /*lint !e732*/
729 (*result)->branchvar2 = data->branchvar2; /*lint !e732*/
730 (*result)->branchdir1 = data->branchdir1;
731 (*result)->branchdir2 = data->branchdir2;
732 }
733 else
734 {
735 (*result)->branchval1 = data->branchval2;
736 (*result)->branchval2 = data->branchval1;
737 (*result)->branchvar1 = data->branchvar2; /*lint !e732*/
738 (*result)->branchvar2 = data->branchvar1; /*lint !e732*/
739 (*result)->branchdir1 = data->branchdir2;
740 (*result)->branchdir2 = data->branchdir1;
741 }
742
743 return SCIP_OKAY;
744}
745
746
747#ifdef SCIP_DEBUG
748/** prints the double branching result */
749static
751 SCIP* scip, /**< SCIP data structure */
752 LEVEL2RESULT* result /**< pointer to the result to be initialized */
753 )
754{
755 SCIP_VAR** vars;
756
757 assert(result != NULL);
758
759 vars = SCIPgetVars(scip);
760
762 "level 2 result: <%s> %s %g + <%s> %s %g: lpval: %.9g, inf: %d, valid: %d\n",
763 SCIPvarGetName(vars[result->branchvar1]), result->branchdir1 ? ">=" : "<=", result->branchval1,
764 SCIPvarGetName(vars[result->branchvar2]), result->branchdir2 ? ">=" : "<=", result->branchval2,
765 result->lpobjval, result->cutoff, result->valid);
766}
767#else
768#define level2resultPrint(scip,result) /**/
769#endif
770
771/** frees the allocated memory of the double branching result */
772static
774 SCIP* scip, /**< SCIP data structure */
775 LEVEL2RESULT** result /**< pointer to the result to be freed */
776 )
777{
778 assert(scip != NULL);
779 assert(result != NULL);
780
781 SCIPfreeBlockMemory(scip, result);
782}
783
784/** returns TRUE iff both level 2 results are equal; two branchings are equal if they branched on the same variables
785 * with the same values
786 */
787static
789 LEVEL2RESULT* result1, /**< first level 2 result */
790 LEVEL2RESULT* result2 /**< second level 2 result */
791 )
792{
793 assert(result1->branchvar1 < result1->branchvar2);
794 assert(result2->branchvar1 < result2->branchvar2);
795
796 /* check all cases */
797 if( result1->branchvar1 != result2->branchvar1
798 || result1->branchvar2 != result2->branchvar2
799 || result1->branchdir1 != result2->branchdir1
800 || result1->branchdir2 != result2->branchdir2
801 || result1->branchval1 > result2->branchval1 + 0.5
802 || result1->branchval1 < result2->branchval1 - 0.5
803 || result1->branchval2 > result2->branchval2 + 0.5
804 || result1->branchval2 < result2->branchval2 - 0.5)
805 return FALSE;
806
807 return TRUE;
808}
809
810/** allocates the level2 data */
811static
813 SCIP* scip, /**< SCIP data structure */
814 LEVEL2DATA** data /**< pointer to the data to be allocated */
815 )
816{
817 assert(scip != NULL);
818 assert(data != NULL);
819
821
822 (*data)->level2results = NULL;
823 (*data)->branchval1 = -SCIPinfinity(scip);
824 (*data)->branchval2 = -SCIPinfinity(scip);
825 (*data)->nlevel2results = 0;
826 (*data)->level2resultssize = 0;
827 (*data)->branchvar1 = 0;
828 (*data)->branchvar2 = 0;
829 (*data)->branchdir1 = 0;
830 (*data)->branchdir2 = 0;
831
832 return SCIP_OKAY;
833}
834
835/** frees the allocated memory of the level2 data */
836static
838 SCIP* scip, /**< SCIP data structure */
839 LEVEL2DATA** data /**< pointer to the data to be freed */
840 )
841{
842 assert(scip != NULL);
843 assert(data != NULL);
844
845 while( (*data)->nlevel2results > 0 )
846 {
847 --(*data)->nlevel2results;
848 level2resultFree(scip, &((*data)->level2results[(*data)->nlevel2results]));
849 }
850 assert((*data)->nlevel2results == 0);
851
852 if( (*data)->level2results != NULL )
853 {
854 SCIPfreeBlockMemoryArray(scip, &(*data)->level2results, (*data)->level2resultssize);
855 }
856
858}
859
860/** ensures that level2results can store at least one more element */
861static
863 SCIP* scip, /**< SCIP data structure */
864 LEVEL2DATA* data /**< level2 data */
865 )
866{
867 assert(scip != NULL);
868 assert(data != NULL);
869
870 if( data->nlevel2results >= data->level2resultssize )
871 {
872 int newsize = SCIPcalcMemGrowSize(scip, data->level2resultssize + 1);
873
875 data->level2resultssize = newsize;
876 }
877
878 return SCIP_OKAY;
879}
880
881/** get a result from the level 2 data */
882static
884 SCIP* scip, /**< SCIP data structure */
885 LEVEL2DATA* data, /**< level2 data */
886 LEVEL2RESULT** result /**< pointer to store result */
887 )
888{
889 LEVEL2RESULT* tmpresult;
890 int i;
891
892 assert(data != NULL);
893 assert(result != NULL);
894
895 *result = NULL;
896
897 /* we branched twice on the same variable; the result cannot be stored already */
898 if( data->branchvar1 == data->branchvar2 )
899 {
902 return SCIP_OKAY;
903 }
904
905 SCIP_CALL( level2resultCreateFromData(scip, data, &tmpresult) );
906
907 /* search for a level 2 result with the same branching decisions */
908 for( i = 0; i < data->nlevel2results; ++i )
909 {
910 if( level2resultEqual(data->level2results[i], tmpresult) )
911 {
912 *result = data->level2results[i];
913 }
914 }
915
916 level2resultFree(scip, &tmpresult);
917
918 return SCIP_OKAY;
919}
920
921
922/** store a new result in the level 2 data */
923static
925 SCIP* scip, /**< SCIP data structure */
926 LEVEL2DATA* data, /**< level2 data */
927 SCIP_Real lpobjval, /**< LP objective value */
928 SCIP_Bool cutoff, /**< was the LP infeasible? */
929 SCIP_Bool valid, /**< is the LP value a valid dual bound? */
930 SCIP_Bool* duplicate /**< pointer to store whether information for the same branching decisions was already stored */
931 )
932{
933 LEVEL2RESULT* result;
934 int i;
935
936 assert(scip != NULL);
937 assert(data != NULL);
938 assert(duplicate != NULL);
939
940 *duplicate = FALSE;
941
942 /* we branched twice on the same variable; the result cannot be re-used lated */
943 if( data->branchvar1 == data->branchvar2 )
944 {
947 return SCIP_OKAY;
948 }
949
951
952 SCIP_CALL( level2resultCreateFromData(scip, data, &result) );
953
954 result->lpobjval = lpobjval;
955 result->cutoff = cutoff;
956 result->valid = valid;
957
958 /* search for a level 2 result with the same branching decisions*/
959 for( i = 0; i < data->nlevel2results; ++i )
960 {
961 if( level2resultEqual( data->level2results[i], result) )
962 {
963 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "same level2 node already processed:\n");
965 level2resultPrint(scip, result);
966 *duplicate = TRUE;
967 }
968 }
969
970 data->level2results[data->nlevel2results] = result;
971 ++data->nlevel2results;
972 assert(data->nlevel2results <= data->level2resultssize);
973
974 return SCIP_OKAY;
975}
976
977
978/** The data that is preserved over multiple runs of the branching rule. */
979typedef struct
980{
981 BRANCHINGDECISION* olddecision; /**< The previous decision that gets used for the case that in the previous run
982 * only non-violating implicit binary constraints were added.*/
983 SCIP_Longint oldnnodelpiterations; /**< node LP iterations when previous branching decision was stored */
984 SCIP_Longint oldnnodelps; /**< node LPs when previous branching decision was stored */
985 SCIP_Longint oldntotalnodes; /**< node at which previous branching decision was stored */
986 SCIP_Longint* lastbranchid; /**< The node id at which the var was last branched on (for a given branching
987 * var). */
988 SCIP_Longint* lastbranchnlps; /**< The number of (non-probing) LPs that where solved when the var was last
989 * branched on. */
990 SCIP_Real* lastbranchlpobjval; /**< The lp objval at which var was last branched on. */
991 BRANCHINGRESULTDATA** lastbranchupres; /**< The result of the last up branching for a given var. */
992 BRANCHINGRESULTDATA** lastbranchdownres; /**< The result of the last down branching for a given var. */
993 int restartindex; /**< The index at which the iteration over the number of candidates starts. */
994 int nvars; /**< The number of variables that can be stored in the arrays. */
996
997/** The parameter that can be changed by the user/caller and alter the behaviour of the lookahead branching. */
998typedef struct
999{
1000 SCIP_Longint reevalage; /**< The number of "normal" (not probing) lps that may have been solved before
1001 * we stop using old data and start recalculating new first level data. */
1002 SCIP_Longint reevalagefsb; /**< The number of "normal" (not probing) lps that may have been solved before
1003 * we stop using old FSB data and start recalculating new first level data. */
1004 int maxnviolatedcons; /**< The number of constraints (domain reductions and binary constraints) we
1005 * want to gather before restarting the run. Set to -1 for an unbounded
1006 * number of constraints. */
1007 int maxnviolatedbincons;/**< The number of binary constraints we want to gather before restarting the
1008 * run. Set to -1 for an undbounded number of binary constraints. */
1009 int maxnviolateddomreds;/**< The number of domain reductions we want to gather before restarting the
1010 * run. Set to -1 for an undbounded number of domain reductions. */
1011 int recursiondepth; /**< How deep should the recursion go? Default for Lookahead: 2 */
1012 int maxncands; /**< If abbreviated == TRUE, at most how many candidates should be handled at the base node? */
1013 int maxndeepercands; /**< If abbreviated == TRUE, at most how many candidates should be handled in deeper nodes? */
1014 SCIP_Bool usedomainreduction; /**< indicates whether the data for domain reductions should be gathered and
1015 * used. */
1016 SCIP_Bool mergedomainreductions; /**< should domain reductions of feasible siblings should be merged? */
1017 SCIP_Bool prefersimplebounds; /**< should domain reductions only be applied if there are simple bound changes? */
1018 SCIP_Bool onlyvioldomreds; /**< Should only domain reductions that violate the LP solution be applied? */
1019 SCIP_Bool usebincons; /**< indicates whether the data for the implicit binary constraints should
1020 * be gathered and used */
1021 int addbinconsrow; /**< should binary constraints be added as rows to the base LP?
1022 * (0: no, 1: separate, 2: as initial rows) */
1023 SCIP_Bool addnonviocons; /**< Should constraints be added, that are not violated by the base LP? */
1024 SCIP_Bool abbreviated; /**< Should the abbreviated version be used? */
1025 SCIP_Bool reusebasis; /**< If abbreviated == TRUE, should the solution lp-basis of the FSB run be
1026 * used in the first abbreviated level? */
1027 SCIP_Bool storeunviolatedsol; /**< Should a solution/decision be stored, to speed up the next iteration
1028 * after adding the constraints/domreds? */
1029 SCIP_Bool abbrevpseudo; /**< If abbreviated == TRUE, should pseudocost values be used, to approximate
1030 * the scoring? */
1031 SCIP_Bool level2avgscore; /**< should the average score be used for uninitialized scores in level 2? */
1032 SCIP_Bool level2zeroscore; /**< should uninitialized scores in level 2 be set to zero? */
1033 SCIP_Bool addclique; /**< add binary constraints with two variables found at the root node also as a clique? */
1034 SCIP_Bool propagate; /**< Should the problem be propagated before solving each inner node? */
1035 SCIP_Bool uselevel2data; /**< should branching data generated at depth level 2 be stored for re-using it? */
1036 SCIP_Bool applychildbounds; /**< should bounds known for child nodes be applied? */
1037 SCIP_Bool enforcemaxdomreds; /**< should the maximum number of domain reductions maxnviolateddomreds be enforced? */
1038 SCIP_Bool updatebranchingresults; /**< should branching results (and scores) be updated w.r.t. proven dual bounds? */
1039 SCIP_Bool inscoring; /**< are we currently in FSB-scoring (only used internally) */
1040 int maxproprounds; /**< maximum number of propagation rounds to perform at temporary nodes
1041 * (-1: unlimited, 0: SCIP default) */
1042 char scoringfunction; /**< scoring function at base level */
1043 char deeperscoringfunction; /**< scoring function at deeper levels */
1044 char scoringscoringfunction;/**< scoring function for FSB scoring */
1045 SCIP_Real minweight; /**< weight of the min gain of two child problems */
1046 SCIP_Real worsefactor; /**< if the FSB score is of a candidate is worse than the best by this factor, skip this candidate (-1: disable) */
1047 SCIP_Bool filterbymaxgain; /**< should lookahead branching only be applied if the max gain in level 1 is not uniquely that of the best candidate? */
1049
1050
1051#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
1052#define MAXRESULT SCIP_DELAYNODE
1053
1054/** returns a human readable name for the given result enum value */
1055static
1056const char* getStatusString(
1057 SCIP_RESULT result /**< enum value to get the string representation for */
1058 )
1059{
1060 assert(result >= 1);
1061 assert(result <= 18);
1062
1063 switch( result )
1064 {
1065 case SCIP_DIDNOTRUN:
1066 return "SCIP_DIDNOTRUN";
1067 case SCIP_DELAYED:
1068 return "SCIP_DELAYED";
1069 case SCIP_DIDNOTFIND:
1070 return "SCIP_DIDNOTFIND";
1071 case SCIP_FEASIBLE:
1072 return "SCIP_FEASIBLE";
1073 case SCIP_INFEASIBLE:
1074 return "SCIP_INFEASIBLE";
1075 case SCIP_UNBOUNDED:
1076 return "SCIP_UNBOUNDED";
1077 case SCIP_CUTOFF:
1078 return "SCIP_CUTOFF";
1079 case SCIP_SEPARATED:
1080 return "SCIP_SEPARATED";
1081 case SCIP_NEWROUND:
1082 return "SCIP_NEWROUND";
1083 case SCIP_REDUCEDDOM:
1084 return "SCIP_REDUCEDDOM";
1085 case SCIP_CONSADDED:
1086 return "SCIP_CONSADDED";
1087 case SCIP_CONSCHANGED:
1088 return "SCIP_CONSCHANGED";
1089 case SCIP_BRANCHED:
1090 return "SCIP_BRANCHED";
1091 case SCIP_SOLVELP:
1092 return "SCIP_SOLVELP";
1093 case SCIP_FOUNDSOL:
1094 return "SCIP_FOUNDSOL";
1095 case SCIP_SUSPENDED:
1096 return "SCIP_SUSPENDED";
1097 case SCIP_SUCCESS:
1098 return "SCIP_SUCCESS";
1099 case SCIP_DELAYNODE:
1100 return "SCIP_DELAYNODE";
1101 default:
1102 SCIPerrorMessage("result code %d not treated in lookahead branching rule\n", result);
1103 SCIPABORT();
1104 return "UNKNOWN";
1105 }
1106}
1107#endif
1108
1109#ifdef SCIP_STATISTIC
1110/** The data used for some statistical analysis. */
1111typedef struct
1112{
1113 int* nresults; /**< Array of counters for each result state the lookahead branching finished.
1114 * The first (0) entry is unused, as the result states are indexed 1-based
1115 * and we use this index as our array index. */
1116 int* nsinglecutoffs; /**< The number of single cutoffs on a (probing) node per probingdepth. */
1117 int* nfullcutoffs; /**< The number of double cutoffs on a (probing) node per probingdepth. */
1118 int* nlpssolved; /**< The number of all lps solved for a given probingdepth (incl. FSB). */
1119 int* nlpssolvedfsb; /**< The number of lps solved by the initial FSB to get the FSB scores. */
1120 int* nduplicatelps; /**< The number of lps solved for duplicate grand-child nodes. */
1121 SCIP_Longint* nlpiterations; /**< The number of all lp iterations needed for a given probingdepth
1122 * (incl. FSB). */
1123 SCIP_Longint* nlpiterationsfsb; /**< The number of lp iterations needed to get the FSB scores. */
1124 int* npropdomred; /**< The number of domain reductions based on domain propagation per
1125 * progingdepth. */
1126 int* noldbranchused; /**< The number of times old branching data is used (see the reevalage
1127 * parameter in the CONFIGURATION struct) */
1128 int* noldbranchusedfsb; /**< The number of times old FSB scoring data is used (see the reevalagefsb
1129 * parameter in the CONFIGURATION struct) */
1130 int* chosenfsbcand; /**< If abbreviated, this is the number of times each candidate was finally
1131 * chosen by the following LAB */
1132 int* stopafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
1133 * scoring candidates by FSB, e.g., by adding constraints or domreds. */
1134 int* cutoffafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
1135 * scoring candidates by FSB because of a found cutoff. */
1136 int* domredafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
1137 * scoring candidates by FSB because of a found domain reduction. */
1138 int nsinglecandidate; /**< number of times a single candidate was given to the recursion routine */
1139 int nsingleafterfilter; /**< number of times a single candidate remained after filtering */
1140 int noldcandidate; /**< number of times the old candidate from last call with nonviolating
1141 * reductions was branched on */
1142 int nlperrorcalls; /**< number of times an LP error occured and LAB branched without completely
1143 * evaluating all candidates */
1144 int nlimitcalls; /**< number of times a time limit was reached and LAB branched without
1145 * completely evaluating all candidates */
1146 int ntotalresults; /**< The total sum of the entries in nresults. */
1147 int nbinconst; /**< The number of binary constraints added to the base node. */
1148 int nbinconstvio; /**< The number of binary constraints added to the base node, that are violated
1149 * by the LP at that node. */
1150 int ndomred; /**< The number of domain reductions added to the base node. */
1151 int ndomredvio; /**< The number of domain reductions added to the base node, that are violated
1152 * by the LP at that node. */
1153 int ndepthreached; /**< The number of times the branching was aborted due to a too small depth. */
1154 int ndomredcons; /**< The number of binary constraints ignored, as they would be dom reds. */
1155 int ncutoffproofnodes; /**< The number of nodes needed to prove all found cutoffs. */
1156 int ndomredproofnodes; /**< The number of nodes needed to prove all found domreds. */
1157 int ncliquesadded; /**< The number of cliques added in the root node. */
1158 int maxnbestcands; /**< if abbreviated, this is the maximum number of candidates to investigate */
1159 int recursiondepth; /**< The recursiondepth of the LAB. Can be used to access the depth-dependent
1160 * arrays contained in the statistics. */
1161} STATISTICS;
1162
1163/** Initializes the statistics with the start values. */
1164static
1165void statisticsInit(
1166 STATISTICS* statistics /**< the statistics to be initialized */
1167 )
1168{
1169 int i;
1170
1171 assert(statistics != NULL);
1172 assert(statistics->recursiondepth > 0);
1173
1174 statistics->nsinglecandidate = 0;
1175 statistics->nsingleafterfilter = 0;
1176 statistics->noldcandidate = 0;
1177 statistics->nlperrorcalls = 0;
1178 statistics->nlimitcalls = 0;
1179 statistics->ntotalresults = 0;
1180 statistics->nbinconst = 0;
1181 statistics->nbinconstvio = 0;
1182 statistics->ndomredvio = 0;
1183 statistics->ndepthreached = 0;
1184 statistics->ndomred = 0;
1185 statistics->ndomredcons = 0;
1186 statistics->ncutoffproofnodes = 0;
1187 statistics->ndomredproofnodes = 0;
1188 statistics->ncliquesadded = 0;
1189
1190 for( i = 0; i <= MAXRESULT; i++)
1191 {
1192 statistics->nresults[i] = 0;
1193 }
1194
1195 for( i = 0; i < statistics->recursiondepth; i++ )
1196 {
1197 statistics->noldbranchused[i] = 0;
1198 statistics->noldbranchusedfsb[i] = 0;
1199 statistics->npropdomred[i] = 0;
1200 statistics->nfullcutoffs[i] = 0;
1201 statistics->nlpssolved[i] = 0;
1202 statistics->nlpssolvedfsb[i] = 0;
1203 statistics->nduplicatelps[i] = 0;
1204 statistics->nlpiterations[i] = 0;
1205 statistics->nlpiterationsfsb[i] = 0;
1206 statistics->nsinglecutoffs[i] = 0;
1207 statistics->stopafterfsb[i] = 0;
1208 statistics->cutoffafterfsb[i] = 0;
1209 statistics->domredafterfsb[i] = 0;
1210 }
1211
1212 for( i = 0; i < statistics->maxnbestcands; i++ )
1213 {
1214 statistics->chosenfsbcand[i] = 0;
1215 }
1216}
1217
1218/** Prints the content of the statistics to stdout. */
1219static
1220void statisticsPrint(
1221 SCIP* scip, /**< SCIP data structure */
1222 STATISTICS* statistics /**< the statistics to print */
1223 )
1224{
1225 assert(scip != NULL);
1226 assert(statistics != NULL);
1227 assert(statistics->recursiondepth > 0);
1228
1229 /* only print something, if we have any statistics */
1230 if( statistics->ntotalresults > 0 )
1231 {
1232 int i;
1233
1234 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Lookahead Branching was called <%i> times.\n", statistics->ntotalresults);
1235
1236 for( i = 1; i <= MAXRESULT; i++ )
1237 {
1238 SCIP_RESULT currentresult = (SCIP_RESULT)i;
1239 /* see type_result.h for the id <-> enum mapping */
1240 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Result <%s> was chosen <%i> times\n", getStatusString(currentresult),
1241 statistics->nresults[i]);
1242 }
1243
1244 for( i = 0; i < statistics->maxnbestcands; i++ )
1245 {
1246 if( statistics->chosenfsbcand[i] > 0 )
1247 {
1248 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "The %i. variable (w.r.t. the FSB score) was chosen as the final result %i times.\n",
1249 i+1, statistics->chosenfsbcand[i]);
1250 }
1251 }
1252
1253 for( i = 0; i < statistics->recursiondepth; i++ )
1254 {
1255 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, branching was stopped after the scoring FSB %i times, %i times because of a cutoff and %i times because of a domain reduction\n",
1256 i, statistics->stopafterfsb[i], statistics->cutoffafterfsb[i], statistics->domredafterfsb[i]);
1257 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%i> fullcutoffs and <%i> single cutoffs were found.\n",
1258 i, statistics->nfullcutoffs[i], statistics->nsinglecutoffs[i]);
1259 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%i> LPs were solved, <%i> of them to calculate the FSB score, <%i> were saved for duplicate grandchildren.\n",
1260 i, statistics->nlpssolved[i], statistics->nlpssolvedfsb[i], statistics->nduplicatelps[i]);
1261 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%" SCIP_LONGINT_FORMAT "> iterations were needed to solve the LPs, <%"
1262 SCIP_LONGINT_FORMAT "> of them to calculate the FSB score.\n", i, statistics->nlpiterations[i],
1263 statistics->nlpiterationsfsb[i]);
1264 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, a decision was discarded <%i> times due to domain reduction because of"
1265 " propagation.\n", i, statistics->npropdomred[i]);
1266 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, old LAB branching results were used in <%i> cases, old FSB scores in <%d> cases.\n",
1267 i, statistics->noldbranchused[i], statistics->noldbranchusedfsb[i]);
1268 }
1269
1270 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "One single branching candidate was given <%i> times, after filtering, a single candidate remained <%i> times.\n",
1271 statistics->nsinglecandidate, statistics->nsingleafterfilter);
1272 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "The old branching candidate was used <%i> times.\n",
1273 statistics->noldcandidate);
1274 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "An LP error led to branching before all candidates were evaluated <%i> times.\n",
1275 statistics->nlperrorcalls);
1276 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "A reached (time) limit led to branching before all candidates were evaluated <%i> times.\n",
1277 statistics->nlimitcalls);
1278 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Depth limit was reached <%i> times.\n", statistics->ndepthreached);
1279 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Ignored <%i> binary constraints, that would be domain reductions.\n",
1280 statistics->ndomredcons);
1281 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added <%i> binary constraints, of which <%i> where violated by the base LP.\n",
1282 statistics->nbinconst, statistics->nbinconstvio);
1283 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Reduced the domain of <%i> vars, <%i> of them where violated by the base LP.\n",
1284 statistics->ndomred, statistics->ndomredvio);
1285 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added <%i> cliques found as binary constraint in the root node\n",
1286 statistics->ncliquesadded);
1287 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Needed <%i> additional nodes to prove the cutoffs of base nodes\n",
1288 statistics->ncutoffproofnodes);
1289 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Needed <%i> additional nodes to prove the domain reductions\n",
1290 statistics->ndomredproofnodes);
1291 }
1292}
1293
1294/** Helper struct to store the statistical data needed in a single run. */
1295typedef struct
1296{
1297 int ncutoffproofnodes; /**< The number of nodes needed to prove the current cutoff. */
1298} LOCALSTATISTICS;
1299
1300/** Allocates the local statistics in buffer memory and initializes it with default values. */
1301static
1302SCIP_RETCODE localStatisticsAllocate(
1303 SCIP* scip, /**< SCIP data structure */
1304 LOCALSTATISTICS** localstats /**< pointer to the local statistics to allocate and initialize */
1305 )
1306{
1307 assert(scip != NULL);
1308 assert(localstats != NULL);
1309
1310 SCIP_CALL( SCIPallocBuffer(scip, localstats) );
1311
1312 (*localstats)->ncutoffproofnodes = 0;
1313
1314 return SCIP_OKAY;
1315}
1316
1317/** Frees the allocated buffer memory of the local statistics. */
1318static
1319void localStatisticsFree(
1320 SCIP* scip, /**< SCIP data structure */
1321 LOCALSTATISTICS** localstats /**< pointer to the local statistics to be freed */
1322 )
1323{
1324 assert(scip != NULL);
1325 assert(localstats != NULL);
1326
1327 SCIPfreeBuffer(scip, localstats);
1328}
1329#endif
1330
1331/** branching rule data */
1332struct SCIP_BranchruleData
1333{
1334 CONFIGURATION* config; /**< the parameter that influence the behaviour of the lookahead branching */
1335 PERSISTENTDATA* persistent; /**< the data that persists over multiple branching decisions */
1336 SCIP_Bool isinitialized; /**< indicates whether the fields in this struct are initialized */
1337#ifdef SCIP_STATISTIC
1338 STATISTICS* statistics; /**< statistical data container */
1339#endif
1340};
1341
1342/** all constraints that were created and may be added to the base node */
1343typedef struct
1344{
1345 SCIP_VAR*** consvars; /**< array containing the variables for each constraint to be created */
1346 int* nconsvars; /**< number of vars in each element of 'consvars' */
1347 SCIP_Bool* violated; /**< indicating whether a constraint is violated by the base solution */
1348 int nelements; /**< number of elements in 'consvars' and 'nconsvars' */
1349 int memorysize; /**< number of entries that the array 'consvars' may hold before the
1350 * array is reallocated. */
1351 int nviolatedcons; /**< number of constraints that are violated by the base LP solution. */
1353
1354/** Allocate and initialize the list holding the constraints. */
1355static
1357 SCIP* scip, /**< SCIP data structure */
1358 CONSTRAINTLIST** conslist, /**< Pointer to the list to be allocated and initialized. */
1359 int startsize /**< The number of entries the list initially can hold. */
1360 )
1361{
1362 assert(scip != NULL);
1363 assert(conslist != NULL);
1364 assert(startsize > 0);
1365
1366 SCIP_CALL( SCIPallocBuffer(scip, conslist) );
1367 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*conslist)->consvars, startsize) );
1368 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*conslist)->nconsvars, startsize) );
1369 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*conslist)->violated, startsize) );
1370
1371 /* We start without any constraints */
1372 (*conslist)->nelements = 0;
1373 (*conslist)->memorysize = startsize;
1374 (*conslist)->nviolatedcons = 0;
1375
1376 return SCIP_OKAY;
1377}
1378
1379/** Append an element to the end of the list of constraints. */
1380static
1382 SCIP* scip, /**< SCIP data structure */
1383 CONSTRAINTLIST* list, /**< list to add the consvars to */
1384 SCIP_VAR** consvars, /**< array of variables for the constraint to be created later */
1385 int nconsvars, /**< number of elements in 'consvars' */
1386 SCIP_Bool violated /**< indicates whether the constraint is violated by the base lp */
1387 )
1388{
1389 assert(scip != NULL);
1390 assert(list != NULL);
1391 assert(consvars != NULL);
1392 assert(nconsvars > 0);
1393
1394 /* In case the list tries to hold more elements than it has space, reallocate */
1395 if( list->memorysize == list->nelements )
1396 {
1397 /* resize the array, such that it can hold the new element */
1398 int newmemsize = SCIPcalcMemGrowSize(scip, list->memorysize + 1);
1399 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &list->consvars, list->memorysize, newmemsize) );
1400 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &list->nconsvars, list->memorysize, newmemsize) );
1401 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &list->violated, list->memorysize, newmemsize) );
1402 list->memorysize = newmemsize;
1403 }
1404
1405 /* Set the new vars at the first unused place, which is the length used as index */
1406 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &list->consvars[list->nelements], consvars, nconsvars) ); /*lint !e866*/
1407 list->nconsvars[list->nelements] = nconsvars;
1408 list->violated[list->nelements] = violated;
1409 list->nelements++;
1410
1411 return SCIP_OKAY;
1412}
1413
1414/** Free all resources of a constraint list in opposite order to the allocation. */
1415static
1417 SCIP* scip, /**< SCIP data structure */
1418 CONSTRAINTLIST** conslist /**< Pointer to the list to be freed. */
1419 )
1420{
1421 int i;
1422
1423 assert(scip != NULL);
1424 assert(conslist != NULL);
1425
1426 for( i = 0; i < (*conslist)->nelements; i++ )
1427 {
1428 SCIPfreeBlockMemoryArray(scip, &(*conslist)->consvars[i], (*conslist)->nconsvars[i]);
1429 }
1430
1431 SCIPfreeBlockMemoryArray(scip, &(*conslist)->violated, (*conslist)->memorysize);
1432 SCIPfreeBlockMemoryArray(scip, &(*conslist)->nconsvars, (*conslist)->memorysize);
1433 SCIPfreeBlockMemoryArray(scip, &(*conslist)->consvars, (*conslist)->memorysize);
1434 SCIPfreeBuffer(scip, conslist);
1435}
1436
1437/**
1438 * list of binary variables currently branched on
1439 * a down branching (x <= 0) is saved as the negated variable (1-x)
1440 * an up branching (x >= 1) is saved as the original variable (x)
1441 * these variables are used to build the binary constraint in case that a ('binary') branch is cut off
1442 */
1443typedef struct
1444{
1445 SCIP_VAR** binaryvars; /**< The binary variables currently branched on. */
1446 int nbinaryvars; /**< The number of entries in 'nbinaryvars'. */
1447 int memorysize; /**< The number of entries that the array 'binaryvars' may hold before the
1448 * array is reallocated. */
1450
1451/** Allocates and initializes the BINARYVARLIST struct. */
1452static
1454 SCIP* scip, /**< SCIP data structure */
1455 BINARYVARLIST** list, /**< Pointer to the list to be allocated and initialized. */
1456 int startsize /**< The number of entries the list initially can hold. */
1457 )
1458{
1459 assert(scip != NULL);
1460 assert(list != NULL);
1461 assert(startsize > 0);
1462
1463 SCIP_CALL( SCIPallocBuffer(scip, list) );
1464 SCIP_CALL( SCIPallocBufferArray(scip, &(*list)->binaryvars, startsize) );
1465
1466 /* We start with no entries and the (current) max length */
1467 (*list)->nbinaryvars = 0;
1468 (*list)->memorysize = startsize;
1469
1470 return SCIP_OKAY;
1471}
1472
1473/** Appends a binary variable to the list, reallocating the list if necessary. */
1474static
1476 SCIP* scip, /**< SCIP data structure */
1477 BINARYVARLIST* list, /**< The list to add the var to. */
1478 SCIP_VAR* vartoadd /**< The binary var to add to the list. */
1479 )
1480{
1481 assert(scip != NULL);
1482 assert(list != NULL);
1483 assert(vartoadd != NULL);
1484 assert(SCIPvarIsBinary(vartoadd));
1485 assert(list->nbinaryvars < list->memorysize);
1486
1487 /* Set the new var at the first unused place, which is the length used as index */
1488 list->binaryvars[list->nbinaryvars] = vartoadd;
1489 list->nbinaryvars++;
1490}
1491
1492/** Remove the last element from the list. */
1493static
1495 BINARYVARLIST* list /**< The list to remove the last element from. */
1496 )
1497{
1498 assert(list != NULL);
1499 assert(list->nbinaryvars > 0);
1500 assert(list->binaryvars[list->nbinaryvars-1] != NULL);
1501
1502 /* decrement the number of entries in the actual list */
1503 list->nbinaryvars--;
1504}
1505
1506/** Frees all resources allocated by a BINARYVARLIST in opposite order of allocation. */
1507static
1509 SCIP* scip, /**< SCIP data structure */
1510 BINARYVARLIST** list /**< Pointer to the list to free */
1511 )
1512{
1513 assert(scip != NULL);
1514 assert(list != NULL);
1515
1516 SCIPfreeBufferArray(scip, &(*list)->binaryvars);
1517 SCIPfreeBuffer(scip, list);
1518}
1519
1520/** struct holding the relevant data for handling binary constraints */
1521typedef struct
1522{
1523 BINARYVARLIST* binaryvars; /**< current binary vars, used to fill the conslist */
1524 CONSTRAINTLIST* conslist; /**< list of constraints to be created */
1525} BINCONSDATA;
1526
1527/** Allocate and initialize the BINCONSDATA struct. */
1528static
1530 SCIP* scip, /**< SCIP data structure */
1531 BINCONSDATA** consdata, /**< Pointer to the struct to be allocated and initialized. */
1532 int maxdepth, /**< The depth of the recursion as an upper bound of branch vars to hold. */
1533 int nstartcons /**< The start size of the array containing the constraints. */
1534 )
1535{
1536 assert(scip != NULL);
1537 assert(consdata != NULL);
1538 assert(maxdepth > 0);
1539 assert(nstartcons > 0);
1540
1541 SCIP_CALL( SCIPallocBuffer(scip, consdata) );
1542 SCIP_CALL( binaryVarListCreate(scip, &(*consdata)->binaryvars, maxdepth) );
1543 SCIP_CALL( constraintListCreate(scip, &(*consdata)->conslist, nstartcons) );
1544
1545 return SCIP_OKAY;
1546}
1547
1548/** Free all resources in a BINCONSDATA in opposite order of allocation. */
1549static
1551 SCIP* scip, /**< SCIP data structure */
1552 BINCONSDATA** consdata /**< Pointer to the struct to be freed. */
1553 )
1554{
1555 assert(scip != NULL);
1556 assert(consdata != NULL);
1557
1558 constraintListFree(scip, &(*consdata)->conslist);
1559 binaryVarListFree(scip, &(*consdata)->binaryvars);
1560 SCIPfreeBuffer(scip, consdata);
1561}
1562
1563/** A struct acting as a fixed list of candidates */
1564typedef struct
1565{
1566 CANDIDATE** candidates; /**< the array of candidates */
1567 int ncandidates; /**< the number of actual entries in candidates (without trailing NULLs); this
1568 * is NOT the length of the candidates array, but the number of candidates in
1569 * it */
1571
1572/** allocates the candidate list on the buffer WITHOUT initializing the contained array of candidates. */
1573static
1575 SCIP* scip, /**< SCIP data structure */
1576 CANDIDATELIST** candidatelist, /**< the candidate list to allocate */
1577 int ncandidates /**< the number of candidates the list must hold */
1578 )
1579{
1580 assert(scip != NULL);
1581 assert(candidatelist != NULL);
1582 assert(ncandidates >= 0);
1583
1584 SCIP_CALL( SCIPallocBuffer(scip, candidatelist) );
1585
1586 if( ncandidates > 0 )
1587 {
1588 SCIP_CALL( SCIPallocBufferArray(scip, &(*candidatelist)->candidates, ncandidates) );
1589 }
1590 else
1591 (*candidatelist)->candidates = NULL;
1592
1593 (*candidatelist)->ncandidates = ncandidates;
1594
1595 return SCIP_OKAY;
1596}
1597
1598/** allocates the given list and fills it with all fractional candidates of the current LP solution. */
1599static
1601 SCIP* scip, /**< SCIP data structure */
1602 CANDIDATELIST** candidatelist /**< the list to allocate and fill */
1603 )
1604{
1605 SCIP_VAR** lpcands;
1606 SCIP_Real* lpcandssol;
1607 SCIP_Real* lpcandsfrac;
1608 int nlpcands;
1609 int i;
1610
1611 assert(scip != NULL);
1612 assert(candidatelist != NULL);
1613
1614 /* get all fractional candidates */
1615 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
1616
1617 assert(lpcands != NULL);
1618 assert(lpcandssol != NULL);
1619 assert(lpcandsfrac != NULL);
1620
1621 SCIP_CALL( candidateListCreate(scip, candidatelist, nlpcands) );
1622
1623 for( i = 0; i < nlpcands; i++ )
1624 {
1625 CANDIDATE* candidate;
1626
1627 SCIP_CALL( candidateCreate(scip, &candidate) );
1628 assert(candidate != NULL);
1629
1630 candidate->branchvar = lpcands[i];
1631 candidate->branchval = lpcandssol[i];
1632 candidate->fracval = lpcandsfrac[i];
1633
1634 (*candidatelist)->candidates[i] = candidate;
1635
1636 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "created candidate <%s>...\n",
1637 SCIPvarGetName(candidate->branchvar));
1638 }
1639
1640 return SCIP_OKAY;
1641}
1642
1643/** frees the allocated buffer memory of the candidate list and frees the contained candidates. */
1644static
1646 SCIP* scip, /**< SCIP data structure */
1647 CANDIDATELIST** candidatelist /**< the list to be freed */
1648 )
1649{
1650 int i;
1651
1652 assert(scip != NULL);
1653 assert(candidatelist != NULL);
1654 assert((*candidatelist)->ncandidates > 0 || (*candidatelist)->candidates == NULL);
1655
1656 if( (*candidatelist)->candidates != NULL )
1657 {
1658 for( i = (*candidatelist)->ncandidates - 1; i >= 0; i-- )
1659 {
1660 CANDIDATE* cand = (*candidatelist)->candidates[i];
1661 if( cand != NULL )
1662 {
1663 SCIP_CALL( candidateFree(scip, &cand) );
1664 }
1665 }
1666
1667 SCIPfreeBufferArray(scip, &(*candidatelist)->candidates);
1668 }
1669 SCIPfreeBuffer(scip, candidatelist);
1670
1671 return SCIP_OKAY;
1672}
1673
1674/** keeps only the first candidates and frees the remaining ones */
1675static
1677 SCIP* scip, /**< SCIP data structure */
1678 CANDIDATELIST* candidatelist, /**< the list to allocate and fill */
1679 int nindices /**< the number of candidates to keep (starting from 0) */
1680 )
1681{
1682 int i;
1683
1684 assert(scip != NULL);
1685 assert(candidatelist != NULL);
1686 assert(0 < nindices);
1687 assert(nindices <= candidatelist->ncandidates);
1688
1689 /* only keep the first nindices candidates and free the remaining ones */
1690 for( i = nindices; i < candidatelist->ncandidates; i++ )
1691 {
1692 CANDIDATE* cand = candidatelist->candidates[i];
1693 if( cand != NULL )
1694 {
1695 SCIP_CALL( candidateFree(scip, &cand) );
1696 candidatelist->candidates[i] = NULL;
1697 }
1698 }
1699 candidatelist->ncandidates = nindices;
1700
1701 return SCIP_OKAY;
1702}
1703
1704/** all domain reductions found through cutoff of branches */
1705typedef struct
1706{
1707 SCIP_Real* lowerbounds; /**< The new lower bounds found for each variable in the problem. */
1708 SCIP_Real* upperbounds; /**< The new upper bounds found for each variable in the problem. */
1709 SCIP_Shortbool* baselpviolated; /**< Indicates whether the base lp solution violates the new bounds of a var.*/
1710 int nviolatedvars; /**< Tracks the number of vars that have a violated (by the base lp) new lower
1711 * or upper bound. */
1712 int nchangedvars; /**< Tracks the number of vars, that have a changed domain. (a change on both,
1713 * upper and lower bound, counts as one.) */
1714 int nsimplebounds; /**< number of changed bounds resulting from infeasible child nodes */
1715#ifdef SCIP_STATISTIC
1716 int* lowerboundnproofs; /**< The number of nodes needed to prove the lower bound for each variable. */
1717 int* upperboundnproofs; /**< The number of nodes needed to prove the upper bound for each variable. */
1718#endif
1720
1721/** allocate the struct on the buffer and initialize it with the default values */
1722static
1724 SCIP* scip, /**< SCIP data structure */
1725 DOMAINREDUCTIONS** domreds /**< The struct that has to be allocated and initialized. */
1726 )
1727{
1728 SCIP_VAR** vars;
1729 int ntotalvars;
1730 int v;
1731
1732 assert(scip != NULL);
1733 assert(domreds != NULL);
1734
1735 /* The arrays saves the data for all variables in the problem via the ProbIndex. See SCIPvarGetProbindex() */
1736 vars = SCIPgetVars(scip);
1737 ntotalvars = SCIPgetNVars(scip);
1738
1739 /* Allocate the struct and the contained arrays; initialize flags to FALSE */
1740 SCIP_CALL( SCIPallocBuffer(scip, domreds) );
1741 SCIP_CALL( SCIPallocBufferArray(scip, &(*domreds)->lowerbounds, ntotalvars) );
1742 SCIP_CALL( SCIPallocBufferArray(scip, &(*domreds)->upperbounds, ntotalvars) );
1743 SCIP_CALL( SCIPallocClearBufferArray(scip, &(*domreds)->baselpviolated, ntotalvars) );
1744#ifdef SCIP_STATISTIC
1745 SCIP_CALL( SCIPallocClearBufferArray(scip, &(*domreds)->lowerboundnproofs, ntotalvars) );
1746 SCIP_CALL( SCIPallocClearBufferArray(scip, &(*domreds)->upperboundnproofs, ntotalvars) );
1747#endif
1748
1749 for( v = 0; v < ntotalvars; ++v )
1750 {
1751 (*domreds)->lowerbounds[v] = SCIPvarGetLbLocal(vars[v]);
1752 (*domreds)->upperbounds[v] = SCIPvarGetUbLocal(vars[v]);
1753 }
1754
1755 /* At the start we have no domain reductions for any variable. */
1756 (*domreds)->nviolatedvars = 0;
1757 (*domreds)->nchangedvars = 0;
1758 (*domreds)->nsimplebounds = 0;
1759
1760 return SCIP_OKAY;
1761}
1762
1763/** frees the given DOMAINREDUCTIONS and all contained Arrays in the opposite order of allocation */
1764static
1766 SCIP* scip, /**< SCIP data structure */
1767 DOMAINREDUCTIONS** domreds /**< Pointer to the struct to be freed. */
1768 )
1769{
1770 assert(scip != NULL);
1771 assert(domreds != NULL);
1772
1773#ifdef SCIP_STATISTIC
1774 SCIPfreeBufferArray(scip, &(*domreds)->upperboundnproofs);
1775 SCIPfreeBufferArray(scip, &(*domreds)->lowerboundnproofs);
1776#endif
1777 SCIPfreeBufferArray(scip, &(*domreds)->baselpviolated);
1778 SCIPfreeBufferArray(scip, &(*domreds)->upperbounds);
1779 SCIPfreeBufferArray(scip, &(*domreds)->lowerbounds);
1780 SCIPfreeBuffer(scip, domreds);
1781}
1782
1783/** information about the current status of the branching */
1784typedef struct
1785{
1786 SCIP_Bool addedbinconss; /**< were binary constraints added? */
1787 SCIP_Bool depthtoosmall; /**< was the remaining depth too small to branch on? */
1788 SCIP_Bool lperror; /**< did an error occur while solving an LP */
1789 SCIP_Bool cutoff; /**< was the current node cut off? */
1790 SCIP_Bool domredcutoff; /**< was the current node cut off due to domain reductions? */
1791 SCIP_Bool domred; /**< were domain reductions added due to information obtained through
1792 * branching? */
1793 SCIP_Bool limitreached; /**< was a limit (time, node, user, ...) reached? */
1794 SCIP_Bool maxnconsreached; /**< was the max number of constraints (bin conss and dom red) reached? */
1795} STATUS;
1796
1797/** Allocates the status on the buffer memory and initializes it with default values. */
1798static
1800 SCIP* scip, /**< SCIP data structure */
1801 STATUS** status /**< the status to be allocated */
1802 )
1803{
1804 assert(scip != NULL);
1805 assert(status != NULL);
1806
1807 SCIP_CALL( SCIPallocBuffer(scip, status) );
1808
1809 (*status)->addedbinconss = FALSE;
1810 (*status)->depthtoosmall = FALSE;
1811 (*status)->lperror = FALSE;
1812 (*status)->cutoff = FALSE;
1813 (*status)->domred = FALSE;
1814 (*status)->domredcutoff = FALSE;
1815 (*status)->limitreached = FALSE;
1816 (*status)->maxnconsreached = FALSE;
1817
1818 return SCIP_OKAY;
1819}
1820
1821/** frees the allocated buffer memory of the status */
1822static
1824 SCIP* scip, /**< SCIP data structure */
1825 STATUS** status /**< the status to be freed */
1826 )
1827{
1828 assert(scip != NULL);
1829 assert(status != NULL);
1830 SCIPfreeBuffer(scip, status);
1831}
1832
1833/** container struct to keep the calculated score for each variable */
1834typedef struct
1835{
1836 SCIP_Real* scores; /**< the scores for each problem variable */
1837 SCIP_Real* downgains; /**< the downgains for each problem variable */
1838 SCIP_Real* upgains; /**< the upgains for each problem variable */
1839 CANDIDATE** bestsortedcands; /**< array containing the best sorted variable indices w.r.t. their score */
1840 int nbestsortedcands; /**< number of elements in bestsortedcands */
1841 SCIP_Real scoresum; /**< sum of set scores */
1842 int nsetscores; /**< number of set scores */
1844
1845/** resets the array containing the sorted indices w.r.t. their score. */
1846static
1848 SCORECONTAINER* scorecontainer /**< the score container to reset */
1849 )
1850{
1851 assert(scorecontainer != NULL);
1852
1853 BMSclearMemoryArray(scorecontainer->bestsortedcands, scorecontainer->nbestsortedcands);
1854}
1855
1856/** allocates the score container and inits it with default values */
1857static
1859 SCIP* scip, /**< SCIP data structure */
1860 SCORECONTAINER** scorecontainer, /**< pointer to the score container to init */
1861 CONFIGURATION* config /**< config struct with the user configuration */
1862 )
1863{
1864 int ntotalvars;
1865 int maxncands;
1866 int i;
1867
1868 assert(scip != NULL);
1869 assert(scorecontainer != NULL);
1870 assert(config != NULL);
1871
1872 /* the container saves the score for all variables in the problem via the ProbIndex, see SCIPvarGetProbindex() */
1873 ntotalvars = SCIPgetNVars(scip);
1874 maxncands = ntotalvars - SCIPgetNContVars(scip) - SCIPgetNContImplVars(scip);
1875 if( maxncands > config->maxncands )
1876 maxncands = config->maxncands;
1877
1878 SCIP_CALL( SCIPallocBuffer(scip, scorecontainer) );
1879 SCIP_CALL( SCIPallocBufferArray(scip, &(*scorecontainer)->scores, ntotalvars) );
1880 SCIP_CALL( SCIPallocBufferArray(scip, &(*scorecontainer)->downgains, ntotalvars) );
1881 SCIP_CALL( SCIPallocBufferArray(scip, &(*scorecontainer)->upgains, ntotalvars) );
1882 SCIP_CALL( SCIPallocBufferArray(scip, &(*scorecontainer)->bestsortedcands, maxncands) );
1883
1884 (*scorecontainer)->nbestsortedcands = maxncands;
1885 (*scorecontainer)->scoresum = 0.0;
1886 (*scorecontainer)->nsetscores = 0;
1887
1888 scoreContainterResetBestSortedCands(*scorecontainer);
1889
1890 /* init the scores to something negative, as scores are always non negative */
1891 for( i = 0; i < ntotalvars; i++ )
1892 {
1893 (*scorecontainer)->scores[i] = -1.0;
1894 (*scorecontainer)->downgains[i] = -1.0;
1895 (*scorecontainer)->upgains[i] = -1.0;
1896 }
1897
1898 return SCIP_OKAY;
1899}
1900
1901/** Finds the insertion index for the given score in the candidate list. The score of each candidate is taken from the
1902 * scorecontainer. The first elements of the candidate list have to be sorted, as this method uses binary search to find
1903 * the correct insertion point
1904 */
1905static
1907 SCIP* scip, /**< SCIP data structure */
1908 SCORECONTAINER* scorecontainer, /**< container with all the scores for each candidate */
1909 SCIP_Real scoretoinsert, /**< score to find the insertion index for */
1910 CANDIDATE** candidates, /**< candidate list where the first nsorted elements are sorted (w.r.t. their
1911 * score) */
1912 int ncandidates /**< number of elements in candidates to consider, starting from 0 */
1913 )
1914{
1915 int left = 0;
1916 int right = ncandidates - 1;
1917
1918 assert(scip != NULL);
1919 assert(scorecontainer != NULL);
1920 assert(candidates != NULL);
1921 assert(ncandidates >= 0);
1922
1923 while( left <= right )
1924 {
1925 int mid = left + ((right - left) / 2);
1926 SCIP_Real midscore = -SCIPinfinity(scip);
1927 CANDIDATE *midcand = candidates[mid];
1928
1929 if( midcand != NULL)
1930 {
1931 SCIP_VAR* midvar;
1932 int midindex;
1933
1934 midvar = midcand->branchvar;
1935 midindex = SCIPvarGetProbindex(midvar);
1936 midscore = scorecontainer->scores[midindex];
1937 }
1938
1939 if( SCIPisGT(scip, scoretoinsert, midscore) )
1940 right = mid - 1;
1941 else
1942 left = mid + 1;
1943 }
1944
1945 return right + 1;
1946}
1947
1948/** Inserts the given probindex into the sorted array in the container, moving all indices after it to the right. Then
1949 * returns the element that does not fit into the array any longer. */
1950static
1952 SCORECONTAINER* scorecontainer, /**< container to insert the index into */
1953 CANDIDATE* candidate, /**< the probindex of a variable to store */
1954 int insertpoint /**< point to store the index at */
1955 )
1956{
1957 int i;
1958 CANDIDATE* movecand = candidate;
1959
1960 assert(scorecontainer != NULL);
1961 assert(candidate != NULL);
1962 assert(insertpoint >= 0);
1963
1964 for( i = insertpoint; i < scorecontainer->nbestsortedcands; i++ )
1965 {
1966 CANDIDATE* oldcand = scorecontainer->bestsortedcands[i];
1967 scorecontainer->bestsortedcands[i] = movecand;
1968 movecand = oldcand;
1969 }
1970
1971 return movecand;
1972}
1973
1974/** sets the score for the variable in the score container */
1975static
1977 SCIP* scip, /**< SCIP data structure */
1978 SCORECONTAINER* scorecontainer, /**< the container to write into */
1979 CANDIDATE* cand, /**< candidate to add the score for */
1980 SCIP_Real score, /**< score to add */
1981 SCIP_Real downgain, /**< LP gain in down child */
1982 SCIP_Real upgain /**< LP gain in up child */
1983 )
1984{
1985 CANDIDATE* droppedcandidate;
1986 int probindex;
1987 int insertpoint;
1988
1989 assert(scip != NULL);
1990 assert(scorecontainer != NULL);
1991 assert(cand != NULL);
1992 assert(SCIPisGE(scip, score, -0.2));
1993
1994 probindex = SCIPvarGetProbindex(cand->branchvar);
1995 assert(probindex >= 0);
1996
1997 if( scorecontainer->scores[probindex] < -0.5 )
1998 {
1999 ++scorecontainer->nsetscores;
2000 scorecontainer->scoresum += score;
2001 }
2002 else
2003 {
2004 scorecontainer->scoresum += (score - scorecontainer->scores[probindex]);
2005 }
2006
2007 scorecontainer->scores[probindex] = score;
2008 scorecontainer->downgains[probindex] = downgain;
2009 scorecontainer->upgains[probindex] = upgain;
2010
2011 /* find the point in the sorted array where the new score should be inserted */
2012 insertpoint = findInsertionPoint(scip, scorecontainer, score, scorecontainer->bestsortedcands,
2013 scorecontainer->nbestsortedcands);
2014
2015 /* insert the current variable (cand) at the position calculated above, returning the candidate that
2016 * was removed at the end of the list; this candidate can be the given candidate for the case that the score does not
2017 * belong to the best ones */
2018 droppedcandidate = scoreContainerUpdateSortOrder(scorecontainer, cand, insertpoint);
2019
2020 /* remove the warm start info from the dropped candidate */
2021 if( droppedcandidate != NULL )
2022 {
2023 SCIP_CALL( candidateFreeWarmStartInfo(scip, droppedcandidate) );
2024 }
2025
2026 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Stored score <%.9g> for var <%s>.\n", score, SCIPvarGetName(cand->branchvar));
2027
2028 return SCIP_OKAY;
2029}
2030
2031/** Frees the score container and all of its contained arrays. */
2032static
2034 SCIP* scip, /**< SCIP data structure */
2035 SCORECONTAINER** scorecontainer /**< score container to free */
2036 )
2037{
2038 assert(scip != NULL);
2039 assert(scorecontainer != NULL);
2040
2041 /* don't free the candidates inside the cands array, as those are handled by the candidate list */
2042 SCIPfreeBufferArray(scip, &(*scorecontainer)->bestsortedcands);
2043 SCIPfreeBufferArray(scip, &(*scorecontainer)->upgains);
2044 SCIPfreeBufferArray(scip, &(*scorecontainer)->downgains);
2045 SCIPfreeBufferArray(scip, &(*scorecontainer)->scores);
2046 SCIPfreeBuffer(scip, scorecontainer);
2047
2048 return SCIP_OKAY;
2049}
2050
2051/*
2052 * Local methods for the logic
2053 */
2054
2055/** branches recursively on all given candidates */
2056static
2058 SCIP* scip, /**< SCIP data structure */
2059 STATUS* status, /**< current status */
2060 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
2061 CONFIGURATION* config, /**< the configuration of the branching rule */
2062 SCIP_SOL* baselpsol, /**< base lp solution */
2063 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found */
2064 BINCONSDATA* binconsdata, /**< container collecting all binary constraints */
2065 CANDIDATELIST* candidatelist, /**< list of candidates to branch on */
2066 BRANCHINGDECISION* decision, /**< struct to store the final decision */
2067 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores */
2068 LEVEL2DATA* level2data, /**< level 2 LP results data */
2069 int recursiondepth, /**< remaining recursion depth */
2070 SCIP_Real lpobjval, /**< LP objective value of current probing node*/
2071 SCIP_Real baselpobjval, /**< LP objective value of focus node (not probing) */
2072 SCIP_Longint* niterations, /**< pointer to store the total number of iterations for this variable */
2073 int* ndeepestcutoffs, /**< pointer to store the total number of cutoffs on the deepest level */
2074 SCIP_Real* bestgain, /**< pointer to store the best gain found with these candidates */
2075 SCIP_Real* totalgains, /**< pointer to store the sum over all gains that are valid in both children */
2076 int* ntotalgains, /**< pointer to store the number of gains summed in totalgains */
2077 int* ndeepestnodes /**< pointer to store the number of nodes processed in the deepest level */
2078#ifdef SCIP_STATISTIC
2079 ,STATISTICS* statistics /**< general statistical data */
2080 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
2081 ,SCIP_Real* firstscoreptr /**< pointer to store score of first candidate, or NULL */
2082 ,SCIP_Real* bestscoreptr /**< pointer to store best score, or NULL */
2083#endif
2084 );
2085
2086/** Adds the given lower bound to the DOMAINREDUCTIONS struct. */
2087static
2089 SCIP* scip, /**< SCIP data structure */
2090 SCIP_VAR* var, /**< The variable the bound should be added for. */
2091 SCIP_Real lowerbound, /**< The new lower bound for the variable. */
2092 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2093 * reduction is violated by it. */
2094 SCIP_Bool simplechange, /**< does the change result from an infeasible child node? */
2095 DOMAINREDUCTIONS* domainreductions /**< The struct the domain reduction should be added to. */
2096#ifdef SCIP_STATISTIC
2097 ,int nproofnodes /**< The number of nodes needed to prove the new lower bound. */
2098 ,int force /**< should the number of proof nodes be added even if the bound is known already? */
2099#endif
2100 )
2101{
2102 int varindex;
2103 SCIP_Real basesolutionval;
2104
2105 assert(scip != NULL);
2106 assert(var != NULL);
2107 assert(baselpsol != NULL);
2108 assert(domainreductions != NULL);
2109#ifdef SCIP_STATISTIC
2110 assert(nproofnodes >= 0);
2111#endif
2112
2113 /* The arrays inside DOMAINREDUCTIONS are indexed via the problem index. */
2114 varindex = SCIPvarGetProbindex(var);
2115
2116 lowerbound = SCIPadjustedVarLb(scip, var, lowerbound);
2117
2118 if( SCIPisLT(scip, domainreductions->lowerbounds[varindex], lowerbound) )
2119 {
2120 /* the new lower bound is stronger (greater) than the old one,
2121 * so we update the bound and number of proof nodes */
2122 domainreductions->lowerbounds[varindex] = lowerbound;
2123 domainreductions->nchangedvars++;
2124 if( simplechange )
2125 domainreductions->nsimplebounds++;
2126#ifdef SCIP_STATISTIC
2127 domainreductions->lowerboundnproofs[varindex] = nproofnodes;
2128 }
2129 else
2130 {
2131 /* if the given lower bound is equal to the old one we take the smaller number of proof nodes */
2132 if( SCIPisEQ(scip, domainreductions->lowerbounds[varindex], lowerbound) &&
2133 (force || domainreductions->lowerboundnproofs[varindex] > nproofnodes) )
2134 domainreductions->lowerboundnproofs[varindex] = nproofnodes;
2135#endif
2136 }
2137
2138 /* we get the solution value to check whether the domain reduction is violated in the base LP */
2139 basesolutionval = SCIPgetSolVal(scip, baselpsol, var);
2140
2141 /* in case the new lower bound is greater than the base solution val and the base solution val is not violated by a
2142 * previously found bound, we increment the nviolatedvars counter and set the baselpviolated flag */
2143 if( SCIPisFeasGT(scip, domainreductions->lowerbounds[varindex], basesolutionval)
2144 && !domainreductions->baselpviolated[varindex] )
2145 {
2146 domainreductions->baselpviolated[varindex] = TRUE;
2147 domainreductions->nviolatedvars++;
2148 }
2149}
2150
2151/** Adds the given upper bound to the DOMAINREDUCTIONS struct. */
2152static
2154 SCIP* scip, /**< SCIP data structure */
2155 SCIP_VAR* var, /**< The variable the bound should be added for. */
2156 SCIP_Real upperbound, /**< The new upper bound for the variable. */
2157 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2158 * reduction is violated by it. */
2159 SCIP_Bool simplechange, /**< does the change result from an infeasible child node? */
2160 DOMAINREDUCTIONS* domainreductions /**< The struct the domain reduction should be added to. */
2161#ifdef SCIP_STATISTIC
2162 ,int nproofnodes /**< The number of nodes needed to prove the new lower bound. */
2163 ,int force /**< should the number of proof nodes be added even if the bound is known already? */
2164#endif
2165 )
2166{
2167 int varindex;
2168 SCIP_Real basesolutionval;
2169
2170 assert(scip != NULL);
2171 assert(var != NULL);
2172 assert(baselpsol != NULL);
2173 assert(domainreductions != NULL);
2174#ifdef SCIP_STATISTIC
2175 assert(nproofnodes >= 0);
2176#endif
2177
2178 /* The arrays inside DOMAINREDUCTIONS are indexed via the problem index. */
2179 varindex = SCIPvarGetProbindex(var);
2180
2181 upperbound = SCIPadjustedVarUb(scip, var, upperbound);
2182
2183 if( SCIPisLE(scip, domainreductions->upperbounds[varindex], upperbound) )
2184 {
2185#ifdef SCIP_STATISTIC
2186 /* if the given upper bound is equal to the old one we take the smaller number of proof nodes */
2187 if( SCIPisEQ(scip, domainreductions->upperbounds[varindex], upperbound) &&
2188 (force || domainreductions->upperboundnproofs[varindex] > nproofnodes) )
2189 domainreductions->upperboundnproofs[varindex] = nproofnodes;
2190#endif
2191 }
2192 else
2193 {
2194 /* the new upper bound is stronger (smaller) than the old one,
2195 * so we update the bound and number of proof nodes */
2196 domainreductions->upperbounds[varindex] = upperbound;
2197 domainreductions->nchangedvars++;
2198 if( simplechange )
2199 domainreductions->nsimplebounds++;
2200#ifdef SCIP_STATISTIC
2201 domainreductions->upperboundnproofs[varindex] = nproofnodes;
2202#endif
2203 }
2204
2205 /* We get the solution value to check whether the domain reduction is violated in the base LP */
2206 basesolutionval = SCIPgetSolVal(scip, baselpsol, var);
2207
2208 /* In case the new upper bound is smaller than the base solution val and the base solution val is not violated by a
2209 * previously found bound, we increment the nviolatedvars counter and set the baselpviolated flag. */
2210 if( SCIPisFeasLT(scip, domainreductions->upperbounds[varindex], basesolutionval)
2211 && !domainreductions->baselpviolated[varindex] )
2212 {
2213 domainreductions->baselpviolated[varindex] = TRUE;
2214 domainreductions->nviolatedvars++;
2215 }
2216}
2217
2218/** apply the domain reductions from a single struct to another one; this may be used in case one of the two child
2219 * problems of a variable is infeasible
2220 */
2221static
2223 SCIP* scip, /**< SCIP data structure */
2224 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2225 * reduction is violated by it. */
2226 int maxstoredomreds, /**< maximum number of domain reductions to store */
2227 DOMAINREDUCTIONS* targetdomreds, /**< The target that should be filled with the merged data. */
2228 DOMAINREDUCTIONS* domreds /**< source domain reductions */
2229 )
2230{
2231 SCIP_VAR** vars;
2232 int nvars;
2233 int i;
2234
2235 assert(scip != NULL);
2236 assert(baselpsol != NULL);
2237 assert(targetdomreds != NULL);
2238 assert(domreds != NULL);
2239
2240 /* as the bounds are tracked for all vars we have to iterate over all vars */
2241 vars = SCIPgetVars(scip);
2242 nvars = SCIPgetNVars(scip);
2243
2244 assert(vars != NULL);
2245 assert(nvars > 0);
2246
2247 for( i = 0; i < nvars; i++ )
2248 {
2249 if( targetdomreds->nviolatedvars >= maxstoredomreds )
2250 return;
2251
2252#ifdef SCIP_STATISTIC
2253 /* adjust the proof nodes */
2254 addLowerBound(scip, vars[i], domreds->lowerbounds[i], baselpsol, TRUE, targetdomreds,
2255 domreds->lowerboundnproofs[i], FALSE);
2256#else
2257 addLowerBound(scip, vars[i], domreds->lowerbounds[i], baselpsol, TRUE, targetdomreds);
2258#endif
2259
2260 if( targetdomreds->nviolatedvars >= maxstoredomreds )
2261 return;
2262
2263#ifdef SCIP_STATISTIC
2264 addUpperBound(scip, vars[i], domreds->upperbounds[i], baselpsol, TRUE, targetdomreds,
2265 domreds->upperboundnproofs[i], FALSE);
2266#else
2267 addUpperBound(scip, vars[i], domreds->upperbounds[i], baselpsol, TRUE, targetdomreds);
2268#endif
2269 }
2270}
2271
2272/**
2273 * merges the domain reduction data from the two given branching children data into the target parent data
2274 */
2275static
2277 SCIP* scip, /**< SCIP data structure */
2278 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2279 * reduction is violated by it. */
2280 int maxstoredomreds, /**< maximum number of domain reductions to store */
2281 DOMAINREDUCTIONS* targetdomreds, /**< The target that should be filled with the merged data. */
2282 DOMAINREDUCTIONS* downdomreds, /**< One of the source DOMAINREDUCTIONS. */
2283 DOMAINREDUCTIONS* updomreds /**< The other source DOMAINREDUCTIONS. */
2284 )
2285{
2286 SCIP_VAR** vars;
2287 int nvars;
2288 int i;
2289
2290 assert(scip != NULL);
2291 assert(baselpsol != NULL);
2292 assert(targetdomreds != NULL);
2293 assert(downdomreds != NULL);
2294 assert(updomreds != NULL);
2295
2296 /* as the bounds are tracked for all vars we have to iterate over all vars */
2297 vars = SCIPgetVars(scip);
2298 nvars = SCIPgetNVars(scip);
2299
2300 assert(vars != NULL);
2301 assert(nvars > 0);
2302
2303 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Combining domain reductions from up and down child.\n");
2304 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Previous number of changed variable domains: %d\n",
2305 targetdomreds->nchangedvars);
2306
2307 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Number of changed variable domains in up child: %d\n",
2308 updomreds->nchangedvars);
2309 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Number of changed variable domains in down child: %d\n",
2310 downdomreds->nchangedvars);
2311
2312 for( i = 0; i < nvars; i++ )
2313 {
2314 SCIP_Real newlowerbound;
2315 SCIP_Real newupperbound;
2316
2317 assert(vars[i] != NULL);
2318
2319 if( targetdomreds->nviolatedvars >= maxstoredomreds )
2320 return;
2321
2322 /* the MIN of both lower bounds represents a valid lower bound at the parent node */
2323 newlowerbound = MIN(downdomreds->lowerbounds[i], updomreds->lowerbounds[i]);
2324
2325 /* This MIN can now be added via the default add method */
2326#ifdef SCIP_STATISTIC
2327 addLowerBound(scip, vars[i], newlowerbound, baselpsol, FALSE, targetdomreds,
2328 MIN(4, downdomreds->lowerboundnproofs[i] + updomreds->lowerboundnproofs[i] + 2), FALSE);
2329#else
2330 addLowerBound(scip, vars[i], newlowerbound, baselpsol, FALSE, targetdomreds);
2331#endif
2332
2333 if( targetdomreds->nviolatedvars >= maxstoredomreds )
2334 return;
2335
2336 /* the MAX of both upper bounds represents a valid upper bound at the parent node */
2337 newupperbound = MAX(downdomreds->upperbounds[i], updomreds->upperbounds[i]);
2338
2339 /* This MAX can now be added via the default add method */
2340#ifdef SCIP_STATISTIC
2341 addUpperBound(scip, vars[i], newupperbound, baselpsol, FALSE, targetdomreds,
2342 MIN(4, downdomreds->upperboundnproofs[i] + updomreds->upperboundnproofs[i] + 2), FALSE);
2343#else
2344 addUpperBound(scip, vars[i], newupperbound, baselpsol, FALSE, targetdomreds);
2345#endif
2346 }
2347
2348 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Subsequent number of changed variable domains: %d\n",
2349 targetdomreds->nchangedvars);
2350}
2351
2352/** Applies the domain reductions to the current node. */
2353static
2355 SCIP* scip, /**< SCIP data structure */
2356 CONFIGURATION* config, /**< the configuration of the branching rule */
2357 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2358 * reduction is violated by it. */
2359 DOMAINREDUCTIONS* domreds, /**< The domain reductions that should be applied to the current node. */
2360 SCIP_Bool* domredcutoff, /**< pointer to store whether a cutoff was found due to domain reductions */
2361 SCIP_Bool* domred /**< pointer to store whether a domain change was added */
2362#ifdef SCIP_STATISTIC
2363 ,STATISTICS* statistics /**< The statistics container. */
2364#endif
2365 )
2366{
2367 int i;
2368 SCIP_VAR** probvars;
2369 int nprobvars;
2370#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
2371 int nboundsadded = 0;
2372 int nboundsaddedvio = 0;
2373#endif
2374
2375 assert(scip != NULL);
2376 assert(baselpsol != NULL);
2377 assert(domreds != NULL);
2378 assert(domredcutoff != NULL);
2379 assert(domred != NULL);
2380#ifdef SCIP_STATISTIC
2381 assert(statistics != NULL);
2382#endif
2383
2384 /* initially we have no cutoff */
2385 *domredcutoff = FALSE;
2386
2387 /* as the bounds are tracked for all vars we have to iterate over all vars */
2388 probvars = SCIPgetVars(scip);
2389 nprobvars = SCIPgetNVars(scip);
2390
2391 assert(probvars != NULL);
2392 assert(nprobvars > 0);
2393
2394 if( config->prefersimplebounds && domreds->nsimplebounds == 0 )
2395 return SCIP_OKAY;
2396
2397 for( i = 0; i < nprobvars && !(*domredcutoff); i++ )
2398 {
2399 SCIP_VAR* var;
2400 SCIP_Real proposedbound;
2401 SCIP_Real baselpval;
2402#ifdef SCIP_DEBUG
2403 SCIP_Real oldbound;
2404#endif
2405 SCIP_Bool infeasible;
2406 SCIP_Bool tightened;
2407
2408 var = probvars[i];
2409
2410 assert(var != NULL);
2411
2412 baselpval = SCIPgetSolVal(scip, baselpsol, var);
2413
2414 if( SCIPisGT(scip, domreds->lowerbounds[i], SCIPvarGetLbLocal(var)) )
2415 {
2416 /* apply lower bound */
2417#ifdef SCIP_DEBUG
2418 oldbound = SCIPvarGetLbLocal(var);
2419#endif
2420 proposedbound = domreds->lowerbounds[i];
2421
2422 if( config->onlyvioldomreds && SCIPisGE(scip, baselpval, proposedbound) )
2423 continue;
2424
2425 /* add the new bound */
2426 SCIP_CALL( SCIPtightenVarLb(scip, var, proposedbound, TRUE, &infeasible, &tightened) );
2427
2428#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
2429 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Variable <%s>, old lower bound <%g>, proposed lower bound <%g>, new "
2430 "lower bound <%g>\n", SCIPvarGetName(var), oldbound, proposedbound, SCIPvarGetLbLocal(var));
2431#endif
2432
2433 if( infeasible )
2434 {
2435 /* the domain reduction may result in an empty model (ub < lb) */
2436 *domredcutoff = TRUE;
2437 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The domain reduction of variable <%s> resulted in an empty "
2438 "model.\n", SCIPvarGetName(var));
2439 }
2440 else if( tightened )
2441 {
2442 /* the lb is now strictly greater than before */
2443 *domred = TRUE;
2444#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
2445 nboundsadded++;
2446#endif
2447#ifdef SCIP_STATISTIC
2448 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The lower bound of variable <%s> was successfully tightened (%d).\n",
2449 SCIPvarGetName(var), domreds->lowerboundnproofs[i]);
2450 statistics->ndomredproofnodes += domreds->lowerboundnproofs[i];
2451#endif
2452
2453#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
2454 if( SCIPisLT(scip, baselpval, SCIPvarGetLbLocal(var)) )
2455 {
2456 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The lower bound of variable <%s> is violated by the base lp "
2457 "value <%g>.\n", SCIPvarGetName(var), baselpval);
2458
2459 nboundsaddedvio++;
2460 }
2461#endif
2462 }
2463 }
2464
2465 if( SCIPisLT(scip, domreds->upperbounds[i], SCIPvarGetUbLocal(var)) )
2466 {
2467 /* apply upper bound */
2468#ifdef SCIP_DEBUG
2469 oldbound = SCIPvarGetUbLocal(var);
2470#endif
2471 proposedbound = domreds->upperbounds[i];
2472
2473 if( config->onlyvioldomreds && SCIPisLE(scip, baselpval, proposedbound) )
2474 continue;
2475
2476 /* add the new bound */
2477 SCIP_CALL( SCIPtightenVarUb(scip, var, proposedbound, TRUE, &infeasible, &tightened) );
2478
2479#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
2480 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Variable <%s>, old upper bound <%g>, proposed upper bound <%g>, new "
2481 "upper bound <%g>\n", SCIPvarGetName(var), oldbound, proposedbound, SCIPvarGetUbLocal(var));
2482#endif
2483
2484 if( infeasible )
2485 {
2486 /* the domain reduction may result in an empty model (ub < lb) */
2487 *domredcutoff = TRUE;
2488 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The domain reduction of variable <%s> resulted in an empty "
2489 "model.\n", SCIPvarGetName(var));
2490 }
2491 else if( tightened )
2492 {
2493 /* the ub is now strictly smaller than before */
2494 *domred = TRUE;
2495#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
2496 nboundsadded++;
2497#endif
2498#ifdef SCIP_STATISTIC
2499 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The upper bound of variable <%s> was successfully tightened (%d).\n",
2500 SCIPvarGetName(var), domreds->upperboundnproofs[i]);
2501 statistics->ndomredproofnodes += domreds->upperboundnproofs[i];
2502#endif
2503
2504#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
2505 if( SCIPisGT(scip, baselpval, SCIPvarGetUbLocal(var)) )
2506 {
2507 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The upper bound of variable <%s> is violated by the base lp "
2508 "value <%g>.\n", SCIPvarGetName(var), baselpval);
2509
2510 nboundsaddedvio++;
2511 }
2512#endif
2513 }
2514 }
2515 }
2516
2517#ifdef SCIP_STATISTIC
2518 statistics->ndomred += nboundsadded;
2519 statistics->ndomredvio += nboundsaddedvio;
2520#endif
2521
2522 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Truly changed <%d> domains of the problem, <%d> of them are violated by the "
2523 "base lp.\n", nboundsadded, nboundsaddedvio);
2524 return SCIP_OKAY;
2525}
2526
2527/** Copies the current LP solution into the given pointer. Needs to be freed after usage! */
2528static
2530 SCIP* scip, /**< SCIP data structure */
2531 SCIP_SOL** lpsol /**< pointer to store the solution into */
2532 )
2533{
2534 assert(scip != NULL);
2535 assert(lpsol != NULL);
2536
2537 /* create temporary solution */
2538 SCIP_CALL( SCIPcreateLPSol(scip, lpsol, NULL) );
2539
2540 /* unlink the solution, so that newly solved lps don't have any influence on our copy */
2541 SCIP_CALL( SCIPunlinkSol(scip, *lpsol) );
2542
2543 return SCIP_OKAY;
2544}
2545
2546/** Executes the branching on a given variable with a given value. */
2547static
2549 SCIP* scip /**< SCIP data structure */,
2550 CONFIGURATION* config, /**< config struct with the user configuration */
2551 BRANCHINGDECISION* decision /**< the decision with all the needed data */
2552 )
2553{
2554 SCIP_VAR* bestvar;
2555 SCIP_Real bestval;
2556 SCIP_NODE* downchild = NULL;
2557 SCIP_NODE* upchild = NULL;
2558
2559 assert(scip != NULL);
2560 assert(decision != NULL);
2561 assert(config != NULL);
2562
2563 bestvar = decision->branchvar;
2564 bestval = decision->branchval;
2565 assert(bestvar != NULL);
2566
2567 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Effective branching on var <%s> with value <%g(%g)>. Old domain: [%g..%g].\n",
2568 SCIPvarGetName(bestvar), bestval, SCIPgetSolVal(scip, NULL, bestvar), SCIPvarGetLbLocal(bestvar), SCIPvarGetUbLocal(bestvar));
2569
2570 assert(!SCIPisIntegral(scip, bestval));
2571
2572 /* branch on the given variable */
2573 assert(SCIPisLT(scip, SCIPvarGetLbLocal(bestvar), bestval));
2574 assert(SCIPisLT(scip, bestval, SCIPvarGetUbLocal(bestvar)));
2575 SCIP_CALL( SCIPbranchVarVal(scip, bestvar, bestval, &downchild, NULL, &upchild) );
2576
2577 SCIPdebugMsg(scip, "down child (node %" SCIP_LONGINT_FORMAT "): branching bound change <%s> <= %g\n",
2578 SCIPnodeGetNumber(downchild), SCIPvarGetName(bestvar), SCIPfeasFloor(scip, bestval));
2579 SCIPdebugMsg(scip, "up child (node %" SCIP_LONGINT_FORMAT "): branching bound change <%s> >= %g\n",
2580 SCIPnodeGetNumber(upchild), SCIPvarGetName(bestvar), SCIPfeasCeil(scip, bestval));
2581
2582 assert(downchild != NULL);
2583 assert(upchild != NULL);
2584
2585 /* update the lower bounds in the children; we must not do this if columns are missing in the LP
2586 * (e.g., because we are doing branch-and-price) or the problem should be solved exactly */
2588 {
2589 /* update the lower bound for the LPs for further children of both created nodes */
2590 if( decision->downdbvalid )
2591 {
2592 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, decision->downdb) );
2593 }
2594 if( decision->updbvalid )
2595 {
2596 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, decision->updb) );
2597 }
2598
2599 if( decision->boundsvalid && config->applychildbounds )
2600 {
2601 SCIP_VAR** vars;
2602 int nvars;
2603 int i;
2604
2605 assert(decision->downlowerbounds != NULL);
2606 assert(decision->downupperbounds != NULL);
2607 assert(decision->uplowerbounds != NULL);
2608 assert(decision->upupperbounds != NULL);
2609
2610 nvars = SCIPgetNVars(scip);
2611 vars = SCIPgetVars(scip);
2612
2613 assert(nvars == decision->boundssize);
2614
2615 for( i = 0; i < nvars; i++ )
2616 {
2617 SCIP_VAR* var = vars[i];
2618 SCIP_Real currentlb;
2619 SCIP_Real currentub;
2620 SCIP_Real newlb = decision->downlowerbounds[i];
2621 SCIP_Real newub = decision->downupperbounds[i];
2622 assert(var != NULL);
2623
2624 currentlb = SCIPvarGetLbLocal(var);
2625 currentub = SCIPvarGetUbLocal(var);
2626
2627 /* update the lower bound of the lower child in case it is better than the current one */
2628 if( SCIPisGT(scip, newlb, currentlb) )
2629 {
2630 SCIP_CALL( SCIPchgVarLbNode(scip, downchild, var, newlb) );
2631
2632 SCIPdebugMsg(scip, "down child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> >= %g\n",
2633 SCIPnodeGetNumber(downchild), SCIPvarGetName(var), newlb);
2634 }
2635
2636 /* update the upper bound of the lower child in case it is better than the current one AND it is not the
2637 * branching variable, as its upper bound is already updated
2638 */
2639 if( SCIPisLT(scip, newub, currentub) && var != bestvar )
2640 {
2641 SCIP_CALL( SCIPchgVarUbNode(scip, downchild, var, newub) );
2642
2643 SCIPdebugMsg(scip, "down child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> <= %g\n",
2644 SCIPnodeGetNumber(downchild), SCIPvarGetName(var), newub);
2645 }
2646
2647 newlb = decision->uplowerbounds[i];
2648 newub = decision->upupperbounds[i];
2649
2650 /* update the lower bound of the upper child in case it is better than the current one AND it is not the
2651 * branching variable, as its lower bound is already updated
2652 */
2653 if( SCIPisGT(scip, newlb, currentlb) && var != bestvar)
2654 {
2655 SCIP_CALL( SCIPchgVarLbNode(scip, upchild, var, newlb) );
2656
2657 SCIPdebugMsg(scip, "up child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> >= %g\n",
2658 SCIPnodeGetNumber(upchild), SCIPvarGetName(var), newlb);
2659 }
2660
2661 /* update the upper bound of the upper child in case it is better than the current one */
2662 if( SCIPisLT(scip, newub, currentub) )
2663 {
2664 SCIP_CALL( SCIPchgVarUbNode(scip, upchild, var, newub) );
2665
2666 SCIPdebugMsg(scip, "up child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> <= %g\n",
2667 SCIPnodeGetNumber(upchild), SCIPvarGetName(var), newub);
2668 }
2669 }
2670 }
2671 }
2672 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " -> down child's lowerbound: %.9g, estimate: %.9g\n",
2673 SCIPnodeGetLowerbound(downchild), SCIPnodeGetEstimate(downchild));
2674 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " -> up child's lowerbound: %.9g, estimate: %.9g\n",
2675 SCIPnodeGetLowerbound(upchild), SCIPnodeGetEstimate(upchild));
2676
2677 return SCIP_OKAY;
2678}
2679
2680/** Get the number of iterations the last LP needed */
2681static
2683 SCIP* scip, /**< SCIP data structure */
2684 SCIP_Longint* iterations /**< pointer to store the number of iterations */
2685 )
2686{
2687 SCIP_LPI* lpi;
2688 int tmpiter;
2689
2690 assert(scip != NULL);
2691 assert(iterations != NULL);
2692
2693 /* get the LP interface of the last solved LP */
2694 SCIP_CALL( SCIPgetLPI(scip, &lpi) );
2695
2696 /* get the number of iterations from the interface */
2697 SCIP_CALL( SCIPlpiGetIterations(lpi, &tmpiter) );
2698
2699 *iterations = (SCIP_Longint)tmpiter;
2700
2701 return SCIP_OKAY;
2702}
2703
2704/** Creates a new probing node with a new bound for the given candidate and solves the corresponding LP. */
2705static
2707 SCIP* scip, /**< SCIP data structure */
2708 CONFIGURATION* config, /**< configuration to control the behavior */
2709 SCIP_Bool downbranching, /**< the branching direction */
2710 CANDIDATE* candidate, /**< the candidate to branch on */
2711 BRANCHINGRESULTDATA* resultdata, /**< pointer to the result data which gets filled with the status */
2712 SCIP_SOL* baselpsol, /**< the base lp solution */
2713 DOMAINREDUCTIONS* domreds, /**< struct to store the domain reduction found during propagation */
2714 STATUS* status /**< status will contain updated lperror and limit fields */
2715 )
2716{
2717 SCIP_Real oldupperbound;
2718 SCIP_Real oldlowerbound;
2719 SCIP_Real newbound;
2720 SCIP_LPSOLSTAT solstat;
2721 SCIP_VAR* branchvar;
2722 SCIP_Real branchval;
2723
2724 assert(scip != NULL);
2725 assert(candidate != NULL);
2726 assert(resultdata != NULL);
2727 assert(status != NULL);
2728 assert(config != NULL);
2729 assert(status != NULL);
2730
2731 branchvar = candidate->branchvar;
2732 branchval = candidate->branchval;
2733
2734 assert(branchvar != NULL);
2735 assert(!SCIPisFeasIntegral(scip, branchval));
2736
2737 if( downbranching )
2738 {
2739 /* round the given value down, so that it can be used as the new upper bound */
2740 newbound = SCIPfeasFloor(scip, branchval);
2741 }
2742 else
2743 {
2744 /* round the given value up, so that it can be used as the new lower bound */
2745 newbound = SCIPfeasCeil(scip, branchval);
2746 }
2747
2748 oldupperbound = SCIPvarGetUbLocal(branchvar);
2749 oldlowerbound = SCIPvarGetLbLocal(branchvar);
2750
2751#ifdef SCIP_DEBUG
2752 if( downbranching )
2753 {
2754 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "DownBranching: Var=<%s>, Proposed upper bound=<%g>, "
2755 "old bounds=[<%g>..<%g>], new bounds=[<%g>..<%g>]\n", SCIPvarGetName(branchvar), newbound, oldlowerbound,
2756 oldupperbound, oldlowerbound, newbound);
2757 }
2758 else
2759 {
2760 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "UpBranching: Var=<%s>, Proposed lower bound=<%g>, "
2761 "old bounds=[<%g>..<%g>], new bounds=[<%g>..<%g>]\n", SCIPvarGetName(branchvar), newbound, oldlowerbound,
2762 oldupperbound, newbound, oldupperbound);
2763 }
2764#endif
2765
2766 if( (downbranching && newbound < oldlowerbound - 0.5)
2767 || (!downbranching && newbound > oldupperbound + 0.5) )
2768 {
2769 /* if lb > ub we can cutoff this node */
2770 resultdata->cutoff = TRUE;
2771
2772 return SCIP_OKAY;
2773 }
2774
2775 assert(!resultdata->cutoff);
2776
2778
2779 if( downbranching )
2780 {
2781 /* down branching preparations */
2782 if( SCIPisFeasLT(scip, newbound, oldupperbound) )
2783 {
2784 /* If the new upper bound is smaller than the old upper bound and also
2785 * greater than (or equal to) the old lower bound, we set the new upper bound.
2786 * oldLowerBound <= newUpperBound < oldUpperBound */
2787 SCIP_CALL( SCIPchgVarUbProbing(scip, branchvar, newbound) );
2788 }
2789 }
2790 else
2791 {
2792 /* up branching preparations */
2793 if( SCIPisFeasGT(scip, newbound, oldlowerbound) )
2794 {
2795 /* If the new lower bound is greater than the old lower bound and also
2796 * smaller than (or equal to) the old upper bound, we set the new lower bound.
2797 * oldLowerBound < newLowerBound <= oldUpperBound
2798 */
2799 SCIP_CALL( SCIPchgVarLbProbing(scip, branchvar, newbound) );
2800 }
2801 }
2802
2803 /* restore the stored LP data (e.g., the basis) from a filtering run */
2804 if( candidateHasWarmStartInfo(candidate, downbranching) )
2805 {
2806 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Restoring lp information for %s branch of variable <%s>\n",
2807 downbranching ? "down" : "up", SCIPvarGetName(branchvar));
2808 SCIP_CALL( candidateLoadWarmStartInfo(scip, candidate, downbranching) );
2809 }
2810
2811 /* apply domain propagation */
2812 if( config->propagate )
2813 {
2814 SCIP_Longint ndomredsfound = 0;
2815
2816 SCIP_CALL( SCIPpropagateProbing(scip, config->maxproprounds, &resultdata->cutoff, &ndomredsfound) );
2817
2818 if( ndomredsfound > 0 )
2819 {
2820 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %" SCIP_LONGINT_FORMAT " domain reductions via propagation.\n", ndomredsfound);
2821
2822 /* domreds != NULL iff config->usedomainreduction */
2823 if( domreds != NULL )
2824 {
2825 int i;
2826 SCIP_VAR** problemvars = SCIPgetVars(scip);
2827 int nproblemvars = SCIPgetNVars(scip);
2828
2829 assert(problemvars != NULL);
2830
2831 assert(config->usedomainreduction);
2832
2833 for( i = 0; i < nproblemvars; i++ )
2834 {
2835 SCIP_Real lowerbound;
2836 SCIP_Real upperbound;
2837 SCIP_VAR* var = problemvars[i];
2838 assert(var != NULL);
2839
2840 lowerbound = SCIPvarGetLbLocal(var);
2841 upperbound = SCIPvarGetUbLocal(var);
2842#ifdef SCIP_STATISTIC
2843 addLowerBound(scip, var, lowerbound, baselpsol, FALSE, domreds, 0, FALSE);
2844 addUpperBound(scip, var, upperbound, baselpsol, FALSE, domreds, 0, FALSE);
2845#else
2846 addLowerBound(scip, var, lowerbound, baselpsol, FALSE, domreds);
2847 addUpperBound(scip, var, upperbound, baselpsol, FALSE, domreds);
2848#endif
2849 }
2850 }
2851 }
2852 }
2853
2854 if( !resultdata->cutoff )
2855 {
2856 /* solve the prepared probing LP */
2857 SCIP_CALL( SCIPsolveProbingLP(scip, -1, &status->lperror, &resultdata->cutoff) );
2858
2859 /* store the number of iterations needed */
2861
2862 solstat = SCIPgetLPSolstat(scip);
2863 assert(solstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY);
2864
2865 /* for us an error occurred, if an error during the solving occurred or the lp could not be solved but was not
2866 * cutoff */
2867 status->lperror = status->lperror || (solstat == SCIP_LPSOLSTAT_NOTSOLVED && resultdata->cutoff == FALSE);
2868
2869 /* if we seem to have reached a {time, iteration}-limit or the user cancelled the execution, we want to stop
2870 * further calculations and instead return the current calculation state */
2871 status->limitreached = (solstat == SCIP_LPSOLSTAT_ITERLIMIT) || (solstat == SCIP_LPSOLSTAT_TIMELIMIT);
2872
2873 if( resultdata->cutoff )
2874 {
2875 resultdata->objval = SCIPinfinity(scip);
2876 resultdata->dualbound = SCIPinfinity(scip);
2877 resultdata->dualboundvalid = TRUE;
2878 }
2879 else if( !status->limitreached && !status->lperror )
2880 {
2881 SCIP_Bool foundsol = FALSE;
2882
2883 SCIP_CALL( SCIPtryStrongbranchLPSol(scip, &foundsol, &resultdata->cutoff) );
2884
2885 /* if we have no error, we save the new objective value and the cutoff decision in the resultdata */
2886 resultdata->objval = SCIPgetLPObjval(scip);
2887 resultdata->dualbound = SCIPgetLPObjval(scip);
2888 resultdata->dualboundvalid = TRUE;
2889 resultdata->cutoff = resultdata->cutoff || SCIPisGE(scip, resultdata->objval, SCIPgetCutoffbound(scip));
2890
2891 assert(solstat != SCIP_LPSOLSTAT_INFEASIBLE || resultdata->cutoff);
2892 }
2893 }
2894
2895 return SCIP_OKAY;
2896}
2897
2898/** Creates a logic or constraint based on the given 'consvars'. This array has to consist of the negated
2899 * versions of the variables present on a cutoff "path" (path means all variables from the root directly
2900 * to the cutoff node).
2901 * Let x_1, ..., x_n be the variables on a path to a cutoff with the branchings x_i <= 1 for all i.
2902 * Summed up the constraints would look like x_1 + ... x_n <= n-1.
2903 * Let y_i = 1 - x_i. Then we have y_1 + ... + y_n >= 1 which is a logic or constraint.
2904 */
2905static
2907 SCIP* scip, /**< SCIP data structure */
2908 CONFIGURATION* config, /**< configuration containing flags changing the behavior */
2909 SCIP_CONS** constraint, /**< pointer to store the created constraint in */
2910 char* constraintname, /**< name of the new constraint */
2911 SCIP_VAR** consvars, /**< array containing the negated binary vars */
2912 int nconsvars /**< the number of elements in 'consvars' */
2913 )
2914{
2915 SCIP_Bool initial;
2917 SCIP_Bool removable;
2918 SCIP_Bool enforce = FALSE;
2919 SCIP_Bool check = FALSE;
2920 SCIP_Bool propagate = TRUE;
2921 SCIP_Bool local = TRUE;
2922 SCIP_Bool modifiable = FALSE;
2923 SCIP_Bool dynamic = FALSE;
2924 SCIP_Bool stickingatnode = FALSE;
2925
2926 assert(scip != NULL);
2927 assert(config != NULL);
2928 assert(constraint != NULL);
2929 assert(constraintname != NULL);
2930 assert(consvars != NULL);
2931 assert(nconsvars > 0);
2932
2933 initial = (config->addbinconsrow == 2);
2934 separate = (config->addbinconsrow == 1);
2935 removable = (config->addbinconsrow == 1);
2936
2937 /* creating a logic or constraint based on the list of vars in 'consvars'.
2938 * A logic or constraints looks like that: y_1 + ... + y_n >= 1.
2939 */
2940 SCIP_CALL( SCIPcreateConsLogicor(scip, constraint, constraintname, nconsvars, consvars, initial, separate, enforce,
2941 check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
2942 return SCIP_OKAY;
2943}
2944
2945/**
2946 * Create a name for the binary constraint.
2947 */
2948static
2950 SCIP_VAR** binaryvars, /**< the variables contained in the constraint */
2951 int nbinaryvars, /**< the number of elements in 'binaryvars' */
2952 char* constraintname /**< the char pointer to store the name in */
2953 )
2954{
2955 int i;
2956
2957 assert(binaryvars != NULL);
2958 assert(nbinaryvars > 0);
2959 assert(constraintname != NULL);
2960 assert(binaryvars[0] != NULL);
2961
2962 (void) SCIPsnprintf(constraintname, SCIP_MAXSTRLEN, "lookahead_bin_%s", SCIPvarGetName(binaryvars[0]));
2963
2964 for( i = 1; i < nbinaryvars; i++ )
2965 {
2966 size_t oldlen;
2967 SCIP_VAR* var = binaryvars[i];
2968 assert(var != NULL);
2969
2970 oldlen = strlen(constraintname);
2971 (void) strncat(constraintname, "_", SCIP_MAXSTRLEN-oldlen);
2972 (void) strncat(constraintname, SCIPvarGetName(var), SCIP_MAXSTRLEN-oldlen-1);
2973 }
2974}
2975
2976/**
2977 * Add the constraints found during the lookahead branching.
2978 * The implicit binary bounds were found when two or more consecutive branchings of binary variables were cutoff. Then these
2979 * branching constraints can be combined into a single 'binary constraint'.
2980 */
2981static
2983 SCIP* scip, /**< SCIP data structure */
2984 CONFIGURATION* config, /**< the configuration of the branching rule */
2985 BINCONSDATA* binconsdata, /**< collected binary constraints */
2986 SCIP_SOL* baselpsol /**< the original lp solution, used to check the violation of the constraint */
2987#ifdef SCIP_STATISTIC
2988 ,STATISTICS* statistics /**< statistics data */
2989#endif
2990 )
2991{
2992 assert(scip != NULL);
2993 assert(config != NULL);
2994 assert(binconsdata != NULL);
2995 assert(baselpsol != NULL);
2996 assert(binconsdata->binaryvars != NULL);
2997 assert(binconsdata->binaryvars->nbinaryvars > 0);
2998
2999 /* if we only have one var for the constraint, we can ignore it as it is already added as a domain reduction. */
3000 if( binconsdata->binaryvars->nbinaryvars > 1 )
3001 {
3002 int i;
3003 SCIP_VAR** negatedvars;
3004 SCIP_Real lhssum = 0.0;
3005 SCIP_Bool violated;
3006
3007 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Adding binary constraint for <%i> vars.\n",
3008 binconsdata->binaryvars->nbinaryvars);
3009
3010 SCIP_CALL( SCIPallocBufferArray(scip, &negatedvars, binconsdata->binaryvars->nbinaryvars) );
3011
3012 for( i = 0; i < binconsdata->binaryvars->nbinaryvars; i++ )
3013 {
3014 SCIP_VAR* var = binconsdata->binaryvars->binaryvars[i];
3015 assert(var != NULL);
3016 assert(SCIPvarIsBinary(var));
3017
3018 SCIP_CALL( SCIPgetNegatedVar(scip, var, &negatedvars[i]) );
3019 lhssum += SCIPgetSolVal(scip, baselpsol, negatedvars[i]);
3020 }
3021
3022 violated = (lhssum < 1);
3023
3024 if( config->addnonviocons || violated )
3025 {
3026 SCIP_CALL( constraintListAppend(scip, binconsdata->conslist, negatedvars,
3027 binconsdata->binaryvars->nbinaryvars, violated) );
3028
3029 /* the constraint we will be building is a logic or: we have a list of binary variables that were
3030 * cutoff while we branched on with >= 1. So we have the constraint: x_1 + ... + x_n <= n-1.
3031 * Let y = (1-x), then we have an equivalent formulation: y_1 + ... + y_n >= 1. If the base lp
3032 * is violating this constraint we count this for our number of violated constraints and bounds. */
3033 if( violated )
3034 binconsdata->conslist->nviolatedcons++;
3035 }
3036
3037 SCIPfreeBufferArray(scip, &negatedvars);
3038 }
3039#ifdef SCIP_STATISTIC
3040 else
3041 {
3042 assert(statistics != NULL);
3043 statistics->ndomredcons++;
3044 }
3045#endif
3046
3047 return SCIP_OKAY;
3048}
3049
3050/** applies the binary constraints to the original problem. */
3051static
3053 SCIP* scip, /**< SCIP data structure */
3054 SCIP_NODE* basenode, /**< original branching node */
3055 CONSTRAINTLIST* conslist, /**< list of constraints to be added */
3056 CONFIGURATION* config, /**< the configuration of the branching rule */
3057 SCIP_Bool* consadded, /**< pointer to store whether at least one constraint was added */
3058 SCIP_Bool* cutoff, /**< pointer to store whether the original problem was made infeasible */
3059 SCIP_Bool* boundchange /**< pointer to store whether a bound change has been applied by adding the
3060 * constraint as a clique */
3061#ifdef SCIP_STATISTIC
3062 ,STATISTICS* statistics /**< statistics data */
3063#endif
3064 )
3065{
3066 int nconsadded = 0;
3067 int i;
3068#ifdef SCIP_STATISTIC
3069 int nvioconsadded = 0;
3070
3071 assert(statistics != NULL);
3072#endif
3073 assert(basenode != NULL);
3074 assert(conslist != NULL);
3075 assert(config != NULL);
3076 assert(consadded != NULL);
3077 assert(cutoff != NULL);
3078 assert(boundchange != NULL);
3079
3080 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "processing %d binary constraints.\n", conslist->nelements);
3081
3082 if( conslist->nelements == 0 )
3083 return SCIP_OKAY;
3084
3085 for( i = 0; i < conslist->nelements; i++ )
3086 {
3087 SCIP_VAR** vars = conslist->consvars[i];
3088 int nvars = conslist->nconsvars[i];
3089 int v;
3090#ifdef SCIP_STATISTIC
3091 SCIP_Bool violated = conslist->violated[i];
3092#endif
3093
3094 assert(vars != NULL);
3095
3096 for( v = 0; v < nvars; ++v )
3097 {
3098 assert(vars[v] != NULL);
3099 assert(SCIPvarIsBinary(vars[v]));
3100
3101 if( SCIPvarGetLbLocal(vars[v]) > 0.5 )
3102 break;
3103 }
3104
3105 /* no variable is fixed to 1 yet, so constraint is not redundant */
3106 if( v == nvars )
3107 {
3108 SCIP_CONS* constraint;
3109 char constraintname[SCIP_MAXSTRLEN];
3110
3111 /* create a name for the new constraint */
3112 createBinaryConstraintName(vars, nvars, constraintname);
3113 /* create the constraint with the freshly created name */
3114 SCIP_CALL( createBinaryConstraint(scip, config, &constraint, constraintname, vars, nvars) );
3115
3116#ifdef PRINTNODECONS
3117 SCIPinfoMessage(scip, NULL, "Created constraint:\n");
3118 SCIP_CALL( SCIPprintCons(scip, constraint, NULL) );
3119 SCIPinfoMessage(scip, NULL, "\n");
3120#endif
3121 /* add the constraint to the given node */
3122 SCIP_CALL( SCIPaddConsNode(scip, basenode, constraint, NULL) );
3123
3124 nconsadded++;
3125
3126#ifdef SCIP_STATISTIC
3127 if( violated )
3128 nvioconsadded++;
3129#endif
3130
3131 /* release the constraint, as it is no longer needed */
3132 SCIP_CALL( SCIPreleaseCons(scip, &constraint) );
3133
3134 /* a 2-variable logicor constraint can be expressend as a clique on the negated variables;
3135 * add it to the clique table if we are at the root node */
3136 if( nvars == 2 && config->addclique && SCIPgetNNodes(scip) == 1 )
3137 {
3138 SCIP_Bool* values;
3139 SCIP_Bool infeasible;
3140 int nbdchgs;
3141
3142 SCIP_CALL( SCIPallocClearBufferArray(scip, &values, nvars) );
3143
3144 /* a two-variable logicor constraint x + y >= 1 yields the implication x == 0 -> y == 1, and is represented
3145 * by the clique inequality ~x + ~y <= 1
3146 */
3147 SCIP_CALL( SCIPaddClique(scip, vars, values, nvars, FALSE, &infeasible, &nbdchgs) );
3148
3149#ifdef SCIP_STATISTIC
3150 statistics->ncliquesadded++;
3151#endif
3152
3153 if( infeasible )
3154 *cutoff = TRUE;
3155
3156 if( nbdchgs > 0 )
3157 *boundchange = TRUE;
3158
3159 SCIPfreeBufferArray(scip, &values);
3160 }
3161 }
3162 }
3163
3164 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "added %d/%d binary constraints.\n", nconsadded, conslist->nelements);
3165
3166 if( nconsadded > 0 )
3167 {
3168 *consadded = TRUE;
3169
3170#ifdef SCIP_STATISTIC
3171 statistics->nbinconst += nconsadded;
3172 statistics->nbinconstvio += nvioconsadded;
3173#endif
3174 }
3175
3176 return SCIP_OKAY;
3177}
3178
3179/** checks whether the given bounds are still the bounds of the given variable */
3180static
3182 SCIP* scip, /**< SCIP data structure */
3183 SCIP_VAR* var, /**< variable to check the bounds of */
3184 SCIP_Real lowerbound, /**< reference lower bound */
3185 SCIP_Real upperbound /**< reference upper bound */
3186 )
3187{
3188 assert(scip != NULL);
3189 assert(var != NULL);
3190 assert(SCIPisFeasIntegral(scip, lowerbound));
3191 assert(SCIPisFeasIntegral(scip, upperbound));
3192 assert(!SCIPisEQ(scip, lowerbound, upperbound));
3193 assert(SCIPvarIsIntegral(var));
3194
3195 /* due to roundings the value might have changed slightly without an actual influence on the integral value */
3196 return SCIPvarGetLbLocal(var) > lowerbound + 0.5 || SCIPvarGetUbLocal(var) < upperbound - 0.5;
3197}
3198
3199/** Checks whether the branching rule should continue or terminate with the currently gathered data */
3200static
3202 STATUS* status, /**< current status */
3203 SCIP_Bool checkdomreds /**< should domain reductions be checked? */
3204 )
3205{
3206 assert(status != NULL);
3207
3208 return !status->lperror && !status->cutoff && !status->limitreached
3209 && !status->maxnconsreached && (!checkdomreds || !status->domred);
3210}
3211
3212/** Checks whether the branching rule should continue or terminate with the currently gathered data. Additionally decrements
3213 * the given loopcounter. This is needed to better emulate the behavior of FSB by LAB with a depth of 1. */
3214static
3216 STATUS* status, /**< current status */
3217 int* loopcounter /**< the counter to decrement */
3218 )
3219{
3220 SCIP_Bool branchfurther;
3221
3222 assert(status != NULL);
3223 assert(loopcounter != NULL);
3224
3225 branchfurther = isBranchFurther(status, FALSE);
3226
3227 if( !branchfurther )
3228 (*loopcounter)--;
3229
3230 return branchfurther;
3231}
3232
3233/** determines whether the previous LAB result of a variable should be reused */
3234static
3236 SCIP* scip, /**< SCIP data structure */
3237 PERSISTENTDATA* persistent, /**< data storage over multiple calls to the rule */
3238 CONFIGURATION* config, /**< the configuration of the branching rule */
3239 SCIP_VAR* branchvar /**< variable to check */
3240 )
3241{
3242 assert(scip != NULL);
3243 assert(config != NULL);
3244 assert(branchvar != NULL);
3245
3246 /* an old branching can be reused, if we are still at the same node and just a few LPs were solved in between */
3247 if( config->inscoring )
3248 {
3249 return SCIPgetVarStrongbranchNode(scip, branchvar) == SCIPgetNNodes(scip)
3250 && SCIPgetVarStrongbranchLPAge(scip, branchvar) < config->reevalagefsb;
3251 }
3252 else
3253 {
3254 return persistent->lastbranchid[SCIPvarGetProbindex(branchvar)] == SCIPgetNNodes(scip)
3255 && SCIPgetNLPs(scip) - persistent->lastbranchnlps[SCIPvarGetProbindex(branchvar)] < config->reevalage;
3256 }
3257}
3258
3259/** retrieves previous LAB result for the given variable */
3260static
3262 SCIP* scip, /**< SCIP data structure */
3263 PERSISTENTDATA* persistent, /**< data storage over multiple calls to the rule */
3264 CONFIGURATION* config, /**< the configuration of the branching rule */
3265 SCIP_VAR* branchvar, /**< variable to get previous results for */
3266 BRANCHINGRESULTDATA* downbranchingresult,/**< pointer to store the previous down result in */
3267 BRANCHINGRESULTDATA* upbranchingresult, /**< pointer to store the previous up result in */
3268 SCIP_Real* oldlpobjval /**< pointer to store the previous base lp objval in */
3269 )
3270{
3271 assert(scip != NULL);
3272 assert(persistent != NULL);
3273 assert(branchvar != NULL);
3274 assert(downbranchingresult != NULL);
3275 assert(upbranchingresult != NULL);
3276 assert(oldlpobjval != NULL);
3277
3278 if( config->inscoring )
3279 {
3280 SCIP_CALL( SCIPgetVarStrongbranchLast(scip, branchvar, &downbranchingresult->dualbound, &upbranchingresult->dualbound,
3281 &downbranchingresult->dualboundvalid, &upbranchingresult->dualboundvalid, NULL, oldlpobjval) );
3282 downbranchingresult->objval = downbranchingresult->dualbound;
3283 upbranchingresult->objval = upbranchingresult->dualbound;
3284 }
3285 else
3286 {
3287 int varindex = SCIPvarGetProbindex(branchvar);
3288
3289 branchingResultDataCopy(persistent->lastbranchdownres[varindex], downbranchingresult);
3290 branchingResultDataCopy(persistent->lastbranchupres[varindex], upbranchingresult);
3291 *oldlpobjval = persistent->lastbranchlpobjval[varindex];
3292 }
3293
3294#ifdef SCIP_DEBUG
3295 {
3296 SCIP_Real downgain;
3297 SCIP_Real upgain;
3298
3299 downgain = MAX(downbranchingresult->dualbound - *oldlpobjval, 0);
3300 upgain = MAX(upbranchingresult->dualbound - *oldlpobjval, 0);
3301
3302 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead branching on variable <%s> already performed (lpage=%"
3303 SCIP_LONGINT_FORMAT ", down=%.9g (%+g), up=%.9g (%+g))\n", SCIPvarGetName(branchvar),
3304 SCIPgetNLPs(scip) - persistent->lastbranchnlps[SCIPvarGetProbindex(branchvar)],
3305 downbranchingresult->dualbound, downgain, upbranchingresult->dualbound, upgain);
3306 }
3307#endif
3308
3309 return SCIP_OKAY;
3310}
3311
3312/** stores the LAB result for use in a later call to the branching rule */
3313static
3315 SCIP* scip, /**< SCIP data structure */
3316 PERSISTENTDATA* persistent, /**< data storage over multiple calls to the rule */
3317 CONFIGURATION* config, /**< the configuration of the branching rule */
3318 SCIP_VAR* branchvar, /**< variable to store previous results for */
3319 SCIP_Real branchval, /**< the value of branchvar */
3320 BRANCHINGRESULTDATA* downbranchingresult,/**< down branching result to store */
3321 BRANCHINGRESULTDATA* upbranchingresult, /**< up branching result to store */
3322 SCIP_Real lpobjval /**< base lp obj val */
3323 )
3324{
3325 assert(scip != NULL);
3326 assert(persistent != NULL);
3327 assert(branchvar != NULL);
3328 assert(downbranchingresult != NULL);
3329 assert(upbranchingresult != NULL);
3330
3331 if( config->inscoring )
3332 {
3333 SCIP_Longint niterations = downbranchingresult->niterations + upbranchingresult->niterations;
3334
3335 SCIP_CALL( SCIPsetVarStrongbranchData(scip, branchvar, lpobjval, branchval, downbranchingresult->dualbound,
3336 upbranchingresult->dualbound, downbranchingresult->dualboundvalid, upbranchingresult->dualboundvalid, niterations,
3337 INT_MAX) );
3338 }
3339 else
3340 {
3341 int varindex = SCIPvarGetProbindex(branchvar);
3342
3343 branchingResultDataCopy(downbranchingresult, persistent->lastbranchdownres[varindex]);
3344 branchingResultDataCopy(upbranchingresult, persistent->lastbranchupres[varindex]);
3345 persistent->lastbranchlpobjval[varindex] = lpobjval;
3346 persistent->lastbranchid[varindex] = SCIPgetNNodes(scip);
3347 persistent->lastbranchnlps[varindex] = SCIPgetNLPs(scip);
3348 }
3349
3350 return SCIP_OKAY;
3351}
3352
3353/** calculates the FSB scores for the given candidates */
3354static
3356 SCIP* scip, /**< SCIP data structure */
3357 STATUS* status, /**< current status */
3358 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
3359 CONFIGURATION* config, /**< the configuration of the branching rule */
3360 SCIP_SOL* baselpsol, /**< base lp solution */
3361 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
3362 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
3363 CANDIDATELIST* candidatelist, /**< list containing all candidates to consider */
3364 BRANCHINGDECISION* decision, /**< struct to store the final decision */
3365 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
3366 LEVEL2DATA* level2data, /**< level 2 LP results data */
3367 SCIP_Real lpobjval /**< base LP objective value */
3368#ifdef SCIP_STATISTIC
3369 ,STATISTICS* statistics /**< general statistical data */
3370 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
3371#endif
3372 )
3373{
3374 assert(scip != NULL);
3375 assert(config != NULL);
3376 assert(candidatelist != NULL);
3377 assert(status != NULL);
3378 assert(scorecontainer != NULL);
3379 assert(SCIPinProbing(scip));
3381
3382 /* inform configuration that we are in scoring mode now */
3383 config->inscoring = TRUE;
3384
3385#ifdef SCIP_STATISTIC
3386 SCIP_CALL( selectVarRecursive(scip, status, persistent, config, baselpsol, domainreductions,
3387 binconsdata, candidatelist, decision, scorecontainer, level2data, 1,
3388 lpobjval, lpobjval, NULL, NULL, NULL, NULL, NULL, NULL,
3389 statistics, localstats, NULL, NULL) );
3390#else
3391 SCIP_CALL( selectVarRecursive(scip, status, persistent, config, baselpsol, domainreductions,
3392 binconsdata, candidatelist, decision, scorecontainer, level2data, 1,
3393 lpobjval, lpobjval, NULL, NULL, NULL, NULL, NULL, NULL) );
3394#endif
3395
3396 /* inform configuration that we leave scoring mode now */
3397 config->inscoring = FALSE;
3398
3399 return SCIP_OKAY;
3400}
3401
3402#ifdef SCIP_DEBUG
3403/** prints the given candidate list */
3404static
3405void printCandidates(
3406 SCIP* scip, /**< SCIP data structure */
3407 SCIP_VERBLEVEL lvl, /**< verbosity level to print the list in */
3408 CANDIDATELIST* candidatelist /**< the list to be printed */
3409 )
3410{
3411 int ncands;
3412 int i;
3413
3414 assert(scip != NULL);
3415 assert(candidatelist != NULL);
3416
3417 ncands = candidatelist->ncandidates;
3418
3419 LABdebugMessagePrint(scip, lvl, "[");
3420
3421 for( i = 0; i < ncands; i++ )
3422 {
3423 CANDIDATE* cand = candidatelist->candidates[i];
3424
3425 assert(cand != NULL);
3426 assert(cand->branchvar != NULL);
3427
3428 LABdebugMessagePrint(scip, lvl, "%s", SCIPvarGetName(cand->branchvar));
3429 if(i != ncands-1)
3430 {
3431 LABdebugMessagePrint(scip, lvl, ", ");
3432 }
3433 }
3434 LABdebugMessagePrint(scip, lvl, "]\n");
3435}
3436#endif
3437
3438/** calculates the score based on the down and up branching result */
3439static
3441 SCIP* scip, /**< SCIP data structure */
3442 SCIP_VAR* branchvar, /**< variable to get the score for */
3443 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3444 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
3445 SCIP_Real lpobjval /**< objective value to get difference to as gain */
3446 )
3447{
3448 SCIP_Real score;
3449 SCIP_Real downgain = SCIPsumepsilon(scip);
3450 SCIP_Real upgain = SCIPsumepsilon(scip);
3451
3452 assert(scip != NULL);
3453 assert(branchvar != NULL);
3454 assert(downbranchingresult != NULL);
3455 assert(upbranchingresult != NULL);
3456
3457 /* the gain is the difference of the dualbound of a child and the reference objective value;
3458 * by bounding it by zero we are safe from numerical troubles
3459 */
3460 if( !downbranchingresult->cutoff )
3461 downgain = MAX(downgain, downbranchingresult->dualbound - lpobjval);
3462 if( !upbranchingresult->cutoff )
3463 upgain = MAX(upgain, upbranchingresult->dualbound - lpobjval);
3464
3465 downgain = 100.0 * downgain;
3466 upgain = 100.0 * upgain;
3467
3468 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3469 * realistic gain for the infeasible child;
3470 * if both children are infeasible we just reset the initial zero values again
3471 */
3472 if( downbranchingresult->cutoff )
3473 downgain = 2 * upgain;
3474 if( upbranchingresult->cutoff )
3475 upgain = 2 * downgain;
3476
3477 score = SCIPgetBranchScore(scip, branchvar, downgain, upgain);
3478
3479 return score;
3480}
3481
3482/** calculates the score based on the down and up branching result */
3483static
3485 SCIP* scip, /**< SCIP data structure */
3486 SCIP_VAR* branchvar, /**< variable to get the score for */
3487 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3488 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
3489 SCIP_Real lpobjval /**< objective value to get difference to as gain */
3490 )
3491{
3492 SCIP_Real lpscore;
3493 SCIP_Real dbscore;
3494 SCIP_Real score;
3495 SCIP_Real downgain = SCIPsumepsilon(scip);
3496 SCIP_Real upgain = SCIPsumepsilon(scip);
3497
3498 assert(scip != NULL);
3499 assert(branchvar != NULL);
3500 assert(downbranchingresult != NULL);
3501 assert(upbranchingresult != NULL);
3502
3503 /* the gain is the difference of the dualbound of a child and the reference objective value;
3504 * by bounding it by zero we are safe from numerical troubles
3505 */
3506 if( !downbranchingresult->cutoff )
3507 downgain = MAX(downgain, downbranchingresult->objval - lpobjval);
3508 if( !upbranchingresult->cutoff )
3509 upgain = MAX(upgain, upbranchingresult->objval - lpobjval);
3510
3511 downgain = 100.0 * downgain;
3512 upgain = 100.0 * upgain;
3513
3514 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3515 * realistic gain for the infeasible child;
3516 * if both children are infeasible we just reset the initial zero values again
3517 */
3518 if( downbranchingresult->cutoff )
3519 downgain = 2 * upgain;
3520 if( upbranchingresult->cutoff )
3521 upgain = 2 * downgain;
3522
3523 lpscore = SCIPgetBranchScore(scip, branchvar, downgain, upgain);
3524
3525 /* the gain is the difference of the dualbound of a child and the reference objective value;
3526 * by bounding it by zero we are safe from numerical troubles
3527 */
3528 if( !downbranchingresult->cutoff )
3529 downgain = MAX(SCIPsumepsilon(scip), downbranchingresult->dualbound - lpobjval); /*lint !e666*/
3530 if( !upbranchingresult->cutoff )
3531 upgain = MAX(SCIPsumepsilon(scip), upbranchingresult->dualbound - lpobjval); /*lint !e666*/
3532
3533 downgain = 100.0 * downgain;
3534 upgain = 100.0 * upgain;
3535
3536 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3537 * realistic gain for the infeasible child;
3538 * if both children are infeasible we just reset the initial zero values again
3539 */
3540 if( downbranchingresult->cutoff )
3541 downgain = 2 * upgain;
3542 if( upbranchingresult->cutoff )
3543 upgain = 2 * downgain;
3544
3545 dbscore = SCIPgetBranchScore(scip, branchvar, downgain, upgain);
3546
3547 score = SCIPgetBranchScore(scip, branchvar, lpscore, dbscore);
3548
3549 return score;
3550}
3551
3552/** calculates the score based on the down and up branching scores */
3553static
3555 SCIP* scip, /**< SCIP data structure */
3556 SCIP_VAR* branchvar, /**< variable to get the score for */
3557 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3558 BRANCHINGRESULTDATA* upbranchingresult /**< branching result of the up branch */
3559 )
3560{
3561 SCIP_Real score;
3562 SCIP_Real downscore;
3563 SCIP_Real upscore;
3564
3565 assert(scip != NULL);
3566 assert(branchvar != NULL);
3567 assert(downbranchingresult != NULL);
3568 assert(upbranchingresult != NULL);
3569
3570 assert(downbranchingresult->deeperscore >= -0.2 || downbranchingresult->cutoff || SCIPisStopped(scip));
3571 assert(upbranchingresult->deeperscore >= -0.2 || upbranchingresult->cutoff || SCIPisStopped(scip));
3572
3573 downscore = sqrt(downbranchingresult->deeperscore);
3574 upscore = sqrt(upbranchingresult->deeperscore);
3575
3576 downscore = MAX(downscore, SCIPsumepsilon(scip)); /*lint !e666*/
3577 upscore = MAX(upscore, SCIPsumepsilon(scip)); /*lint !e666*/
3578
3579 if( downbranchingresult->cutoff )
3580 downscore = 2 * upscore;
3581 if( upbranchingresult->cutoff )
3582 upscore = 2 * downscore;
3583
3584 score = SCIPgetBranchScore(scip, branchvar, downscore, upscore);
3585
3586 return score;
3587}
3588
3589/** calculates the score based on the down and up branching scores */
3590static
3592 SCIP* scip, /**< SCIP data structure */
3593 SCIP_VAR* branchvar, /**< variable to get the score for */
3594 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3595 BRANCHINGRESULTDATA* upbranchingresult /**< branching result of the up branch */
3596 )
3597{
3598 SCIP_Real score;
3599 SCIP_Real downscore;
3600 SCIP_Real upscore;
3601 SCIP_Real totaldowngains;
3602 SCIP_Real totalupgains;
3603 SCIP_Real nlowestlevelcutoffs;
3604 int ntotaldowngains;
3605 int ntotalupgains;
3606
3607 assert(scip != NULL);
3608 assert(branchvar != NULL);
3609 assert(downbranchingresult != NULL);
3610 assert(upbranchingresult != NULL);
3611
3612 assert(downbranchingresult->deeperscore >= -0.2 || downbranchingresult->cutoff || SCIPisStopped(scip));
3613 assert(upbranchingresult->deeperscore >= -0.2 || upbranchingresult->cutoff || SCIPisStopped(scip));
3614
3615 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(MAX(1,downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes));
3616 totaldowngains = downbranchingresult->totalgains;
3617 totalupgains = upbranchingresult->totalgains;
3618 ntotaldowngains = MAX(1, downbranchingresult->ntotalgains);
3619 ntotalupgains = MAX(1, upbranchingresult->ntotalgains);
3620
3621 downscore = sqrt(downbranchingresult->deeperscore);
3622 upscore = sqrt(upbranchingresult->deeperscore);
3623
3624 downscore = MAX(downscore, SCIPsumepsilon(scip)); /*lint !e666*/
3625 upscore = MAX(upscore, SCIPsumepsilon(scip)); /*lint !e666*/
3626
3627 if( downbranchingresult->cutoff )
3628 downscore = 2 * upscore;
3629 if( upbranchingresult->cutoff )
3630 upscore = 2 * downscore;
3631
3632 score = SCIPgetBranchScore(scip, branchvar, downscore, upscore);
3633
3634 downscore = sqrt(totaldowngains/ntotaldowngains);
3635 upscore = sqrt(totalupgains/ntotalupgains);
3636
3637 downscore = MAX(downscore, SCIPsumepsilon(scip)); /*lint !e666*/
3638 upscore = MAX(upscore, SCIPsumepsilon(scip)); /*lint !e666*/
3639
3640 score += SCIPgetBranchScore(scip, branchvar, downscore, upscore)*nlowestlevelcutoffs;
3641
3642 return score;
3643}
3644
3645/** calculates the combined gain, weighted with parameters given by the user configuration */
3646static
3648 SCIP* scip, /**< SCIP data structure */
3649 CONFIGURATION* config, /**< LAB configuration */
3650 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3651 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
3652 SCIP_Real lpobjval /**< objective value to get difference to as gain */
3653 )
3654{
3655 SCIP_Real downgain = 0.0;
3656 SCIP_Real upgain = 0.0;
3657
3658 assert(config != NULL);
3659 assert(downbranchingresult != NULL);
3660 assert(upbranchingresult != NULL);
3661
3662 /* the gain is the difference of the dualbound of a child and the reference objective value;
3663 * by bounding it by zero we are safe from numerical troubles
3664 */
3665 if( !downbranchingresult->cutoff )
3666 downgain = MAX(0, downbranchingresult->dualbound - lpobjval);
3667 if( !upbranchingresult->cutoff )
3668 upgain = MAX(0, upbranchingresult->dualbound - lpobjval);
3669
3670 if( config->scoringfunction == 's' )
3671 {
3672 if( downbranchingresult->cutoff )
3673 downgain = SCIPinfinity(scip);
3674 if( upbranchingresult->cutoff )
3675 upgain = SCIPinfinity(scip);
3676 }
3677 else
3678 {
3679 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3680 * realistic gain for the infeasible child;
3681 * if both children are infeasible we just reset the initial zero values again
3682 */
3683 if( downbranchingresult->cutoff )
3684 downgain = upgain;
3685 if( upbranchingresult->cutoff )
3686 upgain = downgain;
3687 }
3688
3689 return config->minweight * MIN(downgain, upgain) + (1.0 - config->minweight) * MAX(downgain, upgain);
3690}
3691
3692/** calculates the score as mentioned in the lookahead branching paper by Glankwamdee and Linderoth;
3693 * their score scales the number of cutoffs on the last layer of a 2-level temporary branching tree with the average gain of
3694 * every last level problem; together with the best gain for each branch of a variable we get the final score
3695 */
3696static
3698 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3699 BRANCHINGRESULTDATA* upbranchingresult /**< branching result of the up branch */
3700 )
3701{
3702 SCIP_Real bestdowngain;
3703 SCIP_Real bestupgain;
3704 SCIP_Real totaldowngains;
3705 SCIP_Real totalupgains;
3706 int nlowestlevelcutoffs;
3707 int ntotaldowngains;
3708 int ntotalupgains;
3709
3710 assert(downbranchingresult != NULL);
3711 assert(upbranchingresult != NULL);
3712
3713 nlowestlevelcutoffs = downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs;
3714 bestdowngain = downbranchingresult->bestgain;
3715 bestupgain = upbranchingresult->bestgain;
3716 totaldowngains = downbranchingresult->totalgains;
3717 totalupgains = upbranchingresult->totalgains;
3718 ntotaldowngains = MAX(1, downbranchingresult->ntotalgains);
3719 ntotalupgains = MAX(1, upbranchingresult->ntotalgains);
3720
3721 return bestdowngain + bestupgain + (totaldowngains/ntotaldowngains + totalupgains/ntotalupgains)*nlowestlevelcutoffs;
3722}
3723
3724/** calculates the score as mentioned in the lookahead branching paper by Glankwamdee and Linderoth;
3725 * their score scales the number of cutoffs on the last layer of a 2-level temporary branching tree with the average gain of
3726 * every last level problem; together with the best gain for each branch of a variable we get the final score
3727 */
3728static
3730 CONFIGURATION* config, /**< LAB configuration */
3731 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3732 BRANCHINGRESULTDATA* upbranchingresult /**< branching result of the up branch */
3733 )
3734{
3735 SCIP_Real bestdowngain;
3736 SCIP_Real bestupgain;
3737 SCIP_Real totaldowngains;
3738 SCIP_Real totalupgains;
3739 SCIP_Real nlowestlevelcutoffs;
3740 int ntotaldowngains;
3741 int ntotalupgains;
3742
3743 assert(downbranchingresult != NULL);
3744 assert(upbranchingresult != NULL);
3745
3746 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes);
3747 bestdowngain = downbranchingresult->bestgain;
3748 bestupgain = upbranchingresult->bestgain;
3749 totaldowngains = downbranchingresult->totalgains;
3750 totalupgains = upbranchingresult->totalgains;
3751 ntotaldowngains = MAX(1, downbranchingresult->ntotalgains);
3752 ntotalupgains = MAX(1, upbranchingresult->ntotalgains);
3753
3754 return config->minweight*MIN(bestdowngain, bestupgain) + (1.0 - config->minweight)*MAX(bestdowngain, bestupgain) + (totaldowngains/ntotaldowngains + totalupgains/ntotalupgains)*nlowestlevelcutoffs;
3755}
3756
3757static
3759 SCIP* scip, /**< SCIP data structure */
3760 SCIP_VAR* branchvar, /**< variable to get the score for */
3761 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3762 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
3763 SCIP_Real lpobjval /**< objective value to get difference to as gain */
3764 )
3765{
3766 SCIP_Real score;
3767 SCIP_Real downgain = SCIPsumepsilon(scip);
3768 SCIP_Real upgain = SCIPsumepsilon(scip);
3769 SCIP_Real gap;
3770 int nlowestlevelcutoffs;
3771
3772 assert(downbranchingresult != NULL);
3773 assert(upbranchingresult != NULL);
3774
3775 nlowestlevelcutoffs = 0;
3776
3777 /* the gain is the difference of the dualbound of a child and the reference objective value;
3778 * by bounding it by zero we are safe from numerical troubles
3779 */
3780 if( !downbranchingresult->cutoff )
3781 {
3782 nlowestlevelcutoffs += downbranchingresult->ndeepestcutoffs;
3783 downgain = MAX(downgain, downbranchingresult->dualbound - lpobjval);
3784 }
3785 if( !upbranchingresult->cutoff )
3786 {
3787 nlowestlevelcutoffs += upbranchingresult->ndeepestcutoffs;
3788 upgain = MAX(upgain, upbranchingresult->dualbound - lpobjval);
3789 }
3790
3791 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3792 * realistic gain for the infeasible child;
3793 * if both children are infeasible we just reset the initial zero values again
3794 */
3795 if( downbranchingresult->cutoff )
3796 {
3797 nlowestlevelcutoffs += 2 * SCIPgetNPseudoBranchCands(scip);
3798 downgain = 2 * upgain;
3799 }
3800 if( upbranchingresult->cutoff )
3801 {
3802 nlowestlevelcutoffs += 2 * SCIPgetNPseudoBranchCands(scip);
3803 upgain = 2 * downgain;
3804 }
3805
3806 gap = SCIPgetCutoffbound(scip) - lpobjval;
3807
3808 downgain = downgain/gap;
3809 upgain = upgain/gap;
3810
3811 score = 1.0 * nlowestlevelcutoffs + SCIPgetBranchScore(scip, branchvar, downgain, upgain);
3812
3813 return score;
3814}
3815
3816static
3818 SCIP* scip, /**< SCIP data structure */
3819 SCIP_VAR* branchvar, /**< variable to get the score for */
3820 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3821 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
3822 SCIP_Real lpobjval /**< objective value to get difference to as gain */
3823 )
3824{
3825 SCIP_Real score;
3826 SCIP_Real downgain = SCIPsumepsilon(scip);
3827 SCIP_Real upgain = SCIPsumepsilon(scip);
3828 SCIP_Real gap;
3829 int factor;
3830 SCIP_Real nlowestlevelcutoffs;
3831
3832 assert(downbranchingresult != NULL);
3833 assert(upbranchingresult != NULL);
3834
3835 assert(downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes > 0 || (downbranchingresult->cutoff && upbranchingresult->cutoff));
3836
3837 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(1 + downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes);
3838
3840 if( factor > SCIPgetNLPRows(scip) )
3841 factor = SCIPgetNLPRows(scip);
3842 factor = factor * factor;
3843
3844 /* the gain is the difference of the dualbound of a child and the reference objective value;
3845 * by bounding it by zero we are safe from numerical troubles
3846 */
3847 if( !downbranchingresult->cutoff )
3848 {
3849 downgain = MAX(downgain, downbranchingresult->dualbound - lpobjval);
3850 }
3851 if( !upbranchingresult->cutoff )
3852 {
3853 upgain = MAX(upgain, upbranchingresult->dualbound - lpobjval);
3854 }
3855
3856 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3857 * realistic gain for the infeasible child;
3858 * if both children are infeasible we just reset the initial zero values again
3859 */
3860 if( downbranchingresult->cutoff )
3861 {
3862 downgain = 2 * upgain;
3863 }
3864 if( upbranchingresult->cutoff )
3865 {
3866 upgain = 2 * downgain;
3867 }
3868
3869 gap = SCIPgetCutoffbound(scip) - lpobjval;
3870
3871 downgain = downgain/gap;
3872 upgain = upgain/gap;
3873
3874 score = factor * nlowestlevelcutoffs + SCIPgetBranchScore(scip, branchvar, downgain, upgain);
3875
3876 return score;
3877}
3878
3879/** scoring method that selects an actual scoring method based on the user configuration */
3880static
3882 SCIP* scip, /**< SCIP data structure */
3883 CONFIGURATION* config, /**< LAB configuration */
3884 SCIP_VAR* branchvar, /**< variable to get the score for */
3885 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
3886 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
3887 SCIP_Real lpobjval, /**< objective value to get difference to as gain */
3888 SCIP_Real baselpobjval /**< base objective value to get difference to as gain */
3889 )
3890{
3891 SCIP_Real score;
3892 char scoringfunction;
3893
3894 assert(scip != NULL);
3895 assert(config != NULL);
3896 assert(branchvar != NULL);
3897 assert(downbranchingresult != NULL);
3898 assert(upbranchingresult != NULL);
3899
3900 if( config->inscoring )
3901 scoringfunction = config->scoringscoringfunction;
3902 else if( SCIPgetProbingDepth(scip) > 0 )
3903 scoringfunction = config->deeperscoringfunction;
3904 else
3905 scoringfunction = config->scoringfunction;
3906
3907 switch( scoringfunction )
3908 {
3909 case 's':
3910 score = calculateScaledCutoffScore(downbranchingresult, upbranchingresult);
3911 break;
3912 case 'w':
3913 score = calculateWeightedCutoffScore(config, downbranchingresult, upbranchingresult);
3914 break;
3915 case 'f':
3916 score = calculateWeightedGain(scip, config, downbranchingresult, upbranchingresult, baselpobjval);
3917 break;
3918 case 'p':
3919 score = calculateScoreFromDeeperscore(scip, branchvar, downbranchingresult, upbranchingresult);
3920 break;
3921 case 'a':
3922 score = calculateScoreFromDeeperscoreAndCutoffs(scip, branchvar, downbranchingresult, upbranchingresult);
3923 break;
3924 case 'l':
3925 score = calculateScoreFromResult2(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3926 break;
3927 case 'c':
3928 score = calculateCutoffScore(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3929 break;
3930 case 'r':
3931 score = calculateRelCutoffScore(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3932 break;
3933 case 'x':
3934 score = calculateScoreFromResult(scip, branchvar, downbranchingresult, upbranchingresult, baselpobjval);
3935 break;
3936 default:
3937 assert(scoringfunction == 'd');
3938 score = calculateScoreFromResult(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3939 }
3940
3941 return score;
3942}
3943
3944/** calculates the score based on the pseudocosts of the given variable */
3945static
3947 SCIP* scip, /**< SCIP data structure */
3948 CANDIDATE* lpcand /**< candidate to get the score for */
3949 )
3950{
3951 SCIP_Real downpseudocost;
3952 SCIP_Real uppseudocost;
3953 SCIP_Real score;
3954
3955 assert(scip != NULL);
3956 assert(lpcand != NULL);
3957
3958 downpseudocost = SCIPgetVarPseudocostVal(scip, lpcand->branchvar, 0-lpcand->fracval);
3959 uppseudocost = SCIPgetVarPseudocostVal(scip, lpcand->branchvar, 1-lpcand->fracval);
3960
3961 score = SCIPgetBranchScore(scip, lpcand->branchvar, downpseudocost, uppseudocost);
3962
3963 return score;
3964}
3965
3966#ifdef SCIP_DEBUG
3967/** prints the names of the candidates of the given candidate list with their corresponding scores */
3968static
3969void printCandidateList(
3970 SCIP* scip, /**< SCIP data structure */
3971 CANDIDATELIST* candidatelist, /**< list to be printed */
3972 SCORECONTAINER* scorecontainer /**< container with all scores */
3973 )
3974{
3975 int i;
3976
3977 assert(scip != NULL);
3978 assert(candidatelist != NULL);
3979 assert(scorecontainer != NULL);
3980
3981 for( i = 0; i < candidatelist->ncandidates; i++ )
3982 {
3983 SCIP_VAR* var = candidatelist->candidates[i]->branchvar;
3984 SCIP_Real score = scorecontainer->scores[SCIPvarGetProbindex(var)];
3985
3986 assert(var != NULL);
3987
3988 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " Index %2i: Var %s Score %.9g\n", i, SCIPvarGetName(var), score);
3989 }
3990}
3991#endif
3992
3993/** sorts the best candidates (w.r.t. the score in the container) of the candidate list to the front of the list */
3994static
3996 SCIP* scip, /**< SCIP data structure */
3997 CANDIDATELIST* candidatelist, /**< candidates to be sorted */
3998 SCORECONTAINER* scorecontainer, /**< container with the scores for each candidate */
3999 int nbestcandidates /**< number of candidates that should be kept sorted at the start of the list*/
4000 )
4001{
4002 int i;
4003
4004 assert(scip != NULL);
4005 assert(candidatelist != NULL);
4006 assert(scorecontainer != NULL);
4007 assert(candidatelist->ncandidates > 0);
4008 assert(nbestcandidates <= candidatelist->ncandidates);
4009
4010 for( i = 1; i < candidatelist->ncandidates; i++ )
4011 {
4012 CANDIDATE* movecand = candidatelist->candidates[i];
4013 int moveprobindex;
4014 SCIP_Real movescore;
4015 int nsorted;
4016 int insertionindex;
4017 assert(movecand != NULL);
4018
4019 moveprobindex = SCIPvarGetProbindex(movecand->branchvar);
4020 movescore = scorecontainer->scores[moveprobindex];
4021
4022 /* the length of the sorted portion of the array, starting at 0 */
4023 nsorted = MIN(i, nbestcandidates);
4024
4025 insertionindex = findInsertionPoint(scip, scorecontainer, movescore, candidatelist->candidates, nsorted);
4026
4027 assert(insertionindex <= nsorted);
4028
4029 /* if no change has to be made, skip the reordering;
4030 * if the insertionindex lies after the sorted block, skip the reordering
4031 */
4032 if( insertionindex != i && insertionindex < nsorted )
4033 {
4034 int j;
4035 CANDIDATE* reordercand = movecand;
4036
4037 /* move everything inside the sorted block one place further */
4038 for( j = insertionindex; j < nsorted; j++ )
4039 {
4040 CANDIDATE* oldcand = candidatelist->candidates[j];
4041 assert(oldcand != NULL);
4042
4043 candidatelist->candidates[j] = reordercand;
4044 reordercand = oldcand;
4045 }
4046 /* the dropped element gets placed in the position of the actually moved element */
4047 candidatelist->candidates[i] = reordercand;
4048 }
4049 }
4050
4051#ifdef SCIP_DEBUG
4052 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "All %i candidates, with the first %i candidates sorted by their FSB score:"
4053 "\n", candidatelist->ncandidates, nbestcandidates);
4054 printCandidateList(scip, candidatelist, scorecontainer);
4055#endif
4056}
4057
4058/** checks whether the given candidates is reliable, so that its pseudocosts may be used */
4059static
4061 SCIP* scip, /**< SCIP data structure */
4062 SCIP_VAR* branchvar /**< var to check for reliability */
4063 )
4064{
4065 SCIP_Real size;
4066 SCIP_Real downsize;
4067 SCIP_Real upsize;
4068 SCIP_Real reliable = 5;
4069
4070 assert(scip != NULL);
4071 assert(branchvar != NULL);
4072
4075 size = MIN(downsize, upsize);
4076
4077 return size >= reliable;
4078}
4079
4080/** checks whether the current problem is feasible or cutoff */
4081static
4083 SCIP* scip /**< SCIP data structure */
4084 )
4085{
4086 assert(scip != NULL);
4087
4089}
4090
4091/** Ensures that the scores are present in the scorecontainer for each of the candidates to consider */
4092static
4094 SCIP* scip, /**< SCIP data structure */
4095 STATUS* status, /**< current status */
4096 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
4097 CONFIGURATION* config, /**< the configuration of the branching rule */
4098 SCIP_SOL* baselpsol, /**< base lp solution */
4099 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4100 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
4101 CANDIDATELIST* allcandidates, /**< list containing all candidates to consider */
4102 BRANCHINGDECISION* decision, /**< struct to store the final decision */
4103 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4104 LEVEL2DATA* level2data, /**< level 2 LP results data */
4105 SCIP_Real lpobjval /**< base LP objective value */
4106#ifdef SCIP_STATISTIC
4107 ,STATISTICS* statistics /**< general statistical data */
4108 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
4109#endif
4110 )
4111{
4112 int i;
4113 int nunscoredcandidates = 0;
4114 int* candidateunscored;
4115
4116 assert(scip != NULL);
4117 assert(config != NULL);
4118 assert(status != NULL);
4119 assert(allcandidates != NULL);
4120 assert(scorecontainer != NULL);
4121 assert(allcandidates->candidates != NULL || allcandidates->ncandidates == 0);
4122
4123 SCIP_CALL( SCIPallocBufferArray(scip, &candidateunscored, allcandidates->ncandidates) );
4124
4125 /* filter the candidates based on the presence of a score in the 'scorecontainer'. Only those without a score need a
4126 * new one.
4127 */
4128 for( i = 0; i < allcandidates->ncandidates; i++ )
4129 {
4130 CANDIDATE* lpcand = allcandidates->candidates[i];
4131 SCIP_VAR* branchvar = lpcand->branchvar;
4132 int probindex = SCIPvarGetProbindex(branchvar);
4133 SCIP_Real knownscore = scorecontainer->scores[probindex];
4134
4135 assert(lpcand != NULL);
4136 assert(branchvar != NULL);
4137
4138 if( SCIPisLT(scip, knownscore, 0.0) )
4139 {
4140 if( config->abbrevpseudo && isCandidateReliable(scip, branchvar) )
4141 {
4143 SCIP_CALL( scoreContainerSetScore(scip, scorecontainer, lpcand, score, 0.0, 0.0) );
4144 }
4145 else if( config->level2avgscore && SCIPgetProbingDepth(scip) > 0 )
4146 {
4147 assert(scorecontainer->nsetscores > 0);
4148 SCIP_CALL( scoreContainerSetScore(scip, scorecontainer, lpcand,
4149 scorecontainer->scoresum / scorecontainer->nsetscores, 0.0, 0.0) );
4150 }
4151 else if( config->level2zeroscore && SCIPgetProbingDepth(scip) > 0 )
4152 {
4153 assert(scorecontainer->nsetscores > 0);
4154 SCIP_CALL( scoreContainerSetScore(scip, scorecontainer, lpcand,
4155 -0.1, 0.0, 0.0) );
4156 }
4157 else
4158 {
4159 /* score is unknown and needs to be calculated */
4160 candidateunscored[nunscoredcandidates] = i;
4161 nunscoredcandidates++;
4162 }
4163 }
4164 }
4165
4166 if( nunscoredcandidates > 0 )
4167 {
4168 CANDIDATELIST* unscoredcandidates;
4169
4170 /* allocate the list of candidates without any score (gets updated further on) */
4171 SCIP_CALL( candidateListCreate(scip, &unscoredcandidates, nunscoredcandidates) );
4172
4173 /* move the unscored candidates to the temp list */
4174 for( i = 0; i < nunscoredcandidates; i++ )
4175 {
4176 int candindex = candidateunscored[i];
4177
4178 assert(allcandidates->candidates[candindex] != NULL);
4179
4180 unscoredcandidates->candidates[i] = allcandidates->candidates[candindex];
4181 }
4182
4183#ifdef SCIP_DEBUG
4184 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Of the given %i candidates, %i have no score: ",
4185 allcandidates->ncandidates, nunscoredcandidates);
4186 printCandidates(scip, SCIP_VERBLEVEL_HIGH, unscoredcandidates);
4187 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Calculating the FSB result to get a score for the remaining "
4188 "candidates.\n");
4189#endif
4190
4191 /* Calculate all remaining FSB scores and collect the scores in the container */;
4192#ifdef SCIP_STATISTIC
4193 SCIP_CALL( getFSBResult(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, unscoredcandidates,
4194 decision, scorecontainer, level2data, lpobjval, statistics, localstats) );
4195#else
4196 SCIP_CALL( getFSBResult(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, unscoredcandidates,
4197 decision, scorecontainer, level2data, lpobjval) );
4198#endif
4199
4200 /* move the now scored candidates back to the original list */
4201 for( i = 0; i < nunscoredcandidates; i++ )
4202 {
4203 assert(allcandidates->candidates[candidateunscored[i]] == unscoredcandidates->candidates[i]);
4204
4205 assert(unscoredcandidates->candidates[i] != NULL);
4206 unscoredcandidates->candidates[i] = NULL;
4207 }
4208
4209 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Calculated the scores for the remaining candidates\n");
4210
4211 SCIP_CALL( candidateListFree(scip, &unscoredcandidates) );
4212 }
4213
4214 /* reset the best sorted indices, as those are only valid on the FSB run already completed */
4216
4217 SCIPfreeBufferArray(scip, &candidateunscored);
4218
4219 return SCIP_OKAY;
4220}
4221
4222/** Get the candidates to temporarily branch on. In the LAB case this is the complete list of possible candidates. In the
4223 * ALAB case only the 'best' candidates are returned. */
4224static
4226 SCIP* scip, /**< SCIP data structure */
4227 STATUS* status, /**< current status */
4228 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
4229 CONFIGURATION* config, /**< the configuration of the branching rule */
4230 SCIP_SOL* baselpsol, /**< base lp solution */
4231 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4232 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
4233 CANDIDATELIST* candidatelist, /**< list of candidates to branch on */
4234 BRANCHINGDECISION* decision, /**< struct to store the final decision */
4235 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4236 LEVEL2DATA* level2data, /**< level 2 LP results data */
4237 SCIP_Real lpobjval /**< base LP objective value */
4238#ifdef SCIP_STATISTIC
4239 ,STATISTICS* statistics /**< general statistical data */
4240 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
4241#endif
4242 )
4243{
4244 assert(scip != NULL);
4245 assert(config != NULL);
4246 assert(status != NULL);
4247 assert(candidatelist != NULL);
4248 assert(SCIPinProbing(scip));
4249
4250 /* abbreviated LAB: only use the "best" candidates */
4251 if( config->abbreviated )
4252 {
4253 assert(scorecontainer != NULL);
4254
4255 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Getting the best (at most) %i of the given %i candidates: ",
4256 config->maxncands, candidatelist->ncandidates);
4257#ifdef SCIP_DEBUG
4258 printCandidates(scip, SCIP_VERBLEVEL_HIGH, candidatelist);
4259#endif
4260
4261 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%s", "Ensuring that all candidates have a score.\n");
4262#ifdef SCIP_STATISTIC
4263 SCIP_CALL( ensureScoresPresent(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4264 decision, scorecontainer, level2data, lpobjval, statistics, localstats) );
4265#else
4266 SCIP_CALL( ensureScoresPresent(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4267 decision, scorecontainer, level2data, lpobjval) );
4268#endif
4269
4270 /* if we didn't find any domreds or constraints during the FSB scoring, we branch on */
4271 if( isBranchFurther(status, SCIPgetProbingDepth(scip) == 0) )
4272 {
4273 int nusedcands;
4274 int i;
4275
4276 if( SCIPgetProbingDepth(scip) == 0 || config->maxndeepercands == 0 )
4277 nusedcands = MIN(config->maxncands, candidatelist->ncandidates);
4278 else
4279 nusedcands = MIN(config->maxndeepercands, candidatelist->ncandidates);
4280
4281 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%s", "Filter the candidates by their score.\n");
4282
4283 sortFirstCandidatesByScore(scip, candidatelist, scorecontainer, nusedcands);
4284
4285 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Best candidate according to FSB scores: <%s>\n",
4286 SCIPvarGetName(candidatelist->candidates[0]->branchvar));
4287
4288 if( config->worsefactor >= 0 )
4289 {
4290 for( i = 1; i < nusedcands; ++i )
4291 {
4292 if( scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)] >
4293 config->worsefactor * scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)] )
4294 break;
4295 }
4296 nusedcands = i;
4297 }
4298
4299 if( config->filterbymaxgain && SCIPgetProbingDepth(scip) == 0 )
4300 {
4301 SCIP_Real maxgain;
4302 SCIP_Real bestmaxgain = MAX(scorecontainer->downgains[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)],
4303 scorecontainer->upgains[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)]); /*lint !e666*/
4304
4305 if( bestmaxgain == 0.0 )
4306 nusedcands = 1;
4307 else
4308 {
4309 for( i = nusedcands - 1; i >= 1; --i )
4310 {
4311 maxgain = MAX(scorecontainer->downgains[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)],
4312 scorecontainer->upgains[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)]); /*lint !e666*/
4313
4314 if( SCIPisSumLE(scip, maxgain / bestmaxgain, 1.0) )
4315 {
4316 --nusedcands;
4317
4318 if( i < nusedcands )
4319 {
4320 CANDIDATE* tmp = candidatelist->candidates[i];
4321 candidatelist->candidates[i] = candidatelist->candidates[nusedcands];
4322 candidatelist->candidates[nusedcands] = tmp;
4323 }
4324 }
4325 }
4326 }
4327 }
4328
4329 if( SCIPgetProbingDepth(scip) > 0 && scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)] > -0.05)
4330 {
4331 for( i = 1; i < nusedcands; ++i )
4332 {
4333 if( scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)] < -0.05 )
4334 break;
4335 }
4336 nusedcands = i;
4337 }
4338
4339 SCIP_CALL( candidateListKeep(scip, candidatelist, nusedcands) );
4340 }
4341#ifdef SCIP_DEBUG
4342 else
4343 {
4344 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Strong Branching would have stopped.\n");
4345 }
4346#endif
4347
4349 status->cutoff = TRUE;
4350 }
4351 else
4352 {
4353 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Getting the branching candidates by selecting all candidates.\n");
4354 }
4355
4356 return SCIP_OKAY;
4357}
4358
4359/** Executes the general branching on a variable in a given direction (up/down) and repeats the algorithm from the new node */
4360static
4362 SCIP* scip, /**< SCIP data structure */
4363 STATUS* status, /**< current status */
4364 CONFIGURATION* config, /**< the configuration of the branching rule */
4365 SCIP_SOL* baselpsol, /**< the base lp solution */
4366 CANDIDATE* candidate, /**< candidate to branch on */
4367 SCIP_Real localbaselpsolval, /**< the objective value of the current temporary problem */
4368 SCIP_Real baselpobjval, /**< LP objective value of focus node (not probing) */
4369 int recursiondepth, /**< remaining recursion depth */
4370 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4371 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
4372 LEVEL2DATA* level2data, /**< level 2 LP results data */
4373 BRANCHINGRESULTDATA* branchingresult, /**< container to store the result of the branching in */
4374 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4375 SCIP_Bool downbranching /**< should we branch up or down in here? */
4376#ifdef SCIP_STATISTIC
4377 ,STATISTICS* statistics /**< general statistical data */
4378 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
4379#endif
4380 )
4381{
4382 int probingdepth;
4383 SCIP_VAR* branchvar;
4384 SCIP_Real branchvalfrac;
4385 SCIP_Real branchval;
4386 SCIP_Bool varisbinary;
4387 SCIP_Bool solvedlp = TRUE;
4388
4389 assert(scip != NULL);
4390 assert(status != NULL);
4391 assert(config != NULL);
4392 assert(candidate != NULL);
4393 assert(branchingresult != NULL);
4394
4395 branchvar = candidate->branchvar;
4396 branchvalfrac = candidate->fracval;
4397 branchval = candidate->branchval;
4398
4399 assert(branchvar != NULL);
4400
4401 probingdepth = SCIPgetProbingDepth(scip);
4402 varisbinary = SCIPvarIsBinary(branchvar);
4403
4404 if( binconsdata != NULL && varisbinary )
4405 {
4406 if( downbranching )
4407 {
4408 /* In case that the branch variable is binary, add the negated var to the list.
4409 * This list is used to generate a set packing constraint for cutoff branches which were reached by only using
4410 * binary variables.
4411 * DownBranching on a binary variable x means: x <= 0
4412 * When this cutoff occurs we have that: x >= 1 <=> 1-x <= 0
4413 */
4414 SCIP_VAR* negbranchvar;
4415
4416 SCIP_CALL( SCIPgetNegatedVar(scip, branchvar, &negbranchvar) );
4417
4418 assert(negbranchvar != NULL);
4419
4420 binaryVarListAppend(scip, binconsdata->binaryvars, negbranchvar);
4421 }
4422 else
4423 {
4424 /* In case that the branch variable is binary, add the var to the list.
4425 * This list is used to generate a set packing constraint for cutoff branches which were reached by only using
4426 * binary variables.
4427 * UpBranching on a binary variable x means: x >= 1
4428 * When this cutoff occurs we have that: x <= 0
4429 */
4430 binaryVarListAppend(scip, binconsdata->binaryvars, branchvar);
4431 }
4432 }
4433
4434 if( level2data != NULL )
4435 {
4436 SCIP_Real newbound = downbranching ? SCIPfeasFloor(scip, branchval) : SCIPfeasCeil(scip, branchval);
4437
4438 if( SCIPgetProbingDepth(scip) == 0 )
4439 {
4440 assert(SCIPvarGetProbindex(branchvar) >= 0);
4441 level2data->branchvar1 = (unsigned int) SCIPvarGetProbindex(branchvar);
4442 level2data->branchdir1 = !downbranching;
4443 level2data->branchval1 = newbound;
4444 }
4445 else
4446 {
4447 LEVEL2RESULT* result;
4448
4449 assert(SCIPgetProbingDepth(scip) == 1);
4450 assert(SCIPvarGetProbindex(branchvar) >= 0);
4451
4452 level2data->branchvar2 = (unsigned int) SCIPvarGetProbindex(branchvar);
4453 level2data->branchdir2 = !downbranching;
4454 level2data->branchval2 = newbound;
4455
4456 SCIP_CALL( level2dataGetResult(scip, level2data, &result) );
4457
4458 /* we already processed a similar level 2 node */
4459 if( result != NULL )
4460 {
4461 solvedlp = FALSE;
4462#ifdef SCIP_STATISTIC
4463 statistics->nduplicatelps[probingdepth]++;
4464#endif
4465 branchingresult->objval = result->lpobjval;
4466 branchingresult->dualbound = result->lpobjval;
4467 branchingresult->dualboundvalid = result->valid;
4468 branchingresult->cutoff = result->cutoff;
4469 branchingresult->niterations = 0;
4470
4471 if( !branchingresult->cutoff && branchingresult->dualboundvalid
4472 && SCIPisGE(scip, branchingresult->objval, SCIPgetCutoffbound(scip)) )
4473 branchingresult->cutoff = TRUE;
4474
4476 "Use old %s branching result on var <%s> with 'val > %g' and bounds [<%g>..<%g>]: objval <%.9g>, cutoff <%d> "
4477 "(the parent objval was <%.9g>)\n",
4478 downbranching ? "down" : "up", SCIPvarGetName(branchvar), branchval, SCIPvarGetLbLocal(branchvar),
4479 SCIPvarGetUbLocal(branchvar), branchingresult->objval, branchingresult->cutoff, localbaselpsolval);
4480 }
4481 }
4482 }
4483
4484 if( solvedlp )
4485 {
4486 SCIP_CALL( executeBranching(scip, config, downbranching, candidate, branchingresult, baselpsol, domainreductions,
4487 status) );
4488
4489 assert(SCIPgetProbingDepth(scip) == 1 || SCIPgetProbingDepth(scip) == 2);
4490
4491 if( level2data != NULL && SCIPgetProbingDepth(scip) == 2)
4492 {
4493 SCIP_Bool duplicate;
4494
4495 SCIP_CALL( level2dataStoreResult(scip, level2data, branchingresult->objval, branchingresult->cutoff, branchingresult->dualboundvalid, &duplicate) );
4496 assert(!duplicate);
4497 }
4498
4499#ifdef SCIP_STATISTIC
4500 statistics->nlpssolved[probingdepth]++;
4501 statistics->nlpiterations[probingdepth] += branchingresult->niterations;
4502
4503 if( config->inscoring )
4504 {
4505 statistics->nlpssolvedfsb[probingdepth]++;
4506 statistics->nlpiterationsfsb[probingdepth] += branchingresult->niterations;
4507 }
4508#endif
4509 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Solving the LP took %" SCIP_LONGINT_FORMAT " iterations (status %d).\n",
4510 branchingresult->niterations, SCIPgetLPSolstat(scip));
4511
4512#ifdef SCIP_DEBUG
4513 if( status->lperror )
4514 {
4515 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The LP could not be solved.\n");
4516 }
4517 else if( branchingresult->cutoff )
4518 {
4519 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The solved LP was infeasible and as such is cutoff\n");
4520 }
4521 else
4522 {
4523 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The solved LP was feasible and has an objval <%.9g> (the parent objval was "
4524 "<%.9g>)\n", branchingresult->objval, localbaselpsolval);
4525 }
4526#endif
4527 }
4528
4529 if( !branchingresult->cutoff && !status->lperror && !status->limitreached )
4530 {
4531 SCIP_Real localgain;
4532
4533 localgain = MAX(0, branchingresult->objval - localbaselpsolval);
4534
4535 /* update pseudo costs */
4536 if( downbranching )
4537 {
4538 SCIP_CALL( SCIPupdateVarPseudocost(scip, branchvar, 0.0 - branchvalfrac, localgain, 1.0) );
4539 }
4540 else
4541 {
4542 SCIP_CALL( SCIPupdateVarPseudocost(scip, branchvar, 1.0 - branchvalfrac, localgain, 1.0) );
4543 }
4544 }
4545
4546 if( solvedlp && !branchingresult->cutoff && !status->lperror && !status->limitreached )
4547 {
4548 /* store the warm start information in the candidate, so that it can be reused in a later branching */
4549 if( config->reusebasis && config->inscoring )
4550 {
4551 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Storing warm start information for %s branching on var <%s>\n",
4552 downbranching ? "down" : "up", SCIPvarGetName(branchvar));
4553
4554 SCIP_CALL( candidateStoreWarmStartInfo(scip, candidate, downbranching) );
4555 }
4556
4557 if( recursiondepth > 1 && !config->inscoring )
4558 {
4559 CANDIDATELIST* candidatelist;
4560
4562 assert(candidatelist != NULL);
4563
4564 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%sbranching has <%i> candidates.\n", downbranching ? "Down" : "Up",
4565 candidatelist->ncandidates);
4566
4567 if( candidatelist->ncandidates > 0 )
4568 {
4569 BRANCHINGDECISION* deeperdecision;
4570 STATUS* deeperstatus;
4571 PERSISTENTDATA* deeperpersistent = NULL;
4572 SCIP_Real deeperlpobjval = branchingresult->objval;
4573#ifdef SCIP_STATISTIC
4574 LOCALSTATISTICS* deeperlocalstats;
4575
4576 SCIP_CALL( localStatisticsAllocate(scip, &deeperlocalstats) );
4577#endif
4578 SCIP_CALL( statusCreate(scip, &deeperstatus) );
4579
4580 SCIP_CALL( branchingDecisionCreate(scip, &deeperdecision) );
4581
4582#ifdef SCIP_STATISTIC
4583 SCIP_CALL( filterCandidates(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4584 deeperdecision, scorecontainer, level2data, deeperlpobjval,
4585 statistics, localstats) );
4586#else
4587 SCIP_CALL( filterCandidates(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4588 deeperdecision, scorecontainer, level2data, deeperlpobjval) );
4589#endif
4590 if( deeperstatus->lperror )
4591 {
4592 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "ignoring lperror in filtering call...\n");
4593 deeperstatus->lperror = FALSE;
4594 }
4595 if( deeperstatus->cutoff )
4596 {
4597 branchingresult->ndeepestnodes += 2;
4598 branchingresult->ndeepestcutoffs += 2;
4599 }
4600
4601 /* the status may have changed because of FSB to get the best candidates */
4602 if( isBranchFurther(deeperstatus, FALSE) )
4603 {
4604 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Now the objval is <%.9g>\n", branchingresult->objval);
4605
4606#ifdef SCIP_STATISTIC
4607 deeperlocalstats->ncutoffproofnodes = 0;
4608 SCIP_CALL( selectVarRecursive(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions,
4609 binconsdata, candidatelist, deeperdecision, scorecontainer, level2data, recursiondepth - 1,
4610 deeperlpobjval, baselpobjval, &branchingresult->niterations, &branchingresult->ndeepestcutoffs,
4611 &branchingresult->bestgain, &branchingresult->totalgains, &branchingresult->ntotalgains,
4612 &branchingresult->ndeepestnodes,
4613 statistics, deeperlocalstats, NULL, NULL) );
4614#else
4615 SCIP_CALL( selectVarRecursive(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions,
4616 binconsdata, candidatelist, deeperdecision, scorecontainer, level2data, recursiondepth - 1,
4617 deeperlpobjval, baselpobjval, &branchingresult->niterations, &branchingresult->ndeepestcutoffs,
4618 &branchingresult->bestgain, &branchingresult->totalgains, &branchingresult->ntotalgains,
4619 &branchingresult->ndeepestnodes) );
4620#endif
4621
4622 assert(deeperstatus->cutoff || deeperstatus->domred || deeperstatus->lperror
4623 || branchingresult->ndeepestnodes == 8
4624 || branchingresult->ndeepestnodes == 2 * candidatelist->ncandidates
4625 || SCIPisStopped(scip));
4626
4627 /* the proved dual bound of the deeper branching cannot be less than the current dual bound, as every deeper
4628 * node has more/tighter constraints and as such cannot be better than the base LP. */
4629 assert(SCIPisGE(scip, deeperdecision->proveddb, branchingresult->dualbound));
4630 branchingresult->dualbound = deeperdecision->proveddb;
4631 branchingresult->deeperscore = deeperdecision->score;
4632 branchingresult->dualboundvalid = TRUE;
4633 }
4634#ifdef SCIP_STATISTIC
4635 else
4636 {
4637 assert(SCIPgetProbingDepth(scip) == probingdepth + 1);
4638
4639 statistics->stopafterfsb[probingdepth+1]++;
4640
4641 if( deeperstatus->cutoff )
4642 {
4643 statistics->cutoffafterfsb[probingdepth+1]++;
4644 }
4645 else if( deeperstatus->domred )
4646 {
4647 statistics->domredafterfsb[probingdepth+1]++;
4648 }
4649 }
4650#endif
4651 /* deeperstatus->cutoff is TRUE, if any up/down child pair of the up child were cutoff */
4652 if( deeperstatus->cutoff )
4653 {
4654 branchingresult->cutoff = TRUE;
4655#ifdef SCIP_STATISTIC
4656 localstats->ncutoffproofnodes += deeperlocalstats->ncutoffproofnodes;
4657#endif
4658 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Both deeper children were cutoff, so the %s branch is "
4659 "cutoff\n", downbranching ? "down" : "up");
4660 }
4661
4662 branchingDecisionFree(scip, &deeperdecision);
4663 statusFree(scip, &deeperstatus);
4664#ifdef SCIP_STATISTIC
4665 localStatisticsFree(scip, &deeperlocalstats);
4666#endif
4667 }
4668 else
4669 {
4670 branchingresult->deeperscore = (branchingresult->dualbound - baselpobjval) * (branchingresult->dualbound - baselpobjval) * 10;
4671 }
4672 SCIP_CALL( candidateListFree(scip, &candidatelist) );
4673 }
4674 }
4675
4676 if( recursiondepth == 1 && !config->inscoring )
4677 {
4678 branchingresult->ndeepestnodes++;
4679 /* this is a cutoff on the lowest tree level */
4680 if( branchingresult->cutoff )
4681 {
4682 branchingresult->ndeepestcutoffs++;
4683 }
4684 }
4685
4686 if( binconsdata != NULL && varisbinary )
4687 {
4688 /* the current branching child is infeasible and we only branched on binary variables in lookahead branching */
4689 if( solvedlp && branchingresult->cutoff && !status->lperror && SCIPallColsInLP(scip)
4690 && binconsdata->binaryvars->nbinaryvars == (probingdepth + 1) )
4691 {
4692#ifdef SCIP_STATISTIC
4693 SCIP_CALL( addBinaryConstraint(scip, config, binconsdata, baselpsol, statistics) );
4694#else
4695 SCIP_CALL( addBinaryConstraint(scip, config, binconsdata, baselpsol) );
4696#endif
4697 }
4698
4699 binaryVarListDrop(binconsdata->binaryvars);
4700 }
4701
4702 /* reset the probing depth to undo the previous branching */
4703 SCIP_CALL( SCIPbacktrackProbing(scip, probingdepth) );
4704
4705 return SCIP_OKAY;
4706}
4707
4708/** branches recursively on all given candidates */
4709static
4711 SCIP* scip, /**< SCIP data structure */
4712 STATUS* status, /**< current status */
4713 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
4714 CONFIGURATION* config, /**< the configuration of the branching rule */
4715 SCIP_SOL* baselpsol, /**< base lp solution */
4716 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4717 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
4718 CANDIDATELIST* candidatelist, /**< list of candidates to branch on */
4719 BRANCHINGDECISION* decision, /**< struct to store the final decision */
4720 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4721 LEVEL2DATA* level2data, /**< level 2 LP results data */
4722 int recursiondepth, /**< remaining recursion depth */
4723 SCIP_Real lpobjval, /**< LP objective value of current probing node*/
4724 SCIP_Real baselpobjval, /**< LP objective value of focus node (not probing) */
4725 SCIP_Longint* niterations, /**< pointer to store the total number of iterations for this variable; or NULL*/
4726 int* ndeepestcutoffs, /**< pointer to store the total number of cutoffs on the deepest level; or NULL */
4727 SCIP_Real* bestgain, /**< pointer to store the best gain found with these candidates; or NULL */
4728 SCIP_Real* totalgains, /**< pointer to store the sum over all gains that are valid in both children;
4729 * or NULL, if bestgain == NULL */
4730 int* ntotalgains, /**< pointer to store the number of gains summed in totalgains;
4731 * or NULL, if bestgain == NULL */
4732 int* ndeepestnodes /**< pointer to store the number of nodes processed in the deepest level */
4733#ifdef SCIP_STATISTIC
4734 ,STATISTICS* statistics /**< general statistical data */
4735 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
4736 ,SCIP_Real* firstscoreptr /**< pointer to store score of first candidate, or NULL */
4737 ,SCIP_Real* bestscoreptr /**< pointer to store best score, or NULL */
4738#endif
4739 )
4740{
4741 BRANCHINGRESULTDATA* downbranchingresult = NULL;
4742 BRANCHINGRESULTDATA* upbranchingresult = NULL;
4743 BRANCHINGRESULTDATA* bestdownbranchingresult = NULL;
4744 BRANCHINGRESULTDATA* bestupbranchingresult = NULL;
4745 SCIP_LPI* lpi;
4746 SCIP_Real bestscore = -SCIPinfinity(scip);
4747 SCIP_Real bestscorelowerbound;
4748 SCIP_Real bestscoreupperbound;
4749 SCIP_Real bestscoringlpobjval = -SCIPinfinity(scip);
4750 int start = 0;
4751 int i;
4752 int c;
4753 int nlpcands;
4754 int probingdepth;
4755 SCIP_Bool stopafterinfeasible = FALSE;
4756
4757 assert(scip != NULL);
4758 assert(status != NULL);
4759 assert(config != NULL);
4760 assert(!config->usedomainreduction || domainreductions != NULL);
4761 assert(candidatelist != NULL);
4762 assert(candidatelist->ncandidates > 0);
4763 assert(decision != NULL);
4764 assert(recursiondepth >= 1);
4765#ifdef SCIP_STATISTIC
4766 assert(statistics != NULL);
4767
4768 if( firstscoreptr != NULL )
4769 *firstscoreptr = -1.0;
4770 if( bestscoreptr != NULL )
4771 *bestscoreptr = -1.0;
4772#endif
4773
4774 nlpcands = candidatelist->ncandidates;
4775 probingdepth = SCIPgetProbingDepth(scip);
4776 assert(probingdepth >= 0 && probingdepth < config->recursiondepth);
4777
4778 if( persistent != NULL && (!config->abbreviated || config->inscoring) && probingdepth == 0 )
4779 start = persistent->restartindex;
4780
4781 /* init default decision */
4782 decision->branchvar = candidatelist->candidates[0]->branchvar;
4783 decision->branchval = candidatelist->candidates[0]->branchval;
4784 decision->downdb = lpobjval;
4785 decision->downdbvalid = FALSE;
4786 decision->updb = lpobjval;
4787 decision->updbvalid = FALSE;
4788 decision->proveddb = lpobjval;
4789 decision->score = 0.0;
4790
4791 bestscorelowerbound = SCIPvarGetLbLocal(decision->branchvar);
4792 bestscoreupperbound = SCIPvarGetUbLocal(decision->branchvar);
4793
4794 SCIP_CALL( branchingResultDataCreate(scip, &downbranchingresult) );
4795 SCIP_CALL( branchingResultDataCreate(scip, &upbranchingresult) );
4796
4797 SCIP_CALL( branchingResultDataCreate(scip, &bestdownbranchingresult) );
4798 SCIP_CALL( branchingResultDataCreate(scip, &bestupbranchingresult) );
4799
4800 assert(downbranchingresult != NULL);
4801 assert(upbranchingresult != NULL);
4802
4803 if( config->inscoring )
4804 {
4805 SCIP_CALL( SCIPgetBoolParam(scip, "branching/forceallchildren", &stopafterinfeasible) );
4806 stopafterinfeasible = !stopafterinfeasible;
4807 }
4808
4809 SCIP_CALL( SCIPgetLPI(scip, &lpi) );
4810
4811#ifdef SCIP_DEBUG
4812 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Started selectVarRecursive with <%i> candidates: ", nlpcands);
4813 printCandidates(scip, SCIP_VERBLEVEL_HIGH, candidatelist);
4814#endif
4815
4816 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Starting loop from index %d\n", start);
4817
4818 /* iterate over all current branching candidates and evaluate their two potential child nodes by:
4819 * - potentially applying domain propagation at each node before
4820 * - solving the LP at the nodes to obtain a dual bound
4821 * - potentially evaluating branching candidates at the potential child node again by applying this method recursively
4822 *
4823 * some improvements of the general scheme:
4824 * - results obtained for a candidate in a previous lookahead branching call at this node may be re-used
4825 * - while i counts the number of candidates evaluated in this call, we do not always start at the front
4826 * of the candidate array, but rather store at which index we stopped last time (e.g., because a domain reduction was
4827 * found and applied) and start from that index next time. Even though the set of branching candidates is probably different
4828 * it is often reasonably close and we avoid evaluating the same variables again and again.
4829 */
4830 for( i = 0, c = start;
4831 isBranchFurtherLoopDecrement(status, &c) && i < nlpcands && !SCIPisStopped(scip); i++, c++)
4832 {
4833 DOMAINREDUCTIONS* downdomainreductions = NULL;
4834 DOMAINREDUCTIONS* updomainreductions = NULL;
4835 SCIP_Bool useoldbranching = FALSE;
4836 SCIP_Real oldlpobjval = -SCIPinfinity(scip);
4837 CANDIDATE* candidate;
4838 SCIP_VAR* branchvar;
4839 SCIP_Real branchval;
4840 SCIP_Real branchlb;
4841 SCIP_Real branchub;
4842
4843 c = c % nlpcands;
4844
4845 candidate = candidatelist->candidates[c];
4846
4847 assert(candidate != NULL);
4848
4849 branchvar = candidate->branchvar;
4850 branchval = candidate->branchval;
4851
4852 assert(branchvar != NULL);
4853
4854 branchlb = SCIPvarGetLbLocal(branchvar);
4855 branchub = SCIPvarGetUbLocal(branchvar);
4856
4857 if( SCIPisEQ(scip, branchlb, branchub) )
4858 {
4859 /* if both bounds are equal the variable is fixed and we cannot branch
4860 * this may happen if domain propagation on other candidates finds better bounds for the current candidate
4861 */
4862 status->domred = TRUE;
4863#ifdef SCIP_STATISTIC
4864 statistics->npropdomred[probingdepth]++;
4865#endif
4866 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Domain Propagation changed the bounds of a branching candidate."
4867 "\n");
4868 continue;
4869 }
4870
4871 /* @todo apply already found domainreductions for this candidate? */
4872
4873#ifdef SCIP_STATISTIC
4874 /* Reset the cutoffproofnodes, as the number of proof nodes from previous branching vars (which where not
4875 * cutoff, as we didn't break the loop) is not relevant for the min total sum of proof nodes.
4876 */
4877 localstats->ncutoffproofnodes = 0;
4878#endif
4879
4880 branchingResultDataInit(scip, downbranchingresult);
4881 branchingResultDataInit(scip, upbranchingresult);
4882
4883 /* use old lookahead branching result, if last call on this variable is not too long ago */
4884 if( persistent != NULL && (config->inscoring || probingdepth == 0) && isUseOldBranching(scip, persistent, config, branchvar) )
4885 {
4886 SCIP_CALL( getOldBranching(scip, persistent, config, branchvar, downbranchingresult, upbranchingresult,
4887 &oldlpobjval) );
4888 useoldbranching = TRUE;
4889#ifdef SCIP_STATISTIC
4890 if( config->inscoring )
4891 statistics->noldbranchusedfsb[probingdepth]++;
4892 else
4893 statistics->noldbranchused[probingdepth]++;
4894#endif
4895 }
4896 else
4897 {
4898 SCIP_Bool down;
4899 int k;
4900
4901 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, "Started branching on var <%s> with val <%g> and bounds "
4902 "[<%g>..<%g>]\n", SCIPvarGetName(branchvar), branchval, SCIPvarGetLbLocal(branchvar),
4903 SCIPvarGetUbLocal(branchvar));
4904
4905 if( config->usedomainreduction )
4906 {
4907 SCIP_CALL( domainReductionsCreate(scip, &downdomainreductions) );
4908 SCIP_CALL( domainReductionsCreate(scip, &updomainreductions) );
4909 }
4910
4911 down = SCIPisStrongbranchDownFirst(scip, branchvar);
4912
4913 /* @todo break if result is infeasible (probably only in first layer)? */
4914 for( k = 0; k < 2; ++k )
4915 {
4916 DOMAINREDUCTIONS* localdomainreductions;
4917 BRANCHINGRESULTDATA* localbranchingresult;
4918 BRANCHINGRESULTDATA* otherbranchingresult;
4919
4920 localdomainreductions = down ? downdomainreductions : updomainreductions;
4921 localbranchingresult = down ? downbranchingresult : upbranchingresult;
4922 otherbranchingresult = down ? upbranchingresult : downbranchingresult;
4923
4924#ifdef SCIP_STATISTIC
4925 SCIP_CALL( executeBranchingRecursive(scip, status, config, baselpsol, candidate, lpobjval, baselpobjval,
4926 recursiondepth, localdomainreductions, binconsdata, level2data, localbranchingresult, scorecontainer,
4927 down, statistics, localstats) );
4928#else
4929
4930 SCIP_CALL( executeBranchingRecursive(scip, status, config, baselpsol, candidate, lpobjval, baselpobjval,
4931 recursiondepth, localdomainreductions, binconsdata, level2data, localbranchingresult, scorecontainer,
4932 down) );
4933#endif
4934
4935 /* check whether a new solutions rendered the previous child infeasible */
4936 if( SCIPallColsInLP(scip) && !otherbranchingresult->cutoff )
4937 {
4938 if( k == 1 && SCIPisGE(scip, otherbranchingresult->dualbound, SCIPgetCutoffbound(scip)) )
4939 {
4940 otherbranchingresult->cutoff = TRUE;
4942 "The %s branching changed the cutoffbound and rendered the %s branching result infeasible.\n",
4943 down ? "down" : "up", down ? "up" : "down");
4944 }
4945 }
4946 if( stopafterinfeasible && k == 0 && localbranchingresult->cutoff )
4947 break;
4948
4949 /* the second iteration of the loop should branch in the other direction */
4950 down = !down;
4951 }
4952
4953 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, "-> down=%.9g (gain=%.9g, valid=%u, inf=%u), up=%.9g "
4954 "(gain=%.9g, valid=%u, inf=%u)\n", downbranchingresult->dualbound,
4955 downbranchingresult->dualbound - lpobjval, downbranchingresult->dualboundvalid,
4956 downbranchingresult->cutoff, upbranchingresult->dualbound, upbranchingresult->dualbound - lpobjval,
4957 upbranchingresult->dualboundvalid, upbranchingresult->cutoff);
4958
4959 if( niterations != NULL )
4960 *niterations += downbranchingresult->niterations + upbranchingresult->niterations;
4961
4962 /* store results of branching call */
4963 if( persistent != NULL && !upbranchingresult->cutoff && !downbranchingresult->cutoff && (config->inscoring || probingdepth == 0) )
4964 {
4965 SCIP_CALL( updateOldBranching(scip, persistent, config, branchvar, branchval, downbranchingresult,
4966 upbranchingresult, lpobjval) );
4967 }
4968 }
4969
4970 if( ndeepestcutoffs != NULL )
4971 *ndeepestcutoffs += downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs;
4972
4973 if( ndeepestnodes != NULL )
4974 *ndeepestnodes += downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes;
4975
4976 if( !status->lperror && !status->limitreached )
4977 {
4978 SCIP_Real scoringlpobjval = useoldbranching ? oldlpobjval : lpobjval;
4979 SCIP_Real score = calculateScore(scip, config, branchvar, downbranchingresult, upbranchingresult,
4980 scoringlpobjval, baselpobjval);
4981
4982#ifdef SCIP_STATISTIC
4983 if( i == 0 && firstscoreptr != NULL )
4984 *firstscoreptr = score;
4985#endif
4986
4987 if( bestgain != NULL && !config->inscoring && SCIPgetProbingDepth(scip) == 1 && !useoldbranching )
4988 {
4989 assert(totalgains != NULL);
4990 assert(ntotalgains != NULL);
4991
4992 *bestgain = MAX(*bestgain, score);
4993
4994 if( !downbranchingresult->cutoff && !upbranchingresult->cutoff )
4995 {
4996 (*totalgains) += score;
4997 (*ntotalgains)++;
4998 }
4999 }
5000
5001 /* both child nodes are infeasible -> the current node is infeasible */
5002 if( SCIPallColsInLP(scip) && upbranchingresult->cutoff && downbranchingresult->cutoff )
5003 {
5004 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in both directions\n",
5005 SCIPvarGetName(branchvar));
5006
5007 /* this cutoff may be transferred to a higher level as a domain reduction/valid bound */
5008 status->cutoff = TRUE;
5009#ifdef SCIP_STATISTIC
5010 statistics->nfullcutoffs[probingdepth]++;
5011 localstats->ncutoffproofnodes += 2;
5012#endif
5013 }
5014 /* up child is infeasible */
5015 else if( SCIPallColsInLP(scip) && upbranchingresult->cutoff )
5016 {
5017 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in upward branch\n",
5018 SCIPvarGetName(branchvar));
5019
5020 /* apply down branching bound change at current node if we proved that this node is really infeasible and
5021 * parameters are set accordingly
5022 */
5023 if( config->usedomainreduction && !useoldbranching )
5024 {
5025#ifdef SCIP_STATISTIC
5026 assert(localstats->ncutoffproofnodes == 0 || localstats->ncutoffproofnodes == 2);
5027 addUpperBound(scip, branchvar, branchval, baselpsol, TRUE, domainreductions,
5028 2 + localstats->ncutoffproofnodes, TRUE);
5029#else
5030 addUpperBound(scip, branchvar, branchval, baselpsol, TRUE, domainreductions);
5031#endif
5032 }
5033
5034 /* the proved bound is given by the bound of the down child alone */
5035 if( downbranchingresult->dualboundvalid )
5036 {
5037 decision->proveddb = MAX(decision->proveddb, downbranchingresult->dualbound);
5038 }
5039
5040#ifdef SCIP_STATISTIC
5041 statistics->nsinglecutoffs[probingdepth]++;
5042#endif
5043 }
5044 /* down child is infeasible */
5045 else if( SCIPallColsInLP(scip) && downbranchingresult->cutoff )
5046 {
5047 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in downward branch\n",
5048 SCIPvarGetName(branchvar));
5049
5050 /* apply up branching bound change at current node if we proved that this node is really infeasible and
5051 * parameters are set accordingly
5052 */
5053 if( config->usedomainreduction && !useoldbranching )
5054 {
5055#ifdef SCIP_STATISTIC
5056 assert(localstats->ncutoffproofnodes == 0 || localstats->ncutoffproofnodes == 2);
5057 addLowerBound(scip, branchvar, branchval, baselpsol, TRUE, domainreductions,
5058 2 + localstats->ncutoffproofnodes, TRUE);
5059#else
5060 addLowerBound(scip, branchvar, branchval, baselpsol, TRUE, domainreductions);
5061#endif
5062 }
5063
5064 /* the proved bound is given by the bound of the up child alone */
5065 if( upbranchingresult->dualboundvalid )
5066 {
5067 decision->proveddb = MAX(decision->proveddb, upbranchingresult->dualbound);
5068 }
5069
5070#ifdef SCIP_STATISTIC
5071 statistics->nsinglecutoffs[probingdepth]++;
5072#endif
5073 }
5074 /* "normal" case: both child nodes are LP-feasible */
5075 else
5076 {
5077 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Neither branch is cut off and no limit reached.\n");
5078
5079 /* the proved dual bound is the minimum of the dual bounds of both child nodes */
5080 if( upbranchingresult->dualboundvalid && downbranchingresult->dualboundvalid )
5081 {
5082 decision->proveddb = MAX(decision->proveddb, MIN(upbranchingresult->dualbound,
5083 downbranchingresult->dualbound));
5084 }
5085 }
5086
5087 /* merge domain changes from the two child nodes */
5088 if( updomainreductions != NULL && config->usedomainreduction && SCIPallColsInLP(scip) )
5089 {
5090 int maxstoredomreds = INT_MAX;
5091
5092 assert(downdomainreductions != NULL);
5093
5094 if( config->enforcemaxdomreds && config->maxnviolateddomreds > 0)
5095 maxstoredomreds = config->maxnviolateddomreds;
5096
5097 if( !upbranchingresult->cutoff && !downbranchingresult->cutoff && config->mergedomainreductions )
5098 applyDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, downdomainreductions,
5099 updomainreductions);
5100 else if( upbranchingresult->cutoff && !downbranchingresult->cutoff )
5101 applySingleDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, downdomainreductions);
5102 else if( downbranchingresult->cutoff && !upbranchingresult->cutoff )
5103 applySingleDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, updomainreductions);
5104 }
5105
5106 if( config->updatebranchingresults && bestscore > -1.0 &&
5107 (SCIPisGT(scip, decision->proveddb, bestdownbranchingresult->dualbound)
5108 || SCIPisGT(scip, decision->proveddb, bestupbranchingresult->dualbound)) )
5109 {
5110 SCIP_Real newscore;
5111
5112 bestdownbranchingresult->dualbound = MAX(bestdownbranchingresult->dualbound, decision->proveddb);
5113 bestupbranchingresult->dualbound = MAX(bestupbranchingresult->dualbound, decision->proveddb);
5114
5115 newscore = calculateScore(scip, config, decision->branchvar, bestdownbranchingresult, bestupbranchingresult,
5116 bestscoringlpobjval, baselpobjval);
5117
5118 if( newscore > bestscore )
5119 {
5120 bestscore = newscore;
5121
5122#ifdef SCIP_STATISTIC
5123 if( bestscoreptr != NULL )
5124 *bestscoreptr = newscore;
5125#endif
5126 decision->score = newscore;
5127 decision->downdb = bestdownbranchingresult->dualbound;
5128 decision->updb = bestupbranchingresult->dualbound;
5129 }
5130 }
5131
5132 /* the current candidate variable has a better score than the best candidate investigated so far */
5133 if( SCIPisRelGT(scip, score, bestscore) )
5134 {
5135 int nvars = SCIPgetNVars(scip);
5136
5137 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Old best var <%s> with bounds [<%g>..<%g>] and score %.9g\n",
5138 SCIPvarGetName(decision->branchvar), bestscorelowerbound, bestscoreupperbound, bestscore);
5139
5140 bestscore = score;
5141
5142#ifdef SCIP_STATISTIC
5143 if( bestscoreptr != NULL )
5144 *bestscoreptr = score;
5145#endif
5146 decision->branchvar = candidate->branchvar;
5147 decision->branchval = candidate->branchval;
5148 decision->downdb = downbranchingresult->dualbound;
5149 decision->downdbvalid = downbranchingresult->dualboundvalid;
5150 decision->updb = upbranchingresult->dualbound;
5151 decision->updbvalid = upbranchingresult->dualboundvalid;
5152 decision->score = score;
5153
5154 branchingResultDataCopy(downbranchingresult, bestdownbranchingresult);
5155 branchingResultDataCopy(upbranchingresult, bestupbranchingresult);
5156
5157 /* store domain reductions found at the child nodes */
5158 if( !config->inscoring && updomainreductions != NULL )
5159 {
5160 assert(downdomainreductions != NULL);
5161
5163
5164 BMScopyMemoryArray(decision->uplowerbounds, updomainreductions->lowerbounds, nvars);
5165 BMScopyMemoryArray(decision->upupperbounds, updomainreductions->upperbounds, nvars);
5166 BMScopyMemoryArray(decision->downlowerbounds, downdomainreductions->lowerbounds, nvars);
5167 BMScopyMemoryArray(decision->downupperbounds, downdomainreductions->upperbounds, nvars);
5168 decision->boundsvalid = TRUE;
5169 }
5170 else
5171 {
5172 decision->boundsvalid = FALSE;
5173 }
5174
5175 bestscorelowerbound = branchlb;
5176 bestscoreupperbound = branchub;
5177 bestscoringlpobjval = scoringlpobjval;
5178 assert(!SCIPisEQ(scip, bestscorelowerbound, bestscoreupperbound));
5179
5180 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "New best var <%s> with bounds [<%g>..<%g>] and score %.9g\n",
5181 SCIPvarGetName(decision->branchvar), bestscorelowerbound, bestscoreupperbound, bestscore);
5182 }
5183
5184#ifdef SCIP_DEBUG
5185 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> cand %d/%d var <%s> (solval=%.9g, downgain=%.9g->%.9g, upgain=%.9g->%.9g,"
5186 " score=%.9g) -- best: <%s> (%.9g)\n", c, nlpcands, SCIPvarGetName(branchvar), branchval,
5187 MAX(downbranchingresult->objval - scoringlpobjval, 0), MAX(downbranchingresult->dualbound - scoringlpobjval, 0),
5188 MAX(upbranchingresult->objval - scoringlpobjval, 0), MAX(upbranchingresult->dualbound - scoringlpobjval, 0),
5189 score, SCIPvarGetName(decision->branchvar), bestscore);
5190#endif
5191
5192 if( config->inscoring )
5193 {
5194 assert(scorecontainer != NULL);
5195 /* only for abbreviated lookahead branching: we are in the FSB filtering step and store the score for this
5196 * variable and the warm starting basis to reuse it in the subsequent lookahead evaluation of the best
5197 * candidates
5198 */
5199 SCIP_CALL( scoreContainerSetScore(scip, scorecontainer, candidate, score,
5200 downbranchingresult->dualbound - scoringlpobjval, upbranchingresult->dualbound - scoringlpobjval) );
5201 }
5202
5203 if( probingdepth == 0 && (binconsdata != NULL || domainreductions != NULL) && !useoldbranching
5204 && (config->maxnviolatedcons >= 0 || config->maxnviolatedbincons >= 0 || config->maxnviolateddomreds >= 0 ) )
5205 {
5206 int nbincons = 0;
5207 int ndomreds = 0;
5208
5209 if( binconsdata != NULL )
5210 {
5211 assert(binconsdata != NULL); /* for lint */
5212 nbincons = binconsdata->conslist->nviolatedcons;
5213 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %d binary constraints (%d violated by the LP solution)\n",
5214 binconsdata->conslist->nelements, nbincons);
5215
5216 if( (config->maxnviolatedbincons > 0) && (nbincons >= config->maxnviolatedbincons) )
5217 {
5218 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated binary constraints <%i> is "
5219 "exceeded.\n", config->maxnviolatedbincons);
5220 status->maxnconsreached = TRUE;
5221 }
5222 }
5223
5224 if( domainreductions != NULL )
5225 {
5226 assert(domainreductions != NULL); /* for lint */
5227 ndomreds = domainreductions->nviolatedvars;
5228 if( config->prefersimplebounds && ndomreds > domainreductions->nsimplebounds )
5229 ndomreds = domainreductions->nsimplebounds;
5230
5231 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %d bound changes (%d violated by the LP solution)\n",
5232 domainreductions->nchangedvars, ndomreds);
5233
5234 if( (config->maxnviolateddomreds > 0) && (ndomreds >= config->maxnviolateddomreds) )
5235 {
5236 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated bound changes <%i> is "
5237 "exceeded.\n", config->maxnviolateddomreds);
5238 status->maxnconsreached = TRUE;
5239 }
5240 }
5241
5242 if( config->maxnviolatedcons > 0 && (nbincons + ndomreds >= config->maxnviolatedcons) )
5243 {
5244 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated binary constraints and bound "
5245 "changes <%d> is exceeded.\n", config->maxnviolatedcons);
5246 status->maxnconsreached = TRUE;
5247 }
5248 }
5249 }
5250
5251 if( !(status->domred && decision->branchvar == candidate->branchvar) && areBoundsChanged(scip, decision->branchvar, bestscorelowerbound, bestscoreupperbound) )
5252 {
5253 /* in case the bounds of the current highest scored solution have changed due to domain propagation during
5254 * the lookahead branching we can/should not branch on this variable but instead report the domain
5255 * reduction */
5256 status->domred = TRUE;
5257#ifdef SCIP_STATISTIC
5258 statistics->npropdomred[probingdepth]++;
5259#endif
5260 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Domain Propagation changed the bounds of a branching candidate."
5261 "\n");
5262 }
5263
5264 /* free domain reductions */
5265 if( updomainreductions != NULL )
5266 {
5267 assert(downdomainreductions != NULL);
5268
5269 domainReductionsFree(scip, &updomainreductions);
5270 domainReductionsFree(scip, &downdomainreductions);
5271 }
5272 }
5273
5274 branchingResultDataFree(scip, &bestupbranchingresult);
5275 branchingResultDataFree(scip, &bestdownbranchingresult);
5276
5277 branchingResultDataFree(scip, &upbranchingresult);
5278 branchingResultDataFree(scip, &downbranchingresult);
5279
5280 if( persistent != NULL && (!config->abbreviated || config->inscoring) && probingdepth == 0 )
5281 {
5282 persistent->restartindex = c;
5283 }
5284
5285 return SCIP_OKAY;
5286}
5287
5288/** checks whether the current decision should be stored. This is the case if we found domain reductions
5289 * or constraints that will be applied, but none of them cuts off the current LP solution.
5290 * Then our current decision still holds true for the next call and can be reused without further calculations
5291 */
5292static
5294 CONFIGURATION* config, /**< the configuration of the branching rule */
5295 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
5296 DOMAINREDUCTIONS* domainreductions /**< container collecting all domain reductions found; or NULL */
5297 )
5298{
5299 assert(config != NULL);
5300
5301 if( !config->storeunviolatedsol )
5302 return FALSE;
5303
5304 /* there are violating binary constraints */
5305 if( binconsdata != NULL && binconsdata->conslist->nviolatedcons > 0 )
5306 return FALSE;
5307
5308 /* there are violating domain changes */
5309 if( domainreductions != NULL && domainreductions->nviolatedvars > 0 )
5310 return FALSE;
5311
5312 /* return TRUE if there is at least one domain change or binary constraint */
5313 return (domainreductions != NULL && domainreductions->nchangedvars > 0)
5314 || (binconsdata != NULL && binconsdata->conslist->nelements > 0);
5315}
5316
5317/** starting point to obtain a branching decision via LAB/ALAB. */
5318static
5320 SCIP* scip, /**< SCIP data structure */
5321 CONFIGURATION* config, /**< the configuration of the branching rule */
5322 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
5323 STATUS* status, /**< current status */
5324 BRANCHINGDECISION* decision, /**< struct to store the final decision */
5325 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
5326 CANDIDATELIST* candidatelist /**< list of candidates to branch on */
5327#ifdef SCIP_STATISTIC
5328 ,STATISTICS* statistics /**< general statistical data */
5329 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
5330#endif
5331 )
5332{
5333 int recursiondepth;
5334 DOMAINREDUCTIONS* domainreductions = NULL;
5335 BINCONSDATA* binconsdata = NULL;
5336 LEVEL2DATA* level2data = NULL;
5337 SCIP_SOL* baselpsol = NULL;
5338 SCIP_Real lpobjval;
5339#ifdef SCIP_STATISTIC
5340 SCIP_Real firstscore = -1.0;
5341 SCIP_Real bestscore = -1.0;
5342 int chosencandnr = -1;
5343 SCIP_Bool performedlab = FALSE;
5344#endif
5345
5346 assert(scip != NULL);
5347 assert(config != NULL);
5348 assert(status != NULL);
5349 assert(decision != NULL);
5350 assert(candidatelist != NULL);
5351#ifdef SCIP_STATISTIC
5352 assert(statistics != NULL);
5353#endif
5354
5355 recursiondepth = config->recursiondepth;
5356 lpobjval = SCIPgetLPObjval(scip);
5357
5358 assert(recursiondepth > 0);
5359
5360 if( SCIP_MAXTREEDEPTH <= (SCIPgetDepth(scip) + recursiondepth) )
5361 {
5362 /* we need at least 'recursiondepth' space for the branching */
5363 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Cannot perform probing in selectVarRecursive, depth limit reached. "
5364 "Current:<%i>, Max:<%i>\n", SCIP_MAXTREEDEPTH, SCIPgetDepth(scip) + recursiondepth);
5365 status->depthtoosmall = TRUE;
5366#ifdef SCIP_STATISTIC
5367 statistics->ndepthreached++;
5368#endif
5369 return SCIP_OKAY;
5370 }
5371
5372 assert(!config->inscoring);
5373
5374 if( candidatelist->ncandidates == 1 )
5375 {
5376 decision->branchvar = candidatelist->candidates[0]->branchvar;
5377 decision->branchval = candidatelist->candidates[0]->branchval;
5378 decision->downdb = lpobjval;
5379 decision->downdbvalid = FALSE;
5380 decision->updb = lpobjval;
5381 decision->updbvalid = FALSE;
5382 decision->proveddb = lpobjval;
5383
5384 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Only one candidate (<%s>) is given. This one is chosen without "
5385 "calculations.\n", SCIPvarGetName(decision->branchvar));
5386
5387#ifdef SCIP_STATISTIC
5388 statistics->nsinglecandidate++;
5389#endif
5390 return SCIP_OKAY;
5391 }
5392 assert(!SCIPinProbing(scip));
5393
5394 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The objective value of the base lp is <%.9g>\n", lpobjval);
5395
5396 if( config->usedomainreduction || config->usebincons )
5397 {
5398 /* we have to copy the current solution before getting the candidates, as we possibly solve some LPs during
5399 * the getter and as such would get a wrong LP copied */
5400 SCIP_CALL( copyCurrentSolution(scip, &baselpsol) );
5401 }
5402
5403 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "About to start probing.\n");
5406
5407 /* create the binary constraint data */
5408 if( config->usebincons )
5409 {
5410 SCIP_CALL( binConsDataCreate(scip, &binconsdata, recursiondepth,
5411 (int)SCIPceil(scip, 0.5*candidatelist->ncandidates)) );
5412 }
5413
5414 /* collect domain reductions in FSB scoring or LAB branching */
5415 if( config->usedomainreduction )
5416 {
5417 SCIP_CALL( domainReductionsCreate(scip, &domainreductions) );
5418 }
5419
5420#ifdef SCIP_STATISTIC
5421 SCIP_CALL( filterCandidates(scip, status, persistent, config, baselpsol, domainreductions, NULL, candidatelist,
5422 decision, scorecontainer, level2data, lpobjval,
5423 statistics, localstats) );
5424#else
5425 SCIP_CALL( filterCandidates(scip, status, persistent, config, baselpsol, domainreductions, NULL, candidatelist,
5426 decision, scorecontainer, level2data, lpobjval) );
5427#endif
5428
5429 if( candidatelist->ncandidates == 1 )
5430 {
5431 decision->branchvar = candidatelist->candidates[0]->branchvar;
5432 decision->branchval = candidatelist->candidates[0]->branchval;
5433 decision->downdb = lpobjval;
5434 decision->downdbvalid = FALSE;
5435 decision->updb = lpobjval;
5436 decision->updbvalid = FALSE;
5437 decision->proveddb = lpobjval;
5438
5439 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Only one candidate (<%s>) is given. This one is chosen without "
5440 "calculations.\n", SCIPvarGetName(decision->branchvar));
5441
5442#ifdef SCIP_STATISTIC
5443 statistics->nsingleafterfilter++;
5444#endif
5445 goto TERMINATE;
5446 }
5447
5448 /* the status may have changed because of FSB to get the best candidates
5449 * if that is the case, we already changed the base node and should start again */
5450 if( isBranchFurther(status, TRUE) && candidatelist->ncandidates > 1 )
5451 {
5452 assert(candidatelist->ncandidates > 0);
5453
5454 SCIPstatistic(performedlab = TRUE);
5455
5456 /* we do not need the level 2 data for FSB scoring, so we do not need to create it before */
5457 if( recursiondepth == 2 && config->uselevel2data )
5458 {
5459 SCIP_CALL( level2dataCreate(scip, &level2data) );
5460 }
5461
5462#ifdef SCIP_STATISTIC
5463 SCIP_CALL( selectVarRecursive(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
5464 decision, scorecontainer, level2data, recursiondepth, lpobjval, lpobjval, NULL, NULL, NULL, NULL, NULL, NULL,
5465 statistics, localstats, &firstscore, &bestscore) );
5466#else
5467 SCIP_CALL( selectVarRecursive(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
5468 decision, scorecontainer, level2data, recursiondepth, lpobjval, lpobjval, NULL, NULL, NULL, NULL, NULL, NULL) );
5469#endif
5470
5471 if( level2data != NULL )
5472 {
5473 level2dataFree(scip, &level2data);
5474 }
5475
5476 /* only unviolating constraints and domain changes: store branching decision */
5477 if( persistent != NULL && !status->lperror && isStoreDecision(config, binconsdata, domainreductions) )
5478 {
5479 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "store decision: lpiters=%lld, cand <%s>[%g,%g - %g]\n",
5482 SCIPgetSolVal(scip, NULL, decision->branchvar));
5483
5484 persistent->oldntotalnodes = SCIPgetNTotalNodes(scip);
5487 branchingDecisionCopy(decision, persistent->olddecision);
5488 }
5489
5490#ifdef SCIP_STATISTIC
5491 if( config->abbreviated && !status->cutoff && !status->maxnconsreached
5492 && !status->addedbinconss && !status->domred)
5493 {
5494 if( candidatelist->ncandidates > 0 )
5495 {
5496 assert(candidatelist->ncandidates <= statistics->maxnbestcands);
5497
5498 /* find the "FSB-index" of the decision */
5499 for( chosencandnr = 0; chosencandnr < candidatelist->ncandidates; ++chosencandnr )
5500 {
5501 if( decision->branchvar == candidatelist->candidates[chosencandnr]->branchvar )
5502 {
5503 break;
5504 }
5505 }
5506 assert(chosencandnr < candidatelist->ncandidates);
5507 }
5508 }
5509 }
5510 else
5511 {
5512 int probingdepth = 0;
5513 if( SCIPinProbing(scip) )
5514 probingdepth = SCIPgetProbingDepth(scip);
5515 statistics->stopafterfsb[probingdepth]++;
5516
5517 if( status->cutoff )
5518 {
5519 statistics->cutoffafterfsb[probingdepth]++;
5520 }
5521 else if( status->maxnconsreached )
5522 {
5523 statistics->domredafterfsb[probingdepth]++;
5524 }
5525#endif
5526 }
5527
5528 TERMINATE:
5530 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Ended probing.\n");
5531
5532 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Applying found data to the base node.\n");
5533
5534 /* apply domain reductions */
5535 if( domainreductions != NULL )
5536 {
5537 assert(config->usedomainreduction);
5538
5539 if( !status->cutoff )
5540 {
5541 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Applying domain reductions to the base node.\n");
5542#ifdef SCIP_STATISTIC
5543 SCIP_CALL( applyDomainReductions(scip, config, baselpsol, domainreductions, &status->domredcutoff,
5544 &status->domred, statistics) );
5545#else
5546 SCIP_CALL( applyDomainReductions(scip, config, baselpsol, domainreductions, &status->domredcutoff,
5547 &status->domred) );
5548#endif
5549 }
5550 domainReductionsFree(scip, &domainreductions);
5551 }
5552
5553 /* apply binary constraints */
5554 if( binconsdata != NULL )
5555 {
5556 assert(config->usebincons);
5557 assert(binconsdata->binaryvars->nbinaryvars == 0);
5558
5559 if( !status->cutoff )
5560 {
5561 SCIP_NODE* basenode = SCIPgetCurrentNode(scip);
5562
5563 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Applying %d binary constraints to the base node.\n", binconsdata->conslist->nelements);
5564#ifdef SCIP_STATISTIC
5565 SCIP_CALL( applyBinaryConstraints(scip, basenode, binconsdata->conslist, config,
5566 &status->addedbinconss, &status->cutoff, &status->domred, statistics) );
5567#else
5568 SCIP_CALL( applyBinaryConstraints(scip, basenode, binconsdata->conslist, config,
5569 &status->addedbinconss, &status->cutoff, &status->domred) );
5570#endif
5571 }
5572 else
5573 {
5574 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Discarding %d binary constraints because the base node is cut off.\n", binconsdata->conslist->nelements);
5575 }
5576 binConsDataFree(scip, &binconsdata);
5577 }
5578 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Applied found data to the base node.\n");
5579
5580#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
5581 if( config->abbreviated )
5582 {
5583 if( status->domred )
5584 {
5585 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead Branching has added domain reductions. LAB restarts.\n");
5586
5587#ifdef SCIP_STATISTIC
5588 if( candidatelist->ncandidates == 1 )
5589 statistics->nsingleafterfilter--;
5590#endif
5591 }
5592 else if( status->addedbinconss )
5593 {
5594 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead Branching has added binary constraints. LAB restarts.\n");
5595
5596#ifdef SCIP_STATISTIC
5597 if( candidatelist->ncandidates == 1 )
5598 statistics->nsingleafterfilter--;
5599#endif
5600 }
5601 else if( status->cutoff )
5602 {
5603 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead Branching cut this node off.\n");
5604 }
5605 else if( candidatelist->ncandidates > 0 )
5606 {
5607 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Strong Branching would branch on variable <%s>\n",
5608 SCIPvarGetName(candidatelist->candidates[0]->branchvar));
5609
5610 if( isBranchFurther(status, FALSE) && branchingDecisionIsValid(decision) )
5611 {
5612#ifdef SCIP_STATISTIC
5613 if( chosencandnr >= 0 )
5614 {
5615 ++statistics->chosenfsbcand[chosencandnr];
5616
5617 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "node %lld chose candidate %d score %16.9g vs %16.9g FSB: %16.9g vs %16.9g\n",
5619 scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[chosencandnr]->branchvar)],
5620 scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)],
5621 bestscore, firstscore);
5622 }
5623 else
5624 assert(!performedlab);
5625#endif
5626
5627 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead Branching branches on variable <%s>\n",
5628 SCIPvarGetName(decision->branchvar));
5629 }
5630 }
5631 else
5632 {
5633 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Something unexpected happened.");
5634 SCIPABORT();
5635 }
5636 }
5637#endif
5638
5639 if( baselpsol != NULL )
5640 {
5641 SCIP_CALL( SCIPfreeSol(scip, &baselpsol) );
5642 }
5643
5644 return SCIP_OKAY;
5645}
5646
5647/**
5648 * We can use the previous result, stored in the branchruledata, if the branchingvariable (as an indicator) is set and
5649 * the current lp solution is equal to the previous lp solution.
5650 *
5651 * @return \ref TRUE, if we can branch on the previous decision, \ref FALSE, else.
5652 */
5653static
5655 SCIP* scip, /**< SCIP data structure */
5656 SCIP_BRANCHRULEDATA* branchruledata /**< branching rule data */
5657 )
5658{
5659 PERSISTENTDATA* persistent;
5660
5661 assert(scip != NULL);
5662 assert(branchruledata != NULL);
5663
5664 persistent = branchruledata->persistent;
5665 assert(persistent != NULL);
5666
5667 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "check if previous result should be used: valid=%d, "\
5668 "nodes=%lld (old=%lld), iterations=%lld (old=%lld), lps=%lld (old=%lld)\n",
5673
5674 return branchingDecisionIsValid(persistent->olddecision)
5675 && (persistent->oldntotalnodes == SCIPgetNTotalNodes(scip))
5678}
5679
5680/**
5681 * Uses the results from the previous run saved in the branchruledata to branch.
5682 * This is the case, if in the previous run only non-violating constraints were added. In that case we can use the
5683 * branching decision we would have made then.
5684 * If everything worked, the result pointer contains SCIP_BRANCHED.
5685 *
5686 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5687 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5688 */
5689static
5691 SCIP* scip, /**< SCIP data structure */
5692 SCIP_BRANCHRULEDATA* branchruledata, /**< branching rule data */
5693 SCIP_RESULT* result /**< the pointer to the branching result */
5694 )
5695{
5696 assert(scip != NULL);
5697 assert(branchruledata != NULL);
5698 assert(result != NULL);
5699 assert(branchruledata->config != NULL);
5700 assert(branchruledata->persistent != NULL);
5701 assert(branchruledata->persistent->olddecision != NULL);
5702
5703 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Branching based on previous solution.\n");
5704
5705 /* execute the actual branching */
5706 SCIP_CALL( branchOnVar(scip, branchruledata->config, branchruledata->persistent->olddecision) );
5707 *result = SCIP_BRANCHED;
5708
5709 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Branched based on previous solution. Variable <%s>\n",
5710 SCIPvarGetName(branchruledata->persistent->olddecision->branchvar));
5711
5712 /* reset the var pointer, as this is our indicator whether we should branch on prev data in the next call */
5713 branchruledata->persistent->olddecision->branchvar = NULL;
5714
5715 return SCIP_OKAY;
5716}
5717
5718/** free persistent data structure */
5719static
5721 SCIP* scip, /**< SCIP data structure */
5722 SCIP_BRANCHRULEDATA* branchruledata /**< branching rule data */
5723 )
5724{
5725 PERSISTENTDATA* persistent;
5726 int nvars;
5727 int i;
5728
5729 assert(scip != NULL);
5730 assert(branchruledata != NULL);
5731
5732 persistent = branchruledata->persistent;
5733 assert(persistent != NULL);
5734
5735 nvars = persistent->nvars;
5736
5737 for( i = nvars - 1; i >= 0; i--)
5738 {
5739 assert(persistent->lastbranchdownres[i] != NULL);
5740 assert(persistent->lastbranchupres[i] != NULL);
5741
5742 SCIPfreeBlockMemory(scip, &persistent->lastbranchdownres[i]); /*lint !e866*/
5743 SCIPfreeBlockMemory(scip, &persistent->lastbranchupres[i]); /*lint !e866*/
5744 }
5745
5746 SCIPfreeBlockMemory(scip, &branchruledata->persistent->olddecision);
5747
5748 assert(persistent->lastbranchlpobjval != NULL);
5749 assert(persistent->lastbranchdownres != NULL);
5750 assert(persistent->lastbranchupres != NULL);
5751 assert(persistent->lastbranchnlps != NULL);
5752 assert(persistent->lastbranchid != NULL);
5753
5754 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchlpobjval, nvars);
5755 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchdownres, nvars);
5756 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchupres, nvars);
5757 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchnlps, nvars);
5758 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchid, nvars);
5759
5760 branchruledata->isinitialized = FALSE;
5761
5762 return SCIP_OKAY;
5763}
5764
5765/** initializes the branchruledata and the contained structs */
5766static
5768 SCIP* scip, /**< SCIP data structure */
5769 SCIP_BRANCHRULEDATA* branchruledata /**< the branch rule data to initialize */
5770 )
5771{
5772 int nvars;
5773 int i;
5774
5775 assert(scip != NULL);
5776 assert(branchruledata != NULL);
5777
5778 /* with the SCIPvarGetProbindex() method we can access the index of a given variable in the SCIPgetVars() array and
5779 * as such we can use it to access our arrays which should only contain binary and integer variables
5780 */
5782
5783 /* the branching rule data is already initialized and no new variables have been added in the meantime */
5784 if( branchruledata->isinitialized && nvars == branchruledata->persistent->nvars )
5785 return SCIP_OKAY;
5786
5787 if( branchruledata->isinitialized )
5788 {
5789 SCIP_CALL( freePersistent(scip, branchruledata) );
5790 }
5791
5792 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchid, nvars) );
5793 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchnlps, nvars) );
5794 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchupres, nvars) );
5795 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchdownres, nvars) );
5796 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchlpobjval, nvars) );
5797 branchruledata->persistent->nvars = nvars;
5798 branchruledata->persistent->oldntotalnodes = -1;
5799 branchruledata->persistent->oldnnodelpiterations = -1;
5800 branchruledata->persistent->oldnnodelps = -1;
5801
5802 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->persistent->olddecision) );
5803 branchingDecisionInit(scip, branchruledata->persistent->olddecision);
5804
5805 for( i = 0; i < nvars; i++ )
5806 {
5807 branchruledata->persistent->lastbranchid[i] = -1;
5808 branchruledata->persistent->lastbranchnlps[i] = 0;
5809
5810 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->persistent->lastbranchupres[i]) ); /*lint !e866*/
5811 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->persistent->lastbranchdownres[i]) ); /*lint !e866*/
5812 }
5813
5814 branchruledata->isinitialized = TRUE;
5815
5816 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Initialized the branchruledata\n");
5817
5818 return SCIP_OKAY;
5819}
5820
5821/*
5822 * Callback methods of branching rule
5823 */
5824
5825/** copy method for branchrule plugins (called when SCIP copies plugins) */
5826static
5827SCIP_DECL_BRANCHCOPY(branchCopyLookahead)
5828{ /*lint --e{715}*/
5829 assert(scip != NULL);
5830 assert(branchrule != NULL);
5831 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
5832
5833 /* call inclusion method of branchrule */
5835
5836 return SCIP_OKAY;
5837}
5838
5839/** destructor of branching rule to free user data (called when SCIP is exiting) */
5840static
5841SCIP_DECL_BRANCHFREE(branchFreeLookahead)
5842{ /*lint --e{715}*/
5843 SCIP_BRANCHRULEDATA* branchruledata;
5844
5845 branchruledata = SCIPbranchruleGetData(branchrule);
5846 assert(branchruledata != NULL);
5847 assert(branchruledata->config != NULL);
5848 assert(branchruledata->persistent != NULL);
5849
5850 SCIPfreeBlockMemory(scip, &branchruledata->persistent);
5851 SCIPfreeBlockMemory(scip, &branchruledata->config);
5852 SCIPfreeBlockMemory(scip, &branchruledata);
5853 SCIPbranchruleSetData(branchrule, NULL);
5854
5855 return SCIP_OKAY;
5856}
5857
5858/** initialization method of branching rule (called after problem was transformed) */
5859static
5860SCIP_DECL_BRANCHINIT(branchInitLookahead)
5861{ /*lint --e{715}*/
5862 SCIP_BRANCHRULEDATA* branchruledata;
5863
5864 assert(scip != NULL);
5865 assert(branchrule != NULL);
5866
5867 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Entering branchInitLookahead\n");
5868
5869 branchruledata = SCIPbranchruleGetData(branchrule);
5870 assert(branchruledata != NULL);
5871 assert(branchruledata->persistent != NULL);
5872
5873 branchruledata->persistent->restartindex = 0;
5874
5875#ifdef SCIP_STATISTIC
5876 {
5877 int recursiondepth;
5878 int maxncands;
5879
5880 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Allocating space for the statistics struct.\n");
5881
5882 recursiondepth = branchruledata->config->recursiondepth;
5884 if( maxncands > branchruledata->config->maxncands )
5885 maxncands = branchruledata->config->maxncands;
5886
5887 SCIP_CALL( SCIPallocMemory(scip, &branchruledata->statistics) );
5888 /* RESULT enum is 1 based, so use MAXRESULT + 1 as array size with unused 0 element */
5889 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nresults, MAXRESULT + 1) );
5890 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nsinglecutoffs, recursiondepth) );
5891 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nfullcutoffs, recursiondepth) );
5892 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nlpssolved, recursiondepth) );
5893 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nlpssolvedfsb, recursiondepth) );
5894 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nlpiterations, recursiondepth) );
5895 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nlpiterationsfsb, recursiondepth) );
5896 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nduplicatelps, recursiondepth) );
5897 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->npropdomred, recursiondepth) );
5898 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->noldbranchused, recursiondepth) );
5899 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->noldbranchusedfsb, recursiondepth) );
5900 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->chosenfsbcand, maxncands) );
5901 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->domredafterfsb, recursiondepth) );
5902 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->cutoffafterfsb, recursiondepth) );
5903 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->stopafterfsb, recursiondepth) );
5904
5905 branchruledata->statistics->recursiondepth = recursiondepth;
5906 branchruledata->statistics->maxnbestcands = maxncands;
5907
5908 statisticsInit(branchruledata->statistics);
5909 }
5910#endif
5911
5912 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Leaving branchInitLookahead\n");
5913
5914 return SCIP_OKAY;
5915}
5916
5917
5918/** deinitialization method of branching rule (called before transformed problem is freed) */
5919static
5920SCIP_DECL_BRANCHEXIT(branchExitLookahead)
5921{ /*lint --e{715}*/
5922#ifdef SCIP_STATISTIC
5923 SCIP_BRANCHRULEDATA* branchruledata;
5924 STATISTICS* statistics;
5925
5926 branchruledata = SCIPbranchruleGetData(branchrule);
5927 assert(branchruledata != NULL);
5928
5929 statistics = branchruledata->statistics;
5930 assert(statistics != NULL);
5931
5932 statisticsPrint(scip, statistics);
5933
5934 SCIPfreeMemoryArray(scip, &statistics->stopafterfsb);
5935 SCIPfreeMemoryArray(scip, &statistics->cutoffafterfsb);
5936 SCIPfreeMemoryArray(scip, &statistics->domredafterfsb);
5937 SCIPfreeMemoryArray(scip, &statistics->chosenfsbcand);
5938 SCIPfreeMemoryArray(scip, &statistics->noldbranchusedfsb);
5939 SCIPfreeMemoryArray(scip, &statistics->noldbranchused);
5940 SCIPfreeMemoryArray(scip, &statistics->npropdomred);
5941 SCIPfreeMemoryArray(scip, &statistics->nlpiterationsfsb);
5942 SCIPfreeMemoryArray(scip, &statistics->nlpiterations);
5943 SCIPfreeMemoryArray(scip, &statistics->nduplicatelps);
5944 SCIPfreeMemoryArray(scip, &statistics->nlpssolvedfsb);
5945 SCIPfreeMemoryArray(scip, &statistics->nlpssolved);
5946 SCIPfreeMemoryArray(scip, &statistics->nfullcutoffs);
5947 SCIPfreeMemoryArray(scip, &statistics->nsinglecutoffs);
5948 SCIPfreeMemoryArray(scip, &statistics->nresults);
5949 SCIPfreeMemory(scip, &statistics);
5950#endif
5951
5952 return SCIP_OKAY;
5953}
5954
5955/** solving process deinitialization method of branching rule (called before branch and bound process data is freed) */
5956static
5957SCIP_DECL_BRANCHEXITSOL(branchExitSolLookahead)
5958{ /*lint --e{715}*/
5959 SCIP_BRANCHRULEDATA* branchruledata;
5960
5961 branchruledata = SCIPbranchruleGetData(branchrule);
5962 assert(branchruledata != NULL);
5963
5964 if( branchruledata->isinitialized )
5965 {
5966 SCIP_CALL( freePersistent(scip, branchruledata) );
5967 }
5968
5969 return SCIP_OKAY;
5970}
5971
5972/** branching execution method for fractional LP solutions */
5973static
5974SCIP_DECL_BRANCHEXECLP(branchExeclpLookahead)
5975{ /*lint --e{715}*/
5976 SCIP_BRANCHRULEDATA* branchruledata;
5977 CONFIGURATION* config;
5978 SCIP_Bool userusebincons;
5979
5980 assert(branchrule != NULL);
5981 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
5982 assert(scip != NULL);
5983 assert(result != NULL);
5984
5985 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Entering branchExeclpLookahead at node %lld.\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
5986
5987 branchruledata = SCIPbranchruleGetData(branchrule);
5988 assert(branchruledata != NULL);
5989
5990 config = branchruledata->config;
5991
5992 /* we are only allowed to add binary constraints, if the corresponding flag is given */
5993 userusebincons = config->usebincons;
5994 config->usebincons = config->usebincons && allowaddcons;
5995
5996 SCIP_CALL( initBranchruleData(scip, branchruledata) );
5997
5998 if( config->storeunviolatedsol
5999 && isUsePreviousResult(scip, branchruledata) )
6000 {
6001 /* in case we stopped the previous run without a branching decision, we have stored the decision and execute it
6002 * now */
6003 SCIP_CALL( usePreviousResult(scip, branchruledata, result) );
6004
6005#ifdef SCIP_STATISTIC
6006 branchruledata->statistics->noldcandidate++;
6007#endif
6008 }
6009 else
6010 {
6011 BRANCHINGDECISION* decision;
6012 SCORECONTAINER* scorecontainer = NULL;
6013 CANDIDATELIST* candidatelist;
6014 STATUS* status;
6015#ifdef SCIP_STATISTIC
6016 LOCALSTATISTICS* localstats;
6017#endif
6018
6019 /* create a struct to store the algorithm status */
6020 SCIP_CALL( statusCreate(scip, &status) );
6021
6022 /* create a struct to store the branching decision (in case there is one) */
6023 SCIP_CALL( branchingDecisionCreate(scip, &decision) );
6024 if( config->abbreviated )
6025 {
6026 /* allocate and init the container used to store the FSB scores, later used to filter the candidates */
6027 SCIP_CALL( scoreContainerCreate(scip, &scorecontainer, config) );
6028 }
6029
6031
6032 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The base lp has <%i> variables with fractional value.\n",
6033 candidatelist->ncandidates);
6034
6035 /* execute the main logic */
6036#ifdef SCIP_STATISTIC
6037 /* create a struct to store the statistics needed for this single run */
6038 SCIP_CALL( localStatisticsAllocate(scip, &localstats) );
6039 SCIP_CALL( selectVarStart(scip, config, branchruledata->persistent, status, decision,
6040 scorecontainer, candidatelist, branchruledata->statistics, localstats) );
6041#else
6042 SCIP_CALL( selectVarStart(scip, config, branchruledata->persistent, status, decision,
6043 scorecontainer, candidatelist) );
6044#endif
6045
6046 if( status->cutoff || status->domredcutoff )
6047 {
6048 *result = SCIP_CUTOFF;
6049#ifdef SCIP_STATISTIC
6050 branchruledata->statistics->ncutoffproofnodes += localstats->ncutoffproofnodes;
6051#endif
6052 }
6053 else
6054 {
6055 if( status->addedbinconss )
6056 {
6057 *result = SCIP_CONSADDED;
6058 }
6059 else if( status->domred )
6060 {
6061 *result = SCIP_REDUCEDDOM;
6062 }
6063 else if( status->lperror )
6064 {
6065#ifdef SCIP_STATISTIC
6066 ++branchruledata->statistics->nlperrorcalls;
6067#endif
6068 if( !branchingDecisionIsValid(decision) )
6069 {
6070 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "LP error with no valid candidate: select first candidate variable\n");
6071
6072 assert(candidatelist->ncandidates > 0);
6073 decision->branchvar = candidatelist->candidates[0]->branchvar;
6074 decision->branchval = candidatelist->candidates[0]->branchval;
6075 }
6076 }
6077 else if( status->maxnconsreached )
6078 {
6079 /* this case may occure if the domain reductions that reached the limit were already applied via domain
6080 * propagation
6081 */
6082 *result = SCIP_REDUCEDDOM;
6083 }
6084#ifdef SCIP_STATISTIC
6085 else if( status->limitreached )
6086 {
6087 ++branchruledata->statistics->nlimitcalls;
6088 }
6089#endif
6090 /* update lower bound of current node */
6092 {
6094 }
6095 }
6096
6097 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Result before branching is %s\n", getStatusString(*result));
6098
6099 if( *result != SCIP_CUTOFF /* a variable could not be branched in any direction or any of the calculated domain
6100 * reductions was infeasible */
6101 && *result != SCIP_REDUCEDDOM /* the domain of a variable was reduced by evaluating the calculated cutoffs */
6102 && *result != SCIP_CONSADDED /* implicit binary constraints were already added */
6103 && !status->depthtoosmall /* branching depth wasn't high enough */
6104 && branchingDecisionIsValid(decision)
6105 /*&& (0 <= bestcand && bestcand < nlpcands)*/ /* no valid candidate index could be found */
6106 )
6107 {
6108 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> %d candidates, selected variable <%s> (solval=%g, down=%.9g, "
6109 "up=%.9g)\n", candidatelist->ncandidates, SCIPvarGetName(decision->branchvar), decision->branchval,
6110 decision->downdb, decision->updb);
6111
6112 /* execute the branching as a result of the branching logic */
6113 SCIP_CALL( branchOnVar(scip, config, decision) );
6114
6115 *result = SCIP_BRANCHED;
6116 }
6117
6118#ifdef SCIP_DEBUG
6119 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Result after branching is %s\n", getStatusString(*result));
6120
6121 if( *result == SCIP_BRANCHED )
6122 {
6123 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Finished LookaheadBranching by branching.\n");
6124 }
6125 else if( *result == SCIP_REDUCEDDOM )
6126 {
6127 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Finished LookaheadBranching by reducing domains.\n");
6128 }
6129 else if( *result == SCIP_CUTOFF )
6130 {
6131 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Finished LookaheadBranching by cutting off, as the current "
6132 "problem is infeasible.\n");
6133 }
6134 else if( *result == SCIP_CONSADDED )
6135 {
6136 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Finished LookaheadBranching by adding constraints.\n");
6137 }
6138 else if( status->depthtoosmall )
6139 {
6140 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: The remaining tree depth did not allow for multi level "
6141 "lookahead branching.\n");
6142 }
6143 else
6144 {
6145 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Could not find any variable to branch on.\n");
6146 }
6147#endif
6148
6149#ifdef SCIP_STATISTIC
6150 localStatisticsFree(scip, &localstats);
6151#endif
6152 SCIP_CALL( candidateListFree(scip, &candidatelist) );
6153
6154 /* scorecontainer != NULL iff branchruledata->config->abbreviated == TRUE */
6155 if( scorecontainer != NULL )
6156 {
6157 SCIP_CALL( scoreContainerFree(scip, &scorecontainer) );
6158 }
6159 branchingDecisionFree(scip, &decision);
6160 statusFree(scip, &status);
6161 }
6162
6163#ifdef SCIP_STATISTIC
6164 assert(*result >= 1);
6165 assert(*result <= MAXRESULT);
6166 branchruledata->statistics->ntotalresults++;
6167 branchruledata->statistics->nresults[*result]++;
6168
6169 if( config->abbreviated )
6170 {
6171 int sum;
6172 int i;
6173
6174 sum = branchruledata->statistics->nsinglecandidate + branchruledata->statistics->nsingleafterfilter
6175 + branchruledata->statistics->noldcandidate + branchruledata->statistics->nlperrorcalls
6176 + branchruledata->statistics->nlimitcalls;
6177
6178 for( i = 0; i < branchruledata->statistics->maxnbestcands; i++ )
6179 {
6180 sum += branchruledata->statistics->chosenfsbcand[i];
6181 }
6182 if( sum != branchruledata->statistics->nresults[SCIP_BRANCHED] )
6183 {
6184 printf("branched = %d != sum = %d (%d/%d/%d/%d/%d)\n",
6185 branchruledata->statistics->nresults[SCIP_BRANCHED], sum,
6186 branchruledata->statistics->nsinglecandidate, branchruledata->statistics->nsingleafterfilter,
6187 branchruledata->statistics->noldcandidate,
6188 branchruledata->statistics->nlperrorcalls, branchruledata->statistics->nlimitcalls);
6189 assert(SCIPisStopped(scip));
6190 }
6191 assert(sum == branchruledata->statistics->nresults[SCIP_BRANCHED]);
6192 }
6193
6194 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "#### ncutoffproofnodes: %d ndomredproofnodes: %d\n",
6195 branchruledata->statistics->ncutoffproofnodes, branchruledata->statistics->ndomredproofnodes);
6196#endif
6197
6198 config->usebincons = userusebincons;
6199
6200 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Exiting branchExeclpLookahead.\n");
6201 return SCIP_OKAY;
6202}
6203
6204/*
6205 * branching rule specific interface methods
6206 */
6207
6208/** creates the lookahead branching rule and includes it in SCIP */
6210 SCIP* scip /**< SCIP data structure */
6211 )
6212{
6213 SCIP_BRANCHRULEDATA* branchruledata;
6214 SCIP_BRANCHRULE* branchrule;
6215
6216 /* create lookahead branching rule data */
6217 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
6218 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->config) );
6219 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->persistent) );
6220 branchruledata->persistent->restartindex = 0;
6221 branchruledata->isinitialized = FALSE;
6222 branchruledata->config->inscoring = FALSE;
6223
6224 /* include branching rule */
6226 BRANCHRULE_MAXDEPTH, BRANCHRULE_MAXBOUNDDIST, branchruledata) );
6227
6228 assert(branchrule != NULL);
6229
6230 /* set non fundamental callbacks via setter functions */
6231 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyLookahead) );
6232 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeLookahead) );
6233 SCIP_CALL( SCIPsetBranchruleInit(scip, branchrule, branchInitLookahead) );
6234 SCIP_CALL( SCIPsetBranchruleExit(scip, branchrule, branchExitLookahead) );
6235 SCIP_CALL( SCIPsetBranchruleExitsol(scip, branchrule, branchExitSolLookahead) );
6236 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpLookahead) );
6237
6238 /* add lookahead branching rule parameters */
6240 "branching/lookahead/useimpliedbincons",
6241 "should binary constraints be collected and applied?",
6242 &branchruledata->config->usebincons, TRUE, DEFAULT_USEBINARYCONSTRAINTS, NULL, NULL) );
6244 "branching/lookahead/addbinconsrow",
6245 "should binary constraints be added as rows to the base LP? (0: no, 1: separate, 2: as initial rows)",
6246 &branchruledata->config->addbinconsrow, TRUE, DEFAULT_ADDBINCONSROW, 0, 2, NULL, NULL) );
6247 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxnviolatedcons",
6248 "how many constraints that are violated by the base lp solution should be gathered until the rule is stopped and "\
6249 "they are added? [0 for unrestricted]",
6250 &branchruledata->config->maxnviolatedcons, TRUE, DEFAULT_MAXNVIOLATEDCONS, 0, INT_MAX, NULL, NULL) );
6251 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxnviolatedbincons",
6252 "how many binary constraints that are violated by the base lp solution should be gathered until the rule is "\
6253 "stopped and they are added? [0 for unrestricted]",
6254 &branchruledata->config->maxnviolatedbincons, TRUE, DEFAULT_MAXNVIOLATEDBINCONS, 0, INT_MAX, NULL, NULL) );
6255 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxnviolateddomreds",
6256 "how many domain reductions that are violated by the base lp solution should be gathered until the rule is "\
6257 "stopped and they are added? [0 for unrestricted]",
6258 &branchruledata->config->maxnviolateddomreds, TRUE, DEFAULT_MAXNVIOLATEDDOMREDS, 0, INT_MAX, NULL, NULL) );
6260 "branching/lookahead/reevalage",
6261 "max number of LPs solved after which a previous prob branching results are recalculated",
6262 &branchruledata->config->reevalage, TRUE, DEFAULT_REEVALAGE, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
6264 "branching/lookahead/reevalagefsb",
6265 "max number of LPs solved after which a previous FSB scoring results are recalculated",
6266 &branchruledata->config->reevalagefsb, TRUE, DEFAULT_REEVALAGEFSB, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
6267 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/recursiondepth",
6268 "the max depth of LAB.",
6269 &branchruledata->config->recursiondepth, TRUE, DEFAULT_RECURSIONDEPTH, 1, INT_MAX, NULL, NULL) );
6271 "branching/lookahead/usedomainreduction",
6272 "should domain reductions be collected and applied?",
6273 &branchruledata->config->usedomainreduction, TRUE, DEFAULT_USEDOMAINREDUCTION, NULL, NULL) );
6275 "branching/lookahead/mergedomainreductions",
6276 "should domain reductions of feasible siblings should be merged?",
6277 &branchruledata->config->mergedomainreductions, TRUE, DEFAULT_MERGEDOMAINREDUCTIONS, NULL, NULL) );
6279 "branching/lookahead/prefersimplebounds",
6280 "should domain reductions only be applied if there are simple bound changes?",
6281 &branchruledata->config->prefersimplebounds, TRUE, DEFAULT_PREFERSIMPLEBOUNDS, NULL, NULL) );
6283 "branching/lookahead/onlyvioldomreds",
6284 "should only domain reductions that violate the LP solution be applied?",
6285 &branchruledata->config->onlyvioldomreds, TRUE, DEFAULT_ONLYVIOLDOMREDS, NULL, NULL) );
6287 "branching/lookahead/addnonviocons",
6288 "should binary constraints, that are not violated by the base LP, be collected and added?",
6289 &branchruledata->config->addnonviocons, TRUE, DEFAULT_ADDNONVIOCONS, NULL, NULL) );
6291 "branching/lookahead/abbreviated",
6292 "toggles the abbreviated LAB.",
6293 &branchruledata->config->abbreviated, TRUE, DEFAULT_ABBREVIATED, NULL, NULL) );
6294 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxncands",
6295 "if abbreviated: The max number of candidates to consider at the node.",
6296 &branchruledata->config->maxncands, TRUE, DEFAULT_MAXNCANDS, 1, INT_MAX, NULL, NULL) );
6297 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxndeepercands",
6298 "if abbreviated: The max number of candidates to consider per deeper node.",
6299 &branchruledata->config->maxndeepercands, TRUE, DEFAULT_MAXNDEEPERCANDS, 0, INT_MAX, NULL, NULL) );
6301 "branching/lookahead/reusebasis",
6302 "if abbreviated: Should the information gathered to obtain the best candidates be reused?",
6303 &branchruledata->config->reusebasis, TRUE, DEFAULT_REUSEBASIS, NULL, NULL) );
6305 "branching/lookahead/storeunviolatedsol",
6306 "if only non violating constraints are added, should the branching decision be stored till the next call?",
6307 &branchruledata->config->storeunviolatedsol, TRUE, DEFAULT_STOREUNVIOLATEDSOL, NULL, NULL) );
6309 "branching/lookahead/abbrevpseudo",
6310 "if abbreviated: Use pseudo costs to estimate the score of a candidate.",
6311 &branchruledata->config->abbrevpseudo, TRUE, DEFAULT_ABBREVPSEUDO, NULL, NULL) );
6313 "branching/lookahead/level2avgscore",
6314 "should the average score be used for uninitialized scores in level 2?",
6315 &branchruledata->config->level2avgscore, TRUE, DEFAULT_LEVEL2AVGSCORE, NULL, NULL) );
6317 "branching/lookahead/level2zeroscore",
6318 "should uninitialized scores in level 2 be set to 0?",
6319 &branchruledata->config->level2zeroscore, TRUE, DEFAULT_LEVEL2ZEROSCORE, NULL, NULL) );
6321 "branching/lookahead/addclique",
6322 "add binary constraints with two variables found at the root node also as a clique",
6323 &branchruledata->config->addclique, TRUE, DEFAULT_ADDCLIQUE, NULL, NULL) );
6325 "branching/lookahead/propagate",
6326 "should domain propagation be executed before each temporary node is solved?",
6327 &branchruledata->config->propagate, TRUE, DEFAULT_PROPAGATE, NULL, NULL) );
6329 "branching/lookahead/uselevel2data",
6330 "should branching data generated at depth level 2 be stored for re-using it?",
6331 &branchruledata->config->uselevel2data, TRUE, DEFAULT_USELEVEL2DATA, NULL, NULL) );
6333 "branching/lookahead/applychildbounds",
6334 "should bounds known for child nodes be applied?",
6335 &branchruledata->config->applychildbounds, TRUE, DEFAULT_APPLYCHILDBOUNDS, NULL, NULL) );
6337 "branching/lookahead/enforcemaxdomreds",
6338 "should the maximum number of domain reductions maxnviolateddomreds be enforced?",
6339 &branchruledata->config->enforcemaxdomreds, TRUE, DEFAULT_ENFORCEMAXDOMREDS, NULL, NULL) );
6341 "branching/lookahead/updatebranchingresults",
6342 "should branching results (and scores) be updated w.r.t. proven dual bounds?",
6343 &branchruledata->config->updatebranchingresults, TRUE, DEFAULT_UPDATEBRANCHINGRESULTS, NULL, NULL) );
6345 "branching/lookahead/maxproprounds",
6346 "maximum number of propagation rounds to perform at each temporary node (-1: unlimited, 0: SCIP default)",
6347 &branchruledata->config->maxproprounds, TRUE, DEFAULT_MAXPROPROUNDS, -1, INT_MAX, NULL, NULL) );
6349 "branching/lookahead/scoringfunction",
6350 "scoring function to be used at the base level",
6351 &branchruledata->config->scoringfunction, TRUE, DEFAULT_SCORINGFUNCTION, "dfswplcra", NULL, NULL) );
6353 "branching/lookahead/deeperscoringfunction",
6354 "scoring function to be used at deeper levels",
6355 &branchruledata->config->deeperscoringfunction, TRUE, DEFAULT_DEEPERSCORINGFUNCTION, "dfswlcrx", NULL, NULL) );
6357 "branching/lookahead/scoringscoringfunction",
6358 "scoring function to be used during FSB scoring",
6359 &branchruledata->config->scoringscoringfunction, TRUE, DEFAULT_SCORINGSCORINGFUNCTION, "dfswlcr", NULL, NULL) );
6361 "branching/lookahead/minweight",
6362 "if scoringfunction is 's', this value is used to weight the min of the gains of two child problems in the convex combination",
6363 &branchruledata->config->minweight, TRUE, DEFAULT_MINWEIGHT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
6365 "branching/lookahead/worsefactor",
6366 "if the FSB score is of a candidate is worse than the best by this factor, skip this candidate (-1: disable)",
6367 &branchruledata->config->worsefactor, TRUE, DEFAULT_WORSEFACTOR, -1.0, SCIP_REAL_MAX, NULL, NULL) );
6369 "branching/lookahead/filterbymaxgain",
6370 "should lookahead branching only be applied if the max gain in level 1 is not uniquely that of the best candidate?",
6371 &branchruledata->config->filterbymaxgain, TRUE, DEFAULT_FILTERBYMAXGAIN, NULL, NULL) );
6372
6373 return SCIP_OKAY;
6374}
#define BRANCHRULE_DESC
static SCIP_RETCODE selectVarStart(SCIP *scip, CONFIGURATION *config, PERSISTENTDATA *persistent, STATUS *status, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, CANDIDATELIST *candidatelist)
static SCIP_Bool isCandidateReliable(SCIP *scip, SCIP_VAR *branchvar)
static SCIP_DECL_BRANCHFREE(branchFreeLookahead)
static SCIP_Bool warmStartInfoIsAvailable(WARMSTARTINFO *warmstartinfo)
static void domainReductionsFree(SCIP *scip, DOMAINREDUCTIONS **domreds)
#define DEFAULT_USEBINARYCONSTRAINTS
static SCIP_RETCODE branchingDecisionEnsureBoundArraysSize(SCIP *scip, BRANCHINGDECISION *decision, int nvars)
static void binConsDataFree(SCIP *scip, BINCONSDATA **consdata)
static void level2resultFree(SCIP *scip, LEVEL2RESULT **result)
static SCIP_RETCODE getOldBranching(SCIP *scip, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real *oldlpobjval)
#define DEFAULT_UPDATEBRANCHINGRESULTS
#define BRANCHRULE_PRIORITY
static SCIP_RETCODE scoreContainerCreate(SCIP *scip, SCORECONTAINER **scorecontainer, CONFIGURATION *config)
static SCIP_RETCODE applyDomainReductions(SCIP *scip, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domreds, SCIP_Bool *domredcutoff, SCIP_Bool *domred)
#define DEFAULT_PROPAGATE
static SCIP_Real calculateScaledCutoffScore(BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult)
static SCIP_DECL_BRANCHINIT(branchInitLookahead)
static SCIP_RETCODE level2dataEnsureSize(SCIP *scip, LEVEL2DATA *data)
#define DEFAULT_DEEPERSCORINGFUNCTION
static SCIP_RETCODE executeBranching(SCIP *scip, CONFIGURATION *config, SCIP_Bool downbranching, CANDIDATE *candidate, BRANCHINGRESULTDATA *resultdata, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domreds, STATUS *status)
static SCIP_RETCODE statusCreate(SCIP *scip, STATUS **status)
static void addLowerBound(SCIP *scip, SCIP_VAR *var, SCIP_Real lowerbound, SCIP_SOL *baselpsol, SCIP_Bool simplechange, DOMAINREDUCTIONS *domainreductions)
static SCIP_Real calculateScoreFromPseudocosts(SCIP *scip, CANDIDATE *lpcand)
#define DEFAULT_SCORINGFUNCTION
static void createBinaryConstraintName(SCIP_VAR **binaryvars, int nbinaryvars, char *constraintname)
static SCIP_RETCODE executeBranchingRecursive(SCIP *scip, STATUS *status, CONFIGURATION *config, SCIP_SOL *baselpsol, CANDIDATE *candidate, SCIP_Real localbaselpsolval, SCIP_Real baselpobjval, int recursiondepth, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, LEVEL2DATA *level2data, BRANCHINGRESULTDATA *branchingresult, SCORECONTAINER *scorecontainer, SCIP_Bool downbranching)
static void binaryVarListDrop(BINARYVARLIST *list)
#define DEFAULT_USELEVEL2DATA
static SCIP_Bool areBoundsChanged(SCIP *scip, SCIP_VAR *var, SCIP_Real lowerbound, SCIP_Real upperbound)
static SCIP_Bool isBranchFurther(STATUS *status, SCIP_Bool checkdomreds)
#define DEFAULT_ENFORCEMAXDOMREDS
static SCIP_RETCODE branchingResultDataCreate(SCIP *scip, BRANCHINGRESULTDATA **resultdata)
static SCIP_RETCODE domainReductionsCreate(SCIP *scip, DOMAINREDUCTIONS **domreds)
static SCIP_RETCODE copyCurrentSolution(SCIP *scip, SCIP_SOL **lpsol)
static SCIP_DECL_BRANCHEXIT(branchExitLookahead)
#define DEFAULT_ABBREVIATED
static SCIP_RETCODE warmStartInfoFree(SCIP *scip, WARMSTARTINFO **warmstartinfo)
#define DEFAULT_MERGEDOMAINREDUCTIONS
static void branchingResultDataCopy(BRANCHINGRESULTDATA *sourcedata, BRANCHINGRESULTDATA *targetdata)
static SCIP_RETCODE applyBinaryConstraints(SCIP *scip, SCIP_NODE *basenode, CONSTRAINTLIST *conslist, CONFIGURATION *config, SCIP_Bool *consadded, SCIP_Bool *cutoff, SCIP_Bool *boundchange)
static SCIP_RETCODE scoreContainerFree(SCIP *scip, SCORECONTAINER **scorecontainer)
#define DEFAULT_ADDCLIQUE
#define DEFAULT_REEVALAGE
#define DEFAULT_REEVALAGEFSB
static SCIP_RETCODE constraintListCreate(SCIP *scip, CONSTRAINTLIST **conslist, int startsize)
static SCIP_Real calculateScoreFromDeeperscoreAndCutoffs(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult)
static void scoreContainterResetBestSortedCands(SCORECONTAINER *scorecontainer)
static SCIP_Bool isUsePreviousResult(SCIP *scip, SCIP_BRANCHRULEDATA *branchruledata)
static SCIP_DECL_BRANCHEXECLP(branchExeclpLookahead)
static SCIP_RETCODE ensureScoresPresent(SCIP *scip, STATUS *status, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, CANDIDATELIST *allcandidates, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, LEVEL2DATA *level2data, SCIP_Real lpobjval)
static SCIP_RETCODE candidateCreate(SCIP *scip, CANDIDATE **candidate)
#define DEFAULT_MAXNDEEPERCANDS
static SCIP_RETCODE candidateListCreate(SCIP *scip, CANDIDATELIST **candidatelist, int ncandidates)
static SCIP_Bool isBranchFurtherLoopDecrement(STATUS *status, int *loopcounter)
#define BRANCHRULE_NAME
static void binaryVarListAppend(SCIP *scip, BINARYVARLIST *list, SCIP_VAR *vartoadd)
#define level2resultPrint(scip, result)
static SCIP_Bool level2resultEqual(LEVEL2RESULT *result1, LEVEL2RESULT *result2)
static SCIP_Real calculateScore(SCIP *scip, CONFIGURATION *config, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval, SCIP_Real baselpobjval)
static SCIP_DECL_BRANCHCOPY(branchCopyLookahead)
static SCIP_RETCODE usePreviousResult(SCIP *scip, SCIP_BRANCHRULEDATA *branchruledata, SCIP_RESULT *result)
static SCIP_RETCODE level2resultCreateFromData(SCIP *scip, LEVEL2DATA *data, LEVEL2RESULT **result)
static SCIP_RETCODE candidateListKeep(SCIP *scip, CANDIDATELIST *candidatelist, int nindices)
static SCIP_RETCODE filterCandidates(SCIP *scip, STATUS *status, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, CANDIDATELIST *candidatelist, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, LEVEL2DATA *level2data, SCIP_Real lpobjval)
#define DEFAULT_APPLYCHILDBOUNDS
static SCIP_Real calculateScoreFromResult2(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
static SCIP_RETCODE initBranchruleData(SCIP *scip, SCIP_BRANCHRULEDATA *branchruledata)
#define DEFAULT_MINWEIGHT
static int findInsertionPoint(SCIP *scip, SCORECONTAINER *scorecontainer, SCIP_Real scoretoinsert, CANDIDATE **candidates, int ncandidates)
static SCIP_RETCODE candidateFree(SCIP *scip, CANDIDATE **candidate)
static SCIP_RETCODE candidateListGetAllFractionalCandidates(SCIP *scip, CANDIDATELIST **candidatelist)
#define DEFAULT_ADDBINCONSROW
static SCIP_RETCODE selectVarRecursive(SCIP *scip, STATUS *status, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, CANDIDATELIST *candidatelist, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, LEVEL2DATA *level2data, int recursiondepth, SCIP_Real lpobjval, SCIP_Real baselpobjval, SCIP_Longint *niterations, int *ndeepestcutoffs, SCIP_Real *bestgain, SCIP_Real *totalgains, int *ntotalgains, int *ndeepestnodes)
static void binaryVarListFree(SCIP *scip, BINARYVARLIST **list)
static SCIP_RETCODE getNIterationsLastLP(SCIP *scip, SCIP_Longint *iterations)
static SCIP_RETCODE binConsDataCreate(SCIP *scip, BINCONSDATA **consdata, int maxdepth, int nstartcons)
static SCIP_RETCODE candidateStoreWarmStartInfo(SCIP *scip, CANDIDATE *candidate, SCIP_Bool down)
#define DEFAULT_LEVEL2AVGSCORE
static SCIP_RETCODE branchOnVar(SCIP *scip, CONFIGURATION *config, BRANCHINGDECISION *decision)
static void statusFree(SCIP *scip, STATUS **status)
static SCIP_RETCODE level2dataCreate(SCIP *scip, LEVEL2DATA **data)
static void applyDeeperDomainReductions(SCIP *scip, SCIP_SOL *baselpsol, int maxstoredomreds, DOMAINREDUCTIONS *targetdomreds, DOMAINREDUCTIONS *downdomreds, DOMAINREDUCTIONS *updomreds)
static void level2dataFree(SCIP *scip, LEVEL2DATA **data)
static SCIP_Bool isUseOldBranching(SCIP *scip, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_VAR *branchvar)
static SCIP_DECL_BRANCHEXITSOL(branchExitSolLookahead)
static void addUpperBound(SCIP *scip, SCIP_VAR *var, SCIP_Real upperbound, SCIP_SOL *baselpsol, SCIP_Bool simplechange, DOMAINREDUCTIONS *domainreductions)
static SCIP_RETCODE freePersistent(SCIP *scip, SCIP_BRANCHRULEDATA *branchruledata)
static void branchingDecisionFree(SCIP *scip, BRANCHINGDECISION **decision)
static SCIP_RETCODE level2dataGetResult(SCIP *scip, LEVEL2DATA *data, LEVEL2RESULT **result)
static SCIP_RETCODE candidateFreeWarmStartInfo(SCIP *scip, CANDIDATE *candidate)
static SCIP_Real calculateScoreFromDeeperscore(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult)
static void branchingDecisionCopy(BRANCHINGDECISION *sourcedecision, BRANCHINGDECISION *targetdecision)
SCIP_RETCODE SCIPincludeBranchruleLookahead(SCIP *scip)
static SCIP_RETCODE scoreContainerSetScore(SCIP *scip, SCORECONTAINER *scorecontainer, CANDIDATE *cand, SCIP_Real score, SCIP_Real downgain, SCIP_Real upgain)
#define DEFAULT_REUSEBASIS
static void constraintListFree(SCIP *scip, CONSTRAINTLIST **conslist)
static SCIP_RETCODE addBinaryConstraint(SCIP *scip, CONFIGURATION *config, BINCONSDATA *binconsdata, SCIP_SOL *baselpsol)
#define DEFAULT_RECURSIONDEPTH
static SCIP_RETCODE candidateListFree(SCIP *scip, CANDIDATELIST **candidatelist)
static SCIP_Real calculateWeightedCutoffScore(CONFIGURATION *config, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult)
#define DEFAULT_USEDOMAINREDUCTION
static SCIP_RETCODE warmStartInfoCreate(SCIP *scip, WARMSTARTINFO **warmstartinfo)
static SCIP_Bool isStoreDecision(CONFIGURATION *config, BINCONSDATA *binconsdata, DOMAINREDUCTIONS *domainreductions)
#define DEFAULT_MAXNVIOLATEDCONS
static void applySingleDeeperDomainReductions(SCIP *scip, SCIP_SOL *baselpsol, int maxstoredomreds, DOMAINREDUCTIONS *targetdomreds, DOMAINREDUCTIONS *domreds)
static CANDIDATE * scoreContainerUpdateSortOrder(SCORECONTAINER *scorecontainer, CANDIDATE *candidate, int insertpoint)
static SCIP_RETCODE constraintListAppend(SCIP *scip, CONSTRAINTLIST *list, SCIP_VAR **consvars, int nconsvars, SCIP_Bool violated)
static SCIP_RETCODE binaryVarListCreate(SCIP *scip, BINARYVARLIST **list, int startsize)
static SCIP_RETCODE createBinaryConstraint(SCIP *scip, CONFIGURATION *config, SCIP_CONS **constraint, char *constraintname, SCIP_VAR **consvars, int nconsvars)
static SCIP_Bool candidateHasWarmStartInfo(CANDIDATE *candidate, SCIP_Bool down)
#define DEFAULT_SCORINGSCORINGFUNCTION
static void branchingResultDataFree(SCIP *scip, BRANCHINGRESULTDATA **resultdata)
#define LABdebugMessage(scip, lvl,...)
static SCIP_RETCODE updateOldBranching(SCIP *scip, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_VAR *branchvar, SCIP_Real branchval, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
#define DEFAULT_STOREUNVIOLATEDSOL
static SCIP_Bool isCurrentNodeCutoff(SCIP *scip)
#define DEFAULT_WORSEFACTOR
#define DEFAULT_MAXNVIOLATEDBINCONS
static SCIP_RETCODE level2dataStoreResult(SCIP *scip, LEVEL2DATA *data, SCIP_Real lpobjval, SCIP_Bool cutoff, SCIP_Bool valid, SCIP_Bool *duplicate)
#define DEFAULT_ABBREVPSEUDO
#define DEFAULT_PREFERSIMPLEBOUNDS
static SCIP_Real calculateWeightedGain(SCIP *scip, CONFIGURATION *config, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
#define DEFAULT_FILTERBYMAXGAIN
#define DEFAULT_MAXPROPROUNDS
static void branchingResultDataInit(SCIP *scip, BRANCHINGRESULTDATA *resultdata)
static SCIP_Real calculateRelCutoffScore(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
static SCIP_Real calculateCutoffScore(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
static void sortFirstCandidatesByScore(SCIP *scip, CANDIDATELIST *candidatelist, SCORECONTAINER *scorecontainer, int nbestcandidates)
#define BRANCHRULE_MAXDEPTH
#define DEFAULT_ONLYVIOLDOMREDS
static SCIP_RETCODE branchingDecisionCreate(SCIP *scip, BRANCHINGDECISION **decision)
static SCIP_Real calculateScoreFromResult(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
static SCIP_RETCODE getFSBResult(SCIP *scip, STATUS *status, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, CANDIDATELIST *candidatelist, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, LEVEL2DATA *level2data, SCIP_Real lpobjval)
#define DEFAULT_ADDNONVIOCONS
static SCIP_Bool branchingDecisionIsValid(BRANCHINGDECISION *decision)
#define BRANCHRULE_MAXBOUNDDIST
static void branchingDecisionInit(SCIP *scip, BRANCHINGDECISION *decision)
static SCIP_RETCODE candidateLoadWarmStartInfo(SCIP *scip, CANDIDATE *candidate, SCIP_Bool down)
#define DEFAULT_MAXNVIOLATEDDOMREDS
#define DEFAULT_LEVEL2ZEROSCORE
#define DEFAULT_MAXNCANDS
lookahead LP branching rule
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_MAXTREEDEPTH
Definition: def.h:297
#define SCIP_Shortbool
Definition: def.h:99
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIPABORT()
Definition: def.h:327
#define SCIP_LONGINT_MAX
Definition: def.h:142
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2569
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
int SCIPgetNContImplVars(SCIP *scip)
Definition: scip_prob.c:2522
SCIP_RETCODE SCIPlpiFreeNorms(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPINORMS **lpinorms)
Definition: lpi_clp.cpp:3651
SCIP_Bool SCIPlpiIsPrimalFeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2549
SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2637
SCIP_RETCODE SCIPlpiGetNorms(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPINORMS **lpinorms)
Definition: lpi_clp.cpp:3620
SCIP_RETCODE SCIPlpiFreeState(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPISTATE **lpistate)
Definition: lpi_clp.cpp:3531
SCIP_RETCODE SCIPlpiGetIterations(SCIP_LPI *lpi, int *iterations)
Definition: lpi_clp.cpp:2949
SCIP_RETCODE SCIPlpiGetState(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPISTATE **lpistate)
Definition: lpi_clp.cpp:3417
SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
Definition: scip_prob.c:4354
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:4289
SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip_prob.c:3901
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
Definition: scip_param.c:250
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:111
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:167
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
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:57
SCIP_RETCODE SCIPsetBranchruleExit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXIT((*branchexit)))
Definition: scip_branch.c:208
SCIP_RETCODE SCIPsetBranchruleExecLp(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECLP((*branchexeclp)))
Definition: scip_branch.c:256
SCIP_RETCODE SCIPsetBranchruleCopy(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHCOPY((*branchcopy)))
Definition: scip_branch.c:160
SCIP_RETCODE SCIPincludeBranchruleBasic(SCIP *scip, SCIP_BRANCHRULE **branchruleptr, const char *name, const char *desc, int priority, int maxdepth, SCIP_Real maxbounddist, SCIP_BRANCHRULEDATA *branchruledata)
Definition: scip_branch.c:123
const char * SCIPbranchruleGetName(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:2018
SCIP_BRANCHRULEDATA * SCIPbranchruleGetData(SCIP_BRANCHRULE *branchrule)
Definition: branch.c:1886
SCIP_RETCODE SCIPsetBranchruleFree(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHFREE((*branchfree)))
Definition: scip_branch.c:176
SCIP_RETCODE SCIPsetBranchruleExitsol(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXITSOL((*branchexitsol)))
Definition: scip_branch.c:240
SCIP_RETCODE SCIPsetBranchruleInit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHINIT((*branchinit)))
Definition: scip_branch.c:192
void SCIPbranchruleSetData(SCIP_BRANCHRULE *branchrule, SCIP_BRANCHRULEDATA *branchruledata)
Definition: branch.c:1896
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1134
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:402
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
Definition: scip_branch.c:857
int SCIPgetNPseudoBranchCands(SCIP *scip)
Definition: scip_branch.c:766
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2536
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_Bool SCIPisExact(SCIP *scip)
Definition: scip_exact.c:193
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:632
SCIP_RETCODE SCIPgetLPI(SCIP *scip, SCIP_LPI **lpi)
Definition: scip_lp.c:994
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
SCIP_Bool SCIPallColsInLP(SCIP *scip)
Definition: scip_lp.c:655
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:253
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:134
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip_mem.h:64
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:126
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPallocMemory(scip, ptr)
Definition: scip_mem.h:60
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip_mem.h:80
#define SCIPfreeMemory(scip, ptr)
Definition: scip_mem.h:78
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:122
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
Definition: tree.c:8503
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:8483
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:8523
int SCIPgetProbingDepth(SCIP *scip)
Definition: scip_probing.c:199
SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_probing.c:346
SCIP_RETCODE SCIPsetProbingLPState(SCIP *scip, SCIP_LPISTATE **lpistate, SCIP_LPINORMS **lpinorms, SCIP_Bool primalfeas, SCIP_Bool dualfeas)
Definition: scip_probing.c:882
SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_probing.c:302
SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
Definition: scip_probing.c:581
SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
Definition: scip_probing.c:226
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:98
SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
Definition: scip_probing.c:166
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_probing.c:825
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:608
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1506
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_Longint SCIPgetNNodeZeroIterationLPs(SCIP *scip)
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_Longint SCIPgetNTotalNodes(SCIP *scip)
SCIP_Longint SCIPgetNNodeLPIterations(SCIP *scip)
SCIP_Longint SCIPgetNLPs(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Longint SCIPgetNNodeLPs(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisRelGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPsumepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisSumLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetCutoffdepth(SCIP *scip)
Definition: scip_tree.c:498
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:91
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6401
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip_var.c:8882
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: scip_var.c:11350
SCIP_RETCODE SCIPendStrongbranch(SCIP *scip)
Definition: scip_var.c:3488
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_RETCODE SCIPchgVarUbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:6088
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6651
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:23662
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Longint SCIPgetVarStrongbranchNode(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:5019
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:5634
SCIP_Longint SCIPgetVarStrongbranchLPAge(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:5053
SCIP_RETCODE SCIPsetVarStrongbranchData(SCIP *scip, SCIP_VAR *var, SCIP_Real lpobjval, SCIP_Real primsol, SCIP_Real down, SCIP_Real up, SCIP_Bool downvalid, SCIP_Bool upvalid, SCIP_Longint iter, int itlim)
Definition: scip_var.c:4903
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip_var.c:11188
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:5570
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:2166
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_RETCODE SCIPupdateVarPseudocost(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta, SCIP_Real objdelta, SCIP_Real weight)
Definition: scip_var.c:11122
SCIP_RETCODE SCIPchgVarLbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:6044
SCIP_RETCODE SCIPtryStrongbranchLPSol(SCIP *scip, SCIP_Bool *foundsol, SCIP_Bool *cutoff)
Definition: scip_var.c:4938
SCIP_RETCODE SCIPgetVarStrongbranchLast(SCIP *scip, SCIP_VAR *var, SCIP_Real *down, SCIP_Real *up, SCIP_Bool *downvalid, SCIP_Bool *upvalid, SCIP_Real *solval, SCIP_Real *lpobjval)
Definition: scip_var.c:4869
SCIP_Bool SCIPisStrongbranchDownFirst(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:3399
void SCIPenableVarHistory(SCIP *scip)
Definition: scip_var.c:11083
SCIP_RETCODE SCIPstartStrongbranch(SCIP *scip, SCIP_Bool enablepropagation)
Definition: scip_var.c:3430
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10827
interface methods for specific LP solvers
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:437
public methods for branching rules
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPstatistic(x)
Definition: pub_message.h:120
public data structures and miscellaneous methods
public methods for branch and bound tree
public methods for problem variables
public methods for branching rule plugins and branching
public methods for constraint handler plugins and constraints
public methods for exact solving
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
Definition: sepa_flower.c:1221
SCIP_VAR ** binaryvars
CONSTRAINTLIST * conslist
BINARYVARLIST * binaryvars
SCIP_Real * downlowerbounds
SCIP_Real * upupperbounds
SCIP_Real * uplowerbounds
SCIP_Real * downupperbounds
SCIP_Longint niterations
CANDIDATE ** candidates
SCIP_Real fracval
WARMSTARTINFO * downwarmstartinfo
SCIP_VAR * branchvar
SCIP_Real branchval
WARMSTARTINFO * upwarmstartinfo
SCIP_Bool usebincons
SCIP_Bool applychildbounds
SCIP_Bool usedomainreduction
SCIP_Bool storeunviolatedsol
SCIP_Bool level2avgscore
SCIP_Real worsefactor
SCIP_Longint reevalagefsb
SCIP_Bool abbrevpseudo
SCIP_Bool mergedomainreductions
SCIP_Bool uselevel2data
SCIP_Longint reevalage
SCIP_Bool addnonviocons
SCIP_Bool onlyvioldomreds
SCIP_Bool reusebasis
SCIP_Bool prefersimplebounds
SCIP_Bool abbreviated
SCIP_Bool enforcemaxdomreds
SCIP_Bool updatebranchingresults
SCIP_Bool level2zeroscore
SCIP_Bool filterbymaxgain
SCIP_VAR *** consvars
SCIP_Bool * violated
SCIP_Shortbool * baselpviolated
SCIP_Real * lowerbounds
SCIP_Real * upperbounds
unsigned int branchvar1
unsigned int branchdir2
unsigned int branchdir1
LEVEL2RESULT ** level2results
SCIP_Real branchval2
SCIP_Real branchval1
unsigned int branchvar2
unsigned int branchdir1
unsigned int branchdir2
unsigned int valid
unsigned int cutoff
SCIP_Real lpobjval
unsigned int branchvar1
SCIP_Real branchval1
unsigned int branchvar2
SCIP_Real branchval2
SCIP_Longint * lastbranchid
SCIP_Longint oldnnodelpiterations
SCIP_Longint * lastbranchnlps
BRANCHINGDECISION * olddecision
SCIP_Real * lastbranchlpobjval
SCIP_Longint oldntotalnodes
SCIP_Longint oldnnodelps
BRANCHINGRESULTDATA ** lastbranchdownres
BRANCHINGRESULTDATA ** lastbranchupres
SCIP_Real * scores
SCIP_Real * downgains
SCIP_Real * upgains
CANDIDATE ** bestsortedcands
SCIP_Bool limitreached
SCIP_Bool domredcutoff
SCIP_Bool addedbinconss
SCIP_Bool cutoff
SCIP_Bool lperror
SCIP_Bool domred
SCIP_Bool maxnconsreached
SCIP_Bool depthtoosmall
SCIP_LPISTATE * lpistate
SCIP_Bool dualfeas
SCIP_LPINORMS * lpinorms
SCIP_Bool primalfeas
struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
Definition: type_branch.h:57
@ SCIP_BRANCHDIR_DOWNWARDS
Definition: type_history.h:43
@ SCIP_BRANCHDIR_UPWARDS
Definition: type_history.h:44
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:52
@ SCIP_LPSOLSTAT_NOTSOLVED
Definition: type_lp.h:43
@ SCIP_LPSOLSTAT_TIMELIMIT
Definition: type_lp.h:49
@ SCIP_LPSOLSTAT_UNBOUNDEDRAY
Definition: type_lp.h:46
@ SCIP_LPSOLSTAT_INFEASIBLE
Definition: type_lp.h:45
@ SCIP_LPSOLSTAT_ITERLIMIT
Definition: type_lp.h:48
enum SCIP_VerbLevel SCIP_VERBLEVEL
Definition: type_message.h:64
@ SCIP_VERBLEVEL_HIGH
Definition: type_message.h:61
@ SCIP_VERBLEVEL_NORMAL
Definition: type_message.h:60
@ SCIP_VERBLEVEL_FULL
Definition: type_message.h:62
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_DELAYED
Definition: type_result.h:43
@ SCIP_REDUCEDDOM
Definition: type_result.h:51
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_CONSCHANGED
Definition: type_result.h:53
@ SCIP_CONSADDED
Definition: type_result.h:52
@ SCIP_UNBOUNDED
Definition: type_result.h:47
@ SCIP_FOUNDSOL
Definition: type_result.h:56
@ SCIP_SUSPENDED
Definition: type_result.h:57
@ SCIP_BRANCHED
Definition: type_result.h:54
@ SCIP_SEPARATED
Definition: type_result.h:49
@ SCIP_SOLVELP
Definition: type_result.h:55
@ SCIP_NEWROUND
Definition: type_result.h:50
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_DELAYNODE
Definition: type_result.h:59
@ SCIP_INFEASIBLE
Definition: type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:64