SCIP

    Solving Constraint Integer Programs

    heur_fracdiving.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 heur_fracdiving.c
    26 * @ingroup DEFPLUGINS_HEUR
    27 * @brief LP diving heuristic that chooses fixings w.r.t. the fractionalities
    28 * @author Tobias Achterberg
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    34#include "scip/heuristics.h"
    35#include "scip/pub_heur.h"
    36#include "scip/pub_message.h"
    37#include "scip/pub_misc.h"
    38#include "scip/pub_var.h"
    39#include "scip/scip_heur.h"
    40#include "scip/scip_mem.h"
    41#include "scip/scip_numerics.h"
    42#include "scip/scip_prob.h"
    43#include "scip/scip_sol.h"
    44
    45
    46#define HEUR_NAME "fracdiving"
    47#define HEUR_DESC "LP diving heuristic that chooses fixings w.r.t. the fractionalities"
    48#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_DIVING
    49#define HEUR_PRIORITY -1003000
    50#define HEUR_FREQ 10
    51#define HEUR_FREQOFS 3
    52#define HEUR_MAXDEPTH -1
    53#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
    54#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
    55#define DIVESET_DIVETYPES SCIP_DIVETYPE_INTEGRALITY | SCIP_DIVETYPE_SOS1VARIABLE /**< bit mask that represents all supported dive types */
    56#define DIVESET_ISPUBLIC TRUE /**< is this dive set publicly available (ie., can be used by other primal heuristics?) */
    57
    58
    59/*
    60 * Default parameter settings
    61 */
    62
    63#define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
    64#define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
    65#define DEFAULT_MAXLPITERQUOT 0.05 /**< maximal fraction of diving LP iterations compared to node LP iterations */
    66#define DEFAULT_MAXLPITEROFS 1000 /**< additional number of allowed LP iterations */
    67#define DEFAULT_MAXDIVEUBQUOT 0.8 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
    68 * where diving is performed (0.0: no limit) */
    69#define DEFAULT_MAXDIVEAVGQUOT 0.0 /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
    70 * where diving is performed (0.0: no limit) */
    71#define DEFAULT_MAXDIVEUBQUOTNOSOL 0.1 /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
    72#define DEFAULT_MAXDIVEAVGQUOTNOSOL 0.0 /**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
    73#define DEFAULT_BACKTRACK TRUE /**< use one level of backtracking if infeasibility is encountered? */
    74
    75#define DEFAULT_LPRESOLVEDOMCHGQUOT 0.15 /**< percentage of immediate domain changes during probing to trigger LP resolve */
    76#define DEFAULT_LPSOLVEFREQ 0 /**< LP solve frequency for diving heuristics */
    77#define DEFAULT_ONLYLPBRANCHCANDS FALSE /**< should only LP branching candidates be considered instead of the slower but
    78 * more general constraint handler diving variable selection? */
    79#define DEFAULT_RANDSEED 89 /**< initial random seed */
    80
    81/* locally defined heuristic data */
    82struct SCIP_HeurData
    83{
    84 SCIP_SOL* sol; /**< working solution */
    85};
    86
    87
    88/*
    89 * local methods
    90 */
    91
    92/*
    93 * Callback methods
    94 */
    95
    96/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    97static
    98SCIP_DECL_HEURCOPY(heurCopyFracdiving)
    99{ /*lint --e{715}*/
    100 assert(scip != NULL);
    101 assert(heur != NULL);
    102
    104
    105 /* call inclusion method of primal heuristic */
    107
    108 return SCIP_OKAY;
    109}
    110
    111/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    112static
    113SCIP_DECL_HEURFREE(heurFreeFracdiving) /*lint --e{715}*/
    114{ /*lint --e{715}*/
    115 SCIP_HEURDATA* heurdata;
    116
    117 assert(heur != NULL);
    118 assert(scip != NULL);
    119
    121
    122 /* free heuristic data */
    123 heurdata = SCIPheurGetData(heur);
    124 assert(heurdata != NULL);
    125
    126 SCIPfreeBlockMemory(scip, &heurdata);
    127 SCIPheurSetData(heur, NULL);
    128
    129 return SCIP_OKAY;
    130}
    131
    132
    133/** initialization method of primal heuristic (called after problem was transformed) */
    134static
    135SCIP_DECL_HEURINIT(heurInitFracdiving) /*lint --e{715}*/
    136{ /*lint --e{715}*/
    137 SCIP_HEURDATA* heurdata;
    138
    139 assert(heur != NULL);
    140
    142
    143 /* get heuristic data */
    144 heurdata = SCIPheurGetData(heur);
    145 assert(heurdata != NULL);
    146
    147 /* create working solution */
    148 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    149
    150 return SCIP_OKAY;
    151}
    152
    153
    154/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    155static
    156SCIP_DECL_HEUREXIT(heurExitFracdiving) /*lint --e{715}*/
    157{ /*lint --e{715}*/
    158 SCIP_HEURDATA* heurdata;
    159
    160 assert(heur != NULL);
    161
    163
    164 /* get heuristic data */
    165 heurdata = SCIPheurGetData(heur);
    166 assert(heurdata != NULL);
    167
    168 /* free working solution */
    169 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    170
    171 return SCIP_OKAY;
    172}
    173
    174
    175/** execution method of primal heuristic */
    176static
    177SCIP_DECL_HEUREXEC(heurExecFracdiving) /*lint --e{715}*/
    178{ /*lint --e{715}*/
    179 SCIP_HEURDATA* heurdata;
    180 SCIP_DIVESET* diveset;
    181
    182 heurdata = SCIPheurGetData(heur);
    183 assert(heurdata != NULL);
    184
    185 assert(SCIPheurGetNDivesets(heur) > 0);
    186 assert(SCIPheurGetDivesets(heur) != NULL);
    187 diveset = SCIPheurGetDivesets(heur)[0];
    188 assert(diveset != NULL);
    189
    190 *result = SCIP_DIDNOTRUN;
    191
    192 SCIP_CALL( SCIPperformGenericDivingAlgorithm(scip, diveset, heurdata->sol, heur, result, nodeinfeasible, -1L, -1, -1.0, SCIP_DIVECONTEXT_SINGLE) );
    193
    194 return SCIP_OKAY;
    195}
    196
    197/** calculate score and preferred rounding direction for the candidate variable; the best candidate maximizes the
    198 * score
    199 */
    200static
    201SCIP_DECL_DIVESETGETSCORE(divesetGetScoreFracdiving)
    202{
    203 SCIP_Real obj;
    204 SCIP_Real objnorm;
    205 SCIP_Real objgain;
    206 SCIP_Bool mayrounddown;
    207 SCIP_Bool mayroundup;
    208
    209 /* score fractionality if candidate is an SOS1 variable */
    210 if ( divetype == SCIP_DIVETYPE_SOS1VARIABLE )
    211 {
    212 *score = candsfrac;
    213
    214 /* 'round' in nonzero direction, i.e., fix the candidates neighbors in the conflict graph to zero */
    215 *roundup = SCIPisFeasPositive(scip, candsol);
    216
    217 return SCIP_OKAY;
    218 }
    219
    220 mayrounddown = SCIPvarMayRoundDown(cand);
    221 mayroundup = SCIPvarMayRoundUp(cand);
    222
    223 /* choose rounding direction:
    224 * - if variable may be rounded in either both or neither direction, round corresponding to the fractionality
    225 * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
    226 * the current fractional solution
    227 */
    228 if( mayrounddown != mayroundup )
    229 *roundup = mayrounddown;
    230 /* try to avoid variability; decide randomly if the LP solution can contain some noise. */
    231 else if( SCIPisEQ(scip, candsfrac, 0.5) )
    232 *roundup = (SCIPrandomGetInt(SCIPdivesetGetRandnumgen(diveset), 0, 1) == 0);
    233 else
    234 *roundup = (candsfrac > 0.5);
    235
    236 obj = SCIPvarGetObj(cand);
    237 objnorm = SCIPgetObjNorm(scip);
    238
    239 /* divide by objective norm to normalize obj into [-1,1] */
    240 if( SCIPisPositive(scip, objnorm) )
    241 obj /= objnorm;
    242
    243 /* calculate objective gain and fractionality for the selected rounding direction */
    244 if( *roundup )
    245 {
    246 candsfrac = 1.0 - candsfrac;
    247 objgain = obj * candsfrac;
    248 }
    249 else
    250 objgain = -obj * candsfrac;
    251
    252 assert(objgain >= -1.0 && objgain <= 1.0);
    253
    254 /* penalize too small fractions */
    255 if( SCIPisEQ(scip, candsfrac, 0.01) )
    256 {
    257 /* try to avoid variability; decide randomly if the LP solution can contain some noise.
    258 * use a 1:SCIP_PROBINGSCORE_PENALTYRATIO chance for increasing the fractionality, i.e., the score.
    259 */
    261 candsfrac += 10.0;
    262 }
    263 else if( candsfrac < 0.01 )
    264 candsfrac += 10.0;
    265
    266 /* prefer decisions on binary variables */
    267 if( !SCIPvarIsBinary(cand) )
    268 candsfrac *= 1000.0;
    269
    270 /* prefer variables which cannot be rounded by scoring their fractionality */
    271 if( !(mayrounddown || mayroundup) )
    272 *score = -candsfrac;
    273 else
    274 *score = -2.0 - objgain;
    275
    276 return SCIP_OKAY;
    277}
    278
    279#define divesetAvailableFracdiving NULL
    280
    281/*
    282 * heuristic specific interface methods
    283 */
    284
    285/** creates the fracdiving heuristic and includes it in SCIP */
    287 SCIP* scip /**< SCIP data structure */
    288 )
    289{
    290 SCIP_HEURDATA* heurdata;
    291 SCIP_HEUR* heur;
    292
    293 /* create Fracdiving primal heuristic data */
    294 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    295
    296 /* include primal heuristic */
    299 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecFracdiving, heurdata) );
    300
    301 assert(heur != NULL);
    302
    303 /* primal heuristic is safe to use in exact solving mode */
    304 SCIPheurMarkExact(heur);
    305
    306 /* set non-NULL pointers to callback methods */
    307 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyFracdiving) );
    308 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeFracdiving) );
    309 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitFracdiving) );
    310 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitFracdiving) );
    311
    312 /* create a diveset (this will automatically install some additional parameters for the heuristic)*/
    317 DIVESET_ISPUBLIC, DIVESET_DIVETYPES, divesetGetScoreFracdiving, divesetAvailableFracdiving) );
    318
    319 return SCIP_OKAY;
    320}
    321
    #define NULL
    Definition: def.h:257
    #define SCIP_PROBINGSCORE_PENALTYRATIO
    Definition: def.h:312
    #define SCIP_Bool
    Definition: def.h:100
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_Real SCIPgetObjNorm(SCIP *scip)
    Definition: scip_prob.c:1880
    SCIP_RETCODE SCIPincludeHeurFracdiving(SCIP *scip)
    SCIP_RETCODE SCIPcreateDiveset(SCIP *scip, SCIP_DIVESET **diveset, SCIP_HEUR *heur, const char *name, SCIP_Real minreldepth, SCIP_Real maxreldepth, SCIP_Real maxlpiterquot, SCIP_Real maxdiveubquot, SCIP_Real maxdiveavgquot, SCIP_Real maxdiveubquotnosol, SCIP_Real maxdiveavgquotnosol, SCIP_Real lpresolvedomchgquot, int lpsolvefreq, int maxlpiterofs, unsigned int initialseed, SCIP_Bool backtrack, SCIP_Bool onlylpbranchcands, SCIP_Bool ispublic, SCIP_Bool specificsos1score, SCIP_DECL_DIVESETGETSCORE((*divesetgetscore)), SCIP_DECL_DIVESETAVAILABLE((*divesetavailable)))
    Definition: scip_heur.c:323
    SCIP_RANDNUMGEN * SCIPdivesetGetRandnumgen(SCIP_DIVESET *diveset)
    Definition: heur.c:720
    SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
    Definition: scip_heur.c:167
    SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
    Definition: heur.c:1368
    SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, SCIP_HEURTIMING timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
    Definition: scip_heur.c:122
    SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
    Definition: scip_heur.c:183
    SCIP_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXIT((*heurexit)))
    Definition: scip_heur.c:215
    int SCIPheurGetNDivesets(SCIP_HEUR *heur)
    Definition: heur.c:1675
    void SCIPheurMarkExact(SCIP_HEUR *heur)
    Definition: heur.c:1457
    SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
    Definition: scip_heur.c:199
    const char * SCIPheurGetName(SCIP_HEUR *heur)
    Definition: heur.c:1467
    SCIP_DIVESET ** SCIPheurGetDivesets(SCIP_HEUR *heur)
    Definition: heur.c:1665
    void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
    Definition: heur.c:1378
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:514
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1250
    SCIP_RETCODE SCIPperformGenericDivingAlgorithm(SCIP *scip, SCIP_DIVESET *diveset, SCIP_SOL *worksol, SCIP_HEUR *heur, SCIP_RESULT *result, SCIP_Bool nodeinfeasible, SCIP_Longint iterlim, int nodelimit, SCIP_Real lpresolvedomchgquot, SCIP_DIVECONTEXT divecontext)
    Definition: heuristics.c:221
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR *var)
    Definition: var.c:4478
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
    Definition: var.c:4467
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
    Definition: misc.c:10223
    #define DEFAULT_ONLYLPBRANCHCANDS
    static SCIP_DECL_HEURFREE(heurFreeFracdiving)
    static SCIP_DECL_HEUREXEC(heurExecFracdiving)
    #define DEFAULT_MAXDIVEUBQUOT
    #define DEFAULT_LPRESOLVEDOMCHGQUOT
    static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreFracdiving)
    #define HEUR_TIMING
    #define DEFAULT_MAXLPITERQUOT
    #define HEUR_FREQOFS
    static SCIP_DECL_HEUREXIT(heurExitFracdiving)
    #define HEUR_DESC
    #define DEFAULT_MAXDIVEAVGQUOT
    #define DEFAULT_LPSOLVEFREQ
    #define DEFAULT_BACKTRACK
    #define DEFAULT_MAXDIVEUBQUOTNOSOL
    #define HEUR_DISPCHAR
    #define HEUR_MAXDEPTH
    static SCIP_DECL_HEURCOPY(heurCopyFracdiving)
    #define HEUR_PRIORITY
    #define DEFAULT_MAXRELDEPTH
    #define DEFAULT_MAXLPITEROFS
    static SCIP_DECL_HEURINIT(heurInitFracdiving)
    #define DEFAULT_MAXDIVEAVGQUOTNOSOL
    #define HEUR_NAME
    #define DEFAULT_RANDSEED
    #define DIVESET_DIVETYPES
    #define divesetAvailableFracdiving
    #define DIVESET_ISPUBLIC
    #define HEUR_FREQ
    #define DEFAULT_MINRELDEPTH
    #define HEUR_USESSUBSCIP
    LP diving heuristic that chooses fixings w.r.t. the fractionalities.
    methods commonly used by primal heuristics
    public methods for primal heuristics
    public methods for message output
    public data structures and miscellaneous methods
    public methods for problem variables
    public methods for primal heuristic plugins and divesets
    public methods for memory management
    public methods for numerical tolerances
    public methods for global and local (sub)problems
    public methods for solutions
    SCIP_SOL * sol
    Definition: struct_heur.h:71
    struct SCIP_HeurData SCIP_HEURDATA
    Definition: type_heur.h:77
    #define SCIP_DIVETYPE_SOS1VARIABLE
    Definition: type_heur.h:61
    @ SCIP_DIVECONTEXT_SINGLE
    Definition: type_heur.h:69
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63