SCIP

    Solving Constraint Integer Programs

    branch_mostinf.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_mostinf.c
    26 * @ingroup DEFPLUGINS_BRANCH
    27 * @brief most infeasible LP branching rule
    28 * @author Tobias Achterberg
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    33#include "scip/branch_mostinf.h"
    34#include "scip/pub_branch.h"
    35#include "scip/pub_message.h"
    36#include "scip/pub_var.h"
    37#include "scip/scip_branch.h"
    38#include "scip/scip_message.h"
    39#include "scip/scip_numerics.h"
    40#include "scip/scip_var.h"
    41
    42
    43#define BRANCHRULE_NAME "mostinf"
    44#define BRANCHRULE_DESC "most infeasible branching"
    45#define BRANCHRULE_PRIORITY 100
    46#define BRANCHRULE_MAXDEPTH -1
    47#define BRANCHRULE_MAXBOUNDDIST 1.0
    48
    49/*
    50 * Local methods
    51 */
    52
    53/** compares the so far best branching candidate with a new candidate and updates best candidate, if new candidate is better */
    54static
    56 SCIP* scip, /**< SCIP data structure */
    57 SCIP_VAR** bestvar, /**< best branching candidate */
    58 SCIP_Real* bestscore, /**< score of best branching candidate */
    59 SCIP_Real* bestobj, /**< absolute objective value of best branching candidate */
    60 SCIP_Real* bestsol, /**< proposed branching point of best branching candidate */
    61 SCIP_VAR* cand, /**< branching candidate to consider */
    62 SCIP_Real candscore, /**< scoring of branching candidate */
    63 SCIP_Real candsol /**< proposed branching point of branching candidate */
    64 )
    65{
    66 SCIP_Real obj;
    67
    68 assert(scip != NULL);
    69 assert(bestvar != NULL);
    70 assert(bestscore != NULL);
    71 assert(bestobj != NULL);
    72 assert(*bestobj >= 0.0);
    73 assert(cand != NULL);
    74
    75 /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */
    76 assert(SCIPvarIsActive(SCIPvarGetProbvar(cand)) ||
    78
    80 {
    81 /* for a multi-aggregated variable, we call updateBestCandidate function recursively with all variables in the multi-aggregation */
    82 SCIP_VAR** multvars;
    83 int nmultvars;
    84 int i;
    85 SCIP_Bool success;
    86 SCIP_Real multvarlb;
    87 SCIP_Real multvarub;
    88
    89 cand = SCIPvarGetProbvar(cand);
    90 multvars = SCIPvarGetMultaggrVars(cand);
    91 nmultvars = SCIPvarGetMultaggrNVars(cand);
    92
    93 /* if we have a candidate branching point, then first register only aggregation variables
    94 * for which we can compute a corresponding branching point too (see also comments below)
    95 * if this fails, then register all (unfixed) aggregation variables, thereby forgetting about candsol
    96 */
    97 success = FALSE;
    98 if( candsol != SCIP_INVALID ) /*lint !e777*/
    99 {
    100 SCIP_Real* multscalars;
    101 SCIP_Real minact;
    102 SCIP_Real maxact;
    103 SCIP_Real aggrvarsol;
    104 SCIP_Real aggrvarsol1;
    105 SCIP_Real aggrvarsol2;
    106
    107 multscalars = SCIPvarGetMultaggrScalars(cand);
    108
    109 /* for computing the branching point, we need the current bounds of the multi-aggregated variable */
    110 minact = SCIPcomputeVarLbLocal(scip, cand);
    111 maxact = SCIPcomputeVarUbLocal(scip, cand);
    112
    113 for( i = 0; i < nmultvars; ++i )
    114 {
    115 /* skip fixed variables */
    116 multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]);
    117 multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]);
    118 if( SCIPisEQ(scip, multvarlb, multvarub) )
    119 continue;
    120
    121 assert(multscalars != NULL);
    122 assert(multscalars[i] != 0.0);
    123
    124 /* we cannot ensure that both the upper bound in the left node and the lower bound in the right node
    125 * will be candsol by a clever choice for the branching point of multvars[i],
    126 * but we can try to ensure that at least one of them will be at candsol
    127 */
    128 if( multscalars[i] > 0.0 )
    129 {
    130 /* cand >= candsol
    131 * if multvars[i] >= (candsol - (maxact - multscalars[i] * ub(multvars[i]))) / multscalars[i]
    132 * = (candsol - maxact) / multscalars[i] + ub(multvars[i])
    133 */
    134 aggrvarsol1 = (candsol - maxact) / multscalars[i] + multvarub;
    135
    136 /* cand <= candsol
    137 * if multvars[i] <= (candsol - (minact - multscalar[i] * lb(multvars[i]))) / multscalars[i]
    138 * = (candsol - minact) / multscalars[i] + lb(multvars[i])
    139 */
    140 aggrvarsol2 = (candsol - minact) / multscalars[i] + multvarlb;
    141 }
    142 else
    143 {
    144 /* cand >= candsol
    145 * if multvars[i] <= (candsol - (maxact - multscalars[i] * lb(multvars[i]))) / multscalars[i]
    146 * = (candsol - maxact) / multscalars[i] + lb(multvars[i])
    147 */
    148 aggrvarsol2 = (candsol - maxact) / multscalars[i] + multvarlb;
    149
    150 /* cand <= candsol
    151 * if multvars[i] >= (candsol - (minact - multscalar[i] * ub(multvars[i]))) / multscalars[i]
    152 * = (candsol - minact) / multscalars[i] + ub(multvars[i])
    153 */
    154 aggrvarsol1 = (candsol - minact) / multscalars[i] + multvarub;
    155 }
    156
    157 /* by the above choice, aggrvarsol1 <= ub(multvars[i]) and aggrvarsol2 >= lb(multvars[i])
    158 * if aggrvarsol1 <= lb(multvars[i]) or aggrvarsol2 >= ub(multvars[i]), then choose the other one
    159 * if both are out of bounds, then give up
    160 * if both are inside bounds, then choose the one closer to 0.0 (someone has better idea???)
    161 */
    162 if( SCIPisFeasLE(scip, aggrvarsol1, multvarlb) )
    163 {
    164 if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) )
    165 continue;
    166 else
    167 aggrvarsol = aggrvarsol2;
    168 }
    169 else
    170 {
    171 if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) )
    172 aggrvarsol = aggrvarsol1;
    173 else
    174 aggrvarsol = REALABS(aggrvarsol1) < REALABS(aggrvarsol2) ? aggrvarsol1 : aggrvarsol2;
    175 }
    176 success = TRUE;
    177
    178 updateBestCandidate(scip, bestvar, bestscore, bestobj, bestsol,
    179 multvars[i], candscore, aggrvarsol);
    180 }
    181 }
    182
    183 if( !success )
    184 for( i = 0; i < nmultvars; ++i )
    185 {
    186 /* skip fixed variables */
    187 multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]);
    188 multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]);
    189 if( SCIPisEQ(scip, multvarlb, multvarub) )
    190 continue;
    191
    192 updateBestCandidate(scip, bestvar, bestscore, bestobj, bestsol,
    193 multvars[i], candscore, SCIP_INVALID);
    194 }
    195
    196 assert(*bestvar != NULL); /* if all variables were fixed, something is strange */
    197
    198 return;
    199 }
    200
    201 candscore *= SCIPvarGetBranchFactor(cand);
    202 obj = SCIPvarGetObj(cand);
    203 obj = REALABS(obj);
    204 if( SCIPisInfinity(scip, candscore)
    205 || (!SCIPisInfinity(scip, *bestscore) &&
    206 (SCIPisGT(scip, candscore, *bestscore) || (SCIPisGE(scip, candscore, *bestscore) && obj > *bestobj))) )
    207 {
    208 *bestvar = cand;
    209 *bestscore = candscore;
    210 *bestobj = obj;
    211 *bestsol = candsol;
    212 }
    213}
    214
    215/*
    216 * Callback methods
    217 */
    218
    219/** copy method for branchrule plugins (called when SCIP copies plugins) */
    220static
    221SCIP_DECL_BRANCHCOPY(branchCopyMostinf)
    222{ /*lint --e{715}*/
    223 assert(scip != NULL);
    224 assert(branchrule != NULL);
    225
    227
    228 /* call inclusion method of branchrule */
    230
    231 return SCIP_OKAY;
    232}
    233
    234
    235/** branching execution method for fractional LP solutions */
    236static
    237SCIP_DECL_BRANCHEXECLP(branchExeclpMostinf)
    238{ /*lint --e{715}*/
    239 SCIP_VAR** lpcands;
    240 SCIP_Real* lpcandsfrac;
    241 int nlpcands;
    242 SCIP_Real infeasibility;
    243 SCIP_Real score;
    244 SCIP_Real obj;
    245 SCIP_Real bestscore;
    246 SCIP_Real bestobj;
    247 int bestcand;
    248 int i;
    249
    250 assert(branchrule != NULL);
    251 assert(scip != NULL);
    252 assert(result != NULL);
    253
    255
    256 SCIPdebugMsg(scip, "Execlp method of mostinf branching\n");
    257
    258 /* get branching candidates */
    259 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, NULL, &nlpcands, NULL) );
    260 assert(nlpcands > 0);
    261
    262 /* search the most infeasible candidate */
    263 bestscore = SCIP_REAL_MIN;
    264 bestobj = 0.0;
    265 bestcand = -1;
    266 for( i = 0; i < nlpcands; ++i )
    267 {
    268 assert(lpcands[i] != NULL);
    269
    270 infeasibility = lpcandsfrac[i];
    271 infeasibility = MIN(infeasibility, 1.0-infeasibility);
    272 score = infeasibility;
    273 score *= SCIPvarGetBranchFactor(lpcands[i]);
    274 obj = SCIPvarGetObj(lpcands[i]);
    275 obj = REALABS(obj);
    276 if( SCIPisGT(scip, score, bestscore)
    277 || (SCIPisGE(scip, score, bestscore) && obj > bestobj) )
    278 {
    279 bestscore = score;
    280 bestobj = obj;
    281 bestcand = i;
    282 }
    283 }
    284 assert(bestcand >= 0);
    285
    286 SCIPdebugMsg(scip, " -> %d candidates, selected candidate %d: variable <%s> (frac=%g, obj=%g, factor=%g, score=%g)\n",
    287 nlpcands, bestcand, SCIPvarGetName(lpcands[bestcand]), lpcandsfrac[bestcand], bestobj,
    288 SCIPvarGetBranchFactor(lpcands[bestcand]), bestscore);
    289
    290 /* perform the branching */
    291 SCIP_CALL( SCIPbranchVar(scip, lpcands[bestcand], NULL, NULL, NULL) );
    292 *result = SCIP_BRANCHED;
    293
    294 return SCIP_OKAY;
    295}
    296
    297/** branching execution method for external candidates */
    298static
    299SCIP_DECL_BRANCHEXECEXT(branchExecextMostinf)
    300{ /*lint --e{715}*/
    301 SCIP_VAR** externcands;
    302 SCIP_Real* externcandssol;
    303 SCIP_Real* externcandsscore;
    304 int nexterncands;
    305 SCIP_VAR* bestcand;
    306 SCIP_Real bestscore;
    307 SCIP_Real bestobj;
    308 SCIP_Real bestsol;
    309 SCIP_Real brpoint;
    310 int i;
    311 SCIP_NODE* downchild;
    312 SCIP_NODE* eqchild;
    313 SCIP_NODE* upchild;
    314
    315 assert(branchrule != NULL);
    316 assert(scip != NULL);
    317 assert(result != NULL);
    318
    320
    321 SCIPdebugMsg(scip, "Execext method of mostinf branching\n");
    322
    323 /* get branching candidates */
    324 SCIP_CALL( SCIPgetExternBranchCands(scip, &externcands, &externcandssol, &externcandsscore, NULL, &nexterncands, NULL, NULL, NULL) );
    325 assert(nexterncands > 0);
    326
    327 /* search the most infeasible candidate */
    328 bestscore = SCIP_REAL_MIN;
    329 bestobj = 0.0;
    330 bestcand = NULL;
    331 bestsol = SCIP_INVALID;
    332 for( i = 0; i < nexterncands; ++i )
    333 {
    334 updateBestCandidate(scip, &bestcand, &bestscore, &bestobj, &bestsol, externcands[i], externcandsscore[i], externcandssol[i]);
    335 }
    336
    337 if( bestcand == NULL )
    338 {
    339 SCIPerrorMessage("branchExecextMostinf failed to select a branching variable from %d candidates\n", nexterncands);
    340 *result = SCIP_DIDNOTRUN;
    341 return SCIP_OKAY;
    342 }
    343
    344 brpoint = SCIPgetBranchingPoint(scip, bestcand, bestsol);
    345
    346 SCIPdebugMsg(scip, " -> %d candidates, selected variable <%s> (sol=%g, locdom=[%g,%g], obj=%g, factor=%g, score=%g), branching point=%g\n",
    347 nexterncands, SCIPvarGetName(bestcand), bestsol, SCIPvarGetLbLocal(bestcand), SCIPvarGetUbLocal(bestcand), bestobj,
    348 SCIPvarGetBranchFactor(bestcand), bestscore, brpoint);
    349
    350 /* perform the branching */
    351 SCIP_CALL( SCIPbranchVarVal(scip, bestcand, brpoint, &downchild, &eqchild, &upchild) );
    352
    353 if( downchild != NULL || eqchild != NULL || upchild != NULL )
    354 {
    355 *result = SCIP_BRANCHED;
    356 }
    357 else
    358 {
    359 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
    360 assert(SCIPisEQ(scip, SCIPvarGetLbLocal(bestcand), SCIPvarGetUbLocal(bestcand)));
    361 *result = SCIP_REDUCEDDOM;
    362 }
    363
    364 return SCIP_OKAY;
    365}
    366
    367
    368/*
    369 * branching specific interface methods
    370 */
    371
    372/** creates the most infeasible LP branching rule and includes it in SCIP */
    374 SCIP* scip /**< SCIP data structure */
    375 )
    376{
    377 SCIP_BRANCHRULE* branchrule;
    378
    379 /* include branching rule */
    382
    383 assert(branchrule != NULL);
    384
    385 /* set non-fundamental callbacks via specific setter functions*/
    386 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyMostinf) );
    387 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpMostinf) );
    388 SCIP_CALL( SCIPsetBranchruleExecExt(scip, branchrule, branchExecextMostinf) );
    389
    390 return SCIP_OKAY;
    391}
    #define BRANCHRULE_DESC
    #define BRANCHRULE_PRIORITY
    static SCIP_DECL_BRANCHEXECLP(branchExeclpMostinf)
    #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_BRANCHCOPY(branchCopyMostinf)
    static SCIP_DECL_BRANCHEXECEXT(branchExecextMostinf)
    #define BRANCHRULE_MAXDEPTH
    #define BRANCHRULE_MAXBOUNDDIST
    most 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 SCIPincludeBranchruleMostinf(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_Bool SCIPisGE(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 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