SCIP

    Solving Constraint Integer Programs

    branch_leastinf.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file branch_leastinf.c
    26 * @ingroup DEFPLUGINS_BRANCH
    27 * @brief least infeasible LP branching rule
    28 * @author Tobias Achterberg
    29 * @author Stefan Vigerske
    30 */
    31
    32/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    33
    35#include "scip/pub_branch.h"
    36#include "scip/pub_message.h"
    37#include "scip/pub_var.h"
    38#include "scip/scip_branch.h"
    39#include "scip/scip_message.h"
    40#include "scip/scip_numerics.h"
    41#include "scip/scip_var.h"
    42
    43
    44#define BRANCHRULE_NAME "leastinf"
    45#define BRANCHRULE_DESC "least infeasible branching"
    46#define BRANCHRULE_PRIORITY 50
    47#define BRANCHRULE_MAXDEPTH -1
    48#define BRANCHRULE_MAXBOUNDDIST 1.0
    49
    50/*
    51 * Local methods
    52 */
    53
    54/** compares the so far best branching candidate with a new candidate and updates best candidate, if new candidate is better */
    55static
    57 SCIP* scip, /**< SCIP data structure */
    58 SCIP_VAR** bestvar, /**< best branching candidate */
    59 SCIP_Real* bestscore, /**< score of best branching candidate */
    60 SCIP_Real* bestobj, /**< absolute objective value of best branching candidate */
    61 SCIP_Real* bestsol, /**< proposed branching point of best branching candidate */
    62 SCIP_VAR* cand, /**< branching candidate to consider */
    63 SCIP_Real candscore, /**< scoring of branching candidate */
    64 SCIP_Real candsol /**< proposed branching point of branching candidate */
    65 )
    66{
    67 SCIP_Real obj;
    68
    69 assert(scip != NULL);
    70 assert(bestvar != NULL);
    71 assert(bestscore != NULL);
    72 assert(bestobj != NULL);
    73 assert(*bestobj >= 0.0);
    74 assert(cand != NULL);
    75
    76 /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */
    77 assert(SCIPvarIsActive(SCIPvarGetProbvar(cand)) ||
    79
    81 {
    82 /* for a multi-aggregated variable, we call updateBestCandidate function recursively with all variables in the multi-aggregation */
    83 SCIP_VAR** multvars;
    84 int nmultvars;
    85 int i;
    86 SCIP_Bool success;
    87 SCIP_Real multvarlb;
    88 SCIP_Real multvarub;
    89
    90 cand = SCIPvarGetProbvar(cand);
    91 multvars = SCIPvarGetMultaggrVars(cand);
    92 nmultvars = SCIPvarGetMultaggrNVars(cand);
    93
    94 /* if we have a candidate branching point, then first register only aggregation variables
    95 * for which we can compute a corresponding branching point too (see also comments below)
    96 * if this fails, then register all (unfixed) aggregation variables, thereby forgetting about candsol
    97 */
    98 success = FALSE;
    99 if( candsol != SCIP_INVALID ) /*lint !e777*/
    100 {
    101 SCIP_Real* multscalars;
    102 SCIP_Real minact;
    103 SCIP_Real maxact;
    104 SCIP_Real aggrvarsol;
    105 SCIP_Real aggrvarsol1;
    106 SCIP_Real aggrvarsol2;
    107
    108 multscalars = SCIPvarGetMultaggrScalars(cand);
    109
    110 /* for computing the branching point, we need the current bounds of the multi-aggregated variable */
    111 minact = SCIPcomputeVarLbLocal(scip, cand);
    112 maxact = SCIPcomputeVarUbLocal(scip, cand);
    113
    114 for( i = 0; i < nmultvars; ++i )
    115 {
    116 /* skip fixed variables */
    117 multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]);
    118 multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]);
    119 if( SCIPisEQ(scip, multvarlb, multvarub) )
    120 continue;
    121
    122 assert(multscalars != NULL);
    123 assert(multscalars[i] != 0.0);
    124
    125 /* we cannot ensure that both the upper bound in the left node and the lower bound in the right node
    126 * will be candsol by a clever choice for the branching point of multvars[i],
    127 * but we can try to ensure that at least one of them will be at candsol
    128 */
    129 if( multscalars[i] > 0.0 )
    130 {
    131 /* cand >= candsol
    132 * if multvars[i] >= (candsol - (maxact - multscalars[i] * ub(multvars[i]))) / multscalars[i]
    133 * = (candsol - maxact) / multscalars[i] + ub(multvars[i])
    134 */
    135 aggrvarsol1 = (candsol - maxact) / multscalars[i] + multvarub;
    136
    137 /* cand <= candsol
    138 * if multvars[i] <= (candsol - (minact - multscalar[i] * lb(multvars[i]))) / multscalars[i]
    139 * = (candsol - minact) / multscalars[i] + lb(multvars[i])
    140 */
    141 aggrvarsol2 = (candsol - minact) / multscalars[i] + multvarlb;
    142 }
    143 else
    144 {
    145 /* cand >= candsol
    146 * if multvars[i] <= (candsol - (maxact - multscalars[i] * lb(multvars[i]))) / multscalars[i]
    147 * = (candsol - maxact) / multscalars[i] + lb(multvars[i])
    148 */
    149 aggrvarsol2 = (candsol - maxact) / multscalars[i] + multvarlb;
    150
    151 /* cand <= candsol
    152 * if multvars[i] >= (candsol - (minact - multscalar[i] * ub(multvars[i]))) / multscalars[i]
    153 * = (candsol - minact) / multscalars[i] + ub(multvars[i])
    154 */
    155 aggrvarsol1 = (candsol - minact) / multscalars[i] + multvarub;
    156 }
    157
    158 /* by the above choice, aggrvarsol1 <= ub(multvars[i]) and aggrvarsol2 >= lb(multvars[i])
    159 * if aggrvarsol1 <= lb(multvars[i]) or aggrvarsol2 >= ub(multvars[i]), then choose the other one
    160 * if both are out of bounds, then give up
    161 * if both are inside bounds, then choose the one closer to 0.0 (someone has better idea???)
    162 */
    163 if( SCIPisFeasLE(scip, aggrvarsol1, multvarlb) )
    164 {
    165 if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) )
    166 continue;
    167 else
    168 aggrvarsol = aggrvarsol2;
    169 }
    170 else
    171 {
    172 if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) )
    173 aggrvarsol = aggrvarsol1;
    174 else
    175 aggrvarsol = REALABS(aggrvarsol1) < REALABS(aggrvarsol2) ? aggrvarsol1 : aggrvarsol2;
    176 }
    177 success = TRUE;
    178
    179 updateBestCandidate(scip, bestvar, bestscore, bestobj, bestsol,
    180 multvars[i], candscore, aggrvarsol);
    181 }
    182 }
    183
    184 if( !success )
    185 for( i = 0; i < nmultvars; ++i )
    186 {
    187 /* skip fixed variables */
    188 multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]);
    189 multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]);
    190 if( SCIPisEQ(scip, multvarlb, multvarub) )
    191 continue;
    192
    193 updateBestCandidate(scip, bestvar, bestscore, bestobj, bestsol,
    194 multvars[i], candscore, SCIP_INVALID);
    195 }
    196
    197 assert(*bestvar != NULL); /* if all variables were fixed, something is strange */
    198
    199 return;
    200 }
    201
    202 candscore *= SCIPvarGetBranchFactor(cand);
    203 obj = SCIPvarGetObj(cand);
    204 obj = REALABS(obj);
    205 if( SCIPisInfinity(scip, *bestscore)
    206 || (!SCIPisInfinity(scip, candscore) &&
    207 (SCIPisLT(scip, candscore, *bestscore) || (SCIPisLE(scip, candscore, *bestscore) && obj > *bestobj))) )
    208 {
    209 *bestvar = cand;
    210 *bestscore = candscore;
    211 *bestobj = obj;
    212 *bestsol = candsol;
    213 }
    214}
    215
    216/*
    217 * Callback methods
    218 */
    219
    220/** copy method for branchrule plugins (called when SCIP copies plugins) */
    221static
    222SCIP_DECL_BRANCHCOPY(branchCopyLeastinf)
    223{ /*lint --e{715}*/
    224 assert(scip != NULL);
    225 assert(branchrule != NULL);
    226
    228
    229 /* call inclusion method of branchrule */
    231
    232 return SCIP_OKAY;
    233}
    234
    235
    236/** branching execution method for fractional LP solutions */
    237static
    238SCIP_DECL_BRANCHEXECLP(branchExeclpLeastinf)
    239{ /*lint --e{715}*/
    240 SCIP_VAR** lpcands;
    241 SCIP_Real* lpcandsfrac;
    242 int nlpcands;
    243 SCIP_Real infeasibility;
    244 SCIP_Real score;
    245 SCIP_Real obj;
    246 SCIP_Real bestscore;
    247 SCIP_Real bestobj;
    248 int bestcand;
    249 int i;
    250
    251 assert(branchrule != NULL);
    252 assert(scip != NULL);
    253 assert(result != NULL);
    254
    256
    257 SCIPdebugMsg(scip, "Execlp method of leastinf branching\n");
    258
    259 /* get branching candidates */
    260 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, NULL, &nlpcands, NULL) );
    261 assert(nlpcands > 0);
    262
    263 /* search the least infeasible candidate */
    264 bestscore = SCIP_REAL_MIN;
    265 bestobj = 0.0;
    266 bestcand = -1;
    267 for( i = 0; i < nlpcands; ++i )
    268 {
    269 assert(lpcands[i] != NULL);
    270
    271 infeasibility = lpcandsfrac[i];
    272 infeasibility = MIN(infeasibility, 1.0-infeasibility);
    273 score = 1.0 - infeasibility;
    274 score *= SCIPvarGetBranchFactor(lpcands[i]);
    275 obj = SCIPvarGetObj(lpcands[i]);
    276 obj = REALABS(obj);
    277 if( SCIPisGT(scip, score, bestscore)
    278 || (SCIPisGE(scip, score, bestscore) && obj > bestobj) )
    279 {
    280 bestscore = score;
    281 bestobj = obj;
    282 bestcand = i;
    283 }
    284 }
    285 assert(bestcand >= 0);
    286
    287 SCIPdebugMsg(scip, " -> %d candidates, selected candidate %d: variable <%s> (frac=%g, obj=%g, factor=%g, score=%g)\n",
    288 nlpcands, bestcand, SCIPvarGetName(lpcands[bestcand]), lpcandsfrac[bestcand], bestobj,
    289 SCIPvarGetBranchFactor(lpcands[bestcand]), bestscore);
    290
    291 /* perform the branching */
    292 SCIP_CALL( SCIPbranchVar(scip, lpcands[bestcand], NULL, NULL, NULL) );
    293 *result = SCIP_BRANCHED;
    294
    295 return SCIP_OKAY;
    296}
    297
    298
    299/** branching execution method for external candidates */
    300static
    301SCIP_DECL_BRANCHEXECEXT(branchExecextLeastinf)
    302{ /*lint --e{715}*/
    303 SCIP_VAR** externcands;
    304 SCIP_Real* externcandssol;
    305 SCIP_Real* externcandsscore;
    306 int nexterncands;
    307 SCIP_VAR* bestcand;
    308 SCIP_Real bestscore;
    309 SCIP_Real bestobj;
    310 SCIP_Real bestsol;
    311 SCIP_Real brpoint;
    312 int i;
    313 SCIP_NODE* downchild;
    314 SCIP_NODE* eqchild;
    315 SCIP_NODE* upchild;
    316
    317 assert(branchrule != NULL);
    318 assert(scip != NULL);
    319 assert(result != NULL);
    320
    322
    323 SCIPdebugMsg(scip, "Execext method of leastinf branching\n");
    324
    325 /* get branching candidates */
    326 SCIP_CALL( SCIPgetExternBranchCands(scip, &externcands, &externcandssol, &externcandsscore, NULL, &nexterncands, NULL, NULL, NULL) );
    327 assert(nexterncands > 0);
    328
    329 /* search the least infeasible candidate */
    330 bestscore = SCIPinfinity(scip);
    331 bestobj = 0.0;
    332 bestcand = NULL;
    333 bestsol = SCIP_INVALID;
    334 for( i = 0; i < nexterncands; ++i )
    335 {
    336 updateBestCandidate(scip, &bestcand, &bestscore, &bestobj, &bestsol, externcands[i], externcandsscore[i], externcandssol[i]);
    337 }
    338
    339 if( bestcand == NULL )
    340 {
    341 SCIPerrorMessage("branchExecextLeastinf failed to select a branching variable from %d candidates\n", nexterncands);
    342 *result = SCIP_DIDNOTRUN;
    343 return SCIP_OKAY;
    344 }
    345
    346 brpoint = SCIPgetBranchingPoint(scip, bestcand, bestsol);
    347
    348 SCIPdebugMsg(scip, " -> %d candidates, selected variable <%s> (infeas=%g, obj=%g, factor=%g, score=%g), branching point=%g\n",
    349 nexterncands, SCIPvarGetName(bestcand), bestsol, bestobj,
    350 SCIPvarGetBranchFactor(bestcand), bestscore, brpoint);
    351
    352 /* perform the branching */
    353 SCIP_CALL( SCIPbranchVarVal(scip, bestcand, brpoint, &downchild, &eqchild, &upchild) );
    354
    355 if( downchild != NULL || eqchild != NULL || upchild != NULL )
    356 {
    357 *result = SCIP_BRANCHED;
    358 }
    359 else
    360 {
    361 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
    362 assert(SCIPisEQ(scip, SCIPvarGetLbLocal(bestcand), SCIPvarGetUbLocal(bestcand)));
    363 *result = SCIP_REDUCEDDOM;
    364 }
    365
    366 return SCIP_OKAY;
    367}
    368
    369
    370/*
    371 * branching specific interface methods
    372 */
    373
    374/** creates the least infeasible LP branching rule and includes it in SCIP */
    376 SCIP* scip /**< SCIP data structure */
    377 )
    378{
    379 SCIP_BRANCHRULE* branchrule;
    380
    381 /* include branching rule */
    382 branchrule = NULL;
    385 assert(branchrule != NULL);
    386
    387 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyLeastinf) );
    388 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpLeastinf) );
    389 SCIP_CALL( SCIPsetBranchruleExecExt(scip, branchrule, branchExecextLeastinf) );
    390
    391 return SCIP_OKAY;
    392}
    #define BRANCHRULE_DESC
    #define BRANCHRULE_PRIORITY
    static SCIP_DECL_BRANCHEXECLP(branchExeclpLeastinf)
    #define BRANCHRULE_NAME
    static void updateBestCandidate(SCIP *scip, SCIP_VAR **bestvar, SCIP_Real *bestscore, SCIP_Real *bestobj, SCIP_Real *bestsol, SCIP_VAR *cand, SCIP_Real candscore, SCIP_Real candsol)
    static SCIP_DECL_BRANCHEXECEXT(branchExecextLeastinf)
    static SCIP_DECL_BRANCHCOPY(branchCopyLeastinf)
    #define BRANCHRULE_MAXDEPTH
    #define BRANCHRULE_MAXBOUNDDIST
    least infeasible LP branching rule
    #define NULL
    Definition: def.h:257
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define SCIP_REAL_MIN
    Definition: def.h:168
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_RETCODE SCIPincludeBranchruleLeastinf(SCIP *scip)
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPsetBranchruleExecExt(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECEXT((*branchexecext)))
    Definition: scip_branch.c:272
    SCIP_RETCODE SCIPsetBranchruleExecLp(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECLP((*branchexeclp)))
    Definition: scip_branch.c:256
    SCIP_RETCODE SCIPsetBranchruleCopy(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHCOPY((*branchcopy)))
    Definition: scip_branch.c:160
    SCIP_RETCODE SCIPincludeBranchruleBasic(SCIP *scip, SCIP_BRANCHRULE **branchruleptr, const char *name, const char *desc, int priority, int maxdepth, SCIP_Real maxbounddist, SCIP_BRANCHRULEDATA *branchruledata)
    Definition: scip_branch.c:123
    const char * SCIPbranchruleGetName(SCIP_BRANCHRULE *branchrule)
    Definition: branch.c:2018
    SCIP_RETCODE SCIPgetExternBranchCands(SCIP *scip, SCIP_VAR ***externcands, SCIP_Real **externcandssol, SCIP_Real **externcandsscore, int *nexterncands, int *nprioexterncands, int *nprioexternbins, int *nprioexternints, int *nprioexternimpls)
    Definition: scip_branch.c:519
    SCIP_Real SCIPgetBranchingPoint(SCIP *scip, SCIP_VAR *var, SCIP_Real suggestion)
    Definition: scip_branch.c:905
    SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
    Definition: scip_branch.c:1134
    SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
    Definition: scip_branch.c:402
    SCIP_RETCODE SCIPbranchVar(SCIP *scip, SCIP_VAR *var, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
    Definition: scip_branch.c:1058
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23674
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23418
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
    Definition: var.c:17595
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Real SCIPvarGetBranchFactor(SCIP_VAR *var)
    Definition: var.c:24482
    SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
    Definition: var.c:23838
    int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
    Definition: var.c:23826
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Real SCIPcomputeVarLbLocal(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:8417
    SCIP_Real SCIPcomputeVarUbLocal(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:8462
    SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
    Definition: var.c:23850
    public methods for branching rules
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP variables
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_REDUCEDDOM
    Definition: type_result.h:51
    @ SCIP_BRANCHED
    Definition: type_result.h:54
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_VARSTATUS_MULTAGGR
    Definition: type_var.h:56