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