SCIP

    Solving Constraint Integer Programs

    heur_guideddiving.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_guideddiving.c
    26 * @ingroup DEFPLUGINS_HEUR
    27 * @brief LP diving heuristic that chooses fixings in direction of incumbent solutions
    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_sol.h"
    38#include "scip/pub_var.h"
    39#include "scip/scip_heur.h"
    40#include "scip/scip_lp.h"
    41#include "scip/scip_mem.h"
    42#include "scip/scip_numerics.h"
    43#include "scip/scip_prob.h"
    44#include "scip/scip_sol.h"
    45
    46
    47#define HEUR_NAME "guideddiving"
    48#define HEUR_DESC "LP diving heuristic that chooses fixings in direction of incumbent solutions"
    49#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_DIVING
    50#define HEUR_PRIORITY -1007000
    51#define HEUR_FREQ 10
    52#define HEUR_FREQOFS 7
    53#define HEUR_MAXDEPTH -1
    54#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
    55#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
    56#define DIVESET_DIVETYPES SCIP_DIVETYPE_INTEGRALITY /**< bit mask that represents all supported dive types */
    57#define DIVESET_ISPUBLIC TRUE /**< is this dive set publicly available (ie., can be used by other primal heuristics?) */
    58
    59
    60/*
    61 * Default parameter settings
    62 */
    63
    64#define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
    65#define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
    66#define DEFAULT_MAXLPITERQUOT 0.05 /**< maximal fraction of diving LP iterations compared to node LP iterations */
    67#define DEFAULT_MAXLPITEROFS 1000 /**< additional number of allowed LP iterations */
    68#define DEFAULT_MAXDIVEUBQUOT 0.8 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
    69 * where diving is performed (0.0: no limit) */
    70#define DEFAULT_MAXDIVEAVGQUOT 0.0 /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
    71 * where diving is performed (0.0: no limit) */
    72#define DEFAULT_BACKTRACK TRUE /**< use one level of backtracking if infeasibility is encountered? */
    73#define DEFAULT_LPRESOLVEDOMCHGQUOT 0.15 /**< percentage of immediate domain changes during probing to trigger LP resolve */
    74#define DEFAULT_LPSOLVEFREQ 0 /**< LP solve frequency for diving heuristics */
    75#define DEFAULT_ONLYLPBRANCHCANDS FALSE /**< should only LP branching candidates be considered instead of the slower but
    76 * more general constraint handler diving variable selection? */
    77#define DEFAULT_RANDSEED 127 /**< initial seed for random number generation */
    78
    79/* locally defined heuristic data */
    80struct SCIP_HeurData
    81{
    82 SCIP_SOL* sol; /**< working solution */
    83};
    84
    85/*
    86 * local methods
    87 */
    88
    89/*
    90 * Callback methods
    91 */
    92
    93/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    94static
    95SCIP_DECL_HEURCOPY(heurCopyGuideddiving)
    96{ /*lint --e{715}*/
    97 assert(scip != NULL);
    98 assert(heur != NULL);
    99
    101
    102 /* call inclusion method of primal heuristic */
    104
    105 return SCIP_OKAY;
    106}
    107
    108/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    109static
    110SCIP_DECL_HEURFREE(heurFreeGuideddiving) /*lint --e{715}*/
    111{ /*lint --e{715}*/
    112 SCIP_HEURDATA* heurdata;
    113
    114 assert(heur != NULL);
    115 assert(scip != NULL);
    116
    118
    119 /* free heuristic data */
    120 heurdata = SCIPheurGetData(heur);
    121 assert(heurdata != NULL);
    122
    123 SCIPfreeBlockMemory(scip, &heurdata);
    124 SCIPheurSetData(heur, NULL);
    125
    126 return SCIP_OKAY;
    127}
    128
    129
    130/** initialization method of primal heuristic (called after problem was transformed) */
    131static
    132SCIP_DECL_HEURINIT(heurInitGuideddiving) /*lint --e{715}*/
    133{ /*lint --e{715}*/
    134 SCIP_HEURDATA* heurdata;
    135
    136 assert(heur != NULL);
    137
    139
    140 /* get heuristic data */
    141 heurdata = SCIPheurGetData(heur);
    142 assert(heurdata != NULL);
    143
    144 /* create working solution */
    145 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    146
    147 return SCIP_OKAY;
    148}
    149
    150
    151/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    152static
    153SCIP_DECL_HEUREXIT(heurExitGuideddiving) /*lint --e{715}*/
    154{ /*lint --e{715}*/
    155 SCIP_HEURDATA* heurdata;
    156
    157 assert(heur != NULL);
    158
    160
    161 /* get heuristic data */
    162 heurdata = SCIPheurGetData(heur);
    163 assert(heurdata != NULL);
    164
    165 /* free working solution */
    166 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    167
    168 return SCIP_OKAY;
    169}
    170
    171
    172/** execution method of primal heuristic */
    173static
    174SCIP_DECL_HEUREXEC(heurExecGuideddiving) /*lint --e{715}*/
    175{ /*lint --e{715}*/
    176 SCIP_HEURDATA* heurdata;
    177 SCIP_DIVESET* diveset;
    178
    179 assert(heur != NULL);
    180 assert(scip != NULL);
    181 assert(result != NULL);
    182 assert(SCIPhasCurrentNodeLP(scip));
    183
    185
    186 *result = SCIP_DIDNOTRUN;
    187
    188 /* don't dive, if no feasible solutions exist */
    189 if( SCIPgetNSols(scip) == 0 )
    190 return SCIP_OKAY;
    191
    192 /* get best solution that should guide the search; if this solution lives in the original variable space,
    193 * we cannot use it since it might violate the global bounds of the current problem
    194 */
    196 return SCIP_OKAY;
    197
    198 /* get heuristic's data */
    199 heurdata = SCIPheurGetData(heur);
    200 assert(heurdata != NULL);
    201
    202 /* if there are no integer variables (note that, e.g., SOS1 variables may be present) */
    204 return SCIP_OKAY;
    205
    206 assert(SCIPheurGetNDivesets(heur) > 0);
    207 assert(SCIPheurGetDivesets(heur) != NULL);
    208 diveset = SCIPheurGetDivesets(heur)[0];
    209 assert(diveset != NULL);
    210
    211 /* call generic diving algorithm */
    212 SCIP_CALL( SCIPperformGenericDivingAlgorithm(scip, diveset, heurdata->sol, heur, result, nodeinfeasible, -1L, -1, -1.0, SCIP_DIVECONTEXT_SINGLE) );
    213
    214 return SCIP_OKAY;
    215}
    216
    217/* callbacks for diving */
    218
    219/** calculate score and preferred rounding direction for the candidate variable; the best candidate maximizes the
    220 * score
    221 */
    222static
    223SCIP_DECL_DIVESETGETSCORE(divesetGetScoreGuideddiving)
    224{
    225 SCIP_SOL* bestsol;
    226 SCIP_Real bestsolval;
    227 SCIP_Real obj;
    228 SCIP_Real objnorm;
    229 SCIP_Real objgain;
    230
    231 bestsol = SCIPgetBestSol(scip);
    232 assert(bestsol != NULL);
    233 assert(!SCIPsolIsOriginal(bestsol));
    234
    235 bestsolval = SCIPgetSolVal(scip, bestsol, cand);
    236
    237 /* variable should be rounded (guided) into the direction of its incumbent solution value */
    238 if( candsol < bestsolval )
    239 *roundup = TRUE;
    240 else
    241 *roundup = FALSE;
    242
    243 obj = SCIPvarGetObj(cand);
    244 objnorm = SCIPgetObjNorm(scip);
    245
    246 /* divide by objective norm to normalize obj into [-1,1] */
    247 if( SCIPisPositive(scip, objnorm) )
    248 obj /= objnorm;
    249
    250 /* calculate objective gain and fractionality for the selected rounding direction */
    251 if( *roundup )
    252 {
    253 candsfrac = 1.0 - candsfrac;
    254 objgain = obj * candsfrac;
    255 }
    256 else
    257 objgain = -obj * candsfrac;
    258
    259 assert(objgain >= -1.0 && objgain <= 1.0);
    260
    261 /* penalize too small fractions */
    262 if( candsfrac < 0.01 )
    263 candsfrac *= 0.1;
    264
    265 /* prefer decisions on binary variables */
    266 if( !SCIPvarIsBinary(cand) )
    267 candsfrac *= 0.1;
    268
    269 /* prefer variables which cannot be rounded by scoring their fractionality */
    270 if( !(SCIPvarMayRoundDown(cand) || SCIPvarMayRoundUp(cand)) )
    271 *score = -candsfrac;
    272 else
    273 *score = -2.0 - objgain;
    274
    275 return SCIP_OKAY;
    276}
    277
    278/** callback to check preconditions for diving, e.g., if an incumbent solution is available */
    279static
    280SCIP_DECL_DIVESETAVAILABLE(divesetAvailableGuideddiving)
    281{
    282 /* don't dive with guided diving if no feasible solutions exists or
    283 * if this solution lives in the original variable space,
    284 * because it might violate the global bounds of the current problem
    285 */
    287 *available = FALSE;
    288 else
    289 *available = TRUE;
    290
    291 return SCIP_OKAY;
    292}
    293
    294/*
    295 * heuristic specific interface methods
    296 */
    297
    298/** creates the guideddiving heuristic and includes it in SCIP */
    300 SCIP* scip /**< SCIP data structure */
    301 )
    302{
    303 SCIP_HEURDATA* heurdata;
    304 SCIP_HEUR* heur;
    305
    306 /* create Guideddiving primal heuristic data */
    307 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    308
    309 /* include primal heuristic */
    312 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecGuideddiving, heurdata) );
    313
    314 assert(heur != NULL);
    315
    316 /* primal heuristic is safe to use in exact solving mode */
    317 SCIPheurMarkExact(heur);
    318
    319 /* set non-NULL pointers to callback methods */
    320 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyGuideddiving) );
    321 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeGuideddiving) );
    322 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitGuideddiving) );
    323 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitGuideddiving) );
    324
    325 /* create a diveset (this will automatically install some additional parameters for the heuristic)*/
    329 divesetGetScoreGuideddiving, divesetAvailableGuideddiving) );
    330
    331 return SCIP_OKAY;
    332}
    #define NULL
    Definition: def.h:257
    #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_CALL(x)
    Definition: def.h:364
    int SCIPgetNContVars(SCIP *scip)
    Definition: scip_prob.c:2569
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_Real SCIPgetObjNorm(SCIP *scip)
    Definition: scip_prob.c:1880
    int SCIPgetNContImplVars(SCIP *scip)
    Definition: scip_prob.c:2522
    SCIP_RETCODE SCIPincludeHeurGuideddiving(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_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
    SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
    Definition: scip_lp.c:87
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2986
    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
    int SCIPgetNSols(SCIP *scip)
    Definition: scip_sol.c:2887
    SCIP_Bool SCIPsolIsOriginal(SCIP_SOL *sol)
    Definition: sol.c:4155
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    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 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
    #define DEFAULT_ONLYLPBRANCHCANDS
    #define DEFAULT_MAXDIVEUBQUOT
    #define DEFAULT_LPRESOLVEDOMCHGQUOT
    static SCIP_DECL_HEURCOPY(heurCopyGuideddiving)
    #define HEUR_TIMING
    #define DEFAULT_MAXLPITERQUOT
    #define HEUR_FREQOFS
    #define HEUR_DESC
    #define DEFAULT_MAXDIVEAVGQUOT
    #define DEFAULT_LPSOLVEFREQ
    #define DEFAULT_BACKTRACK
    #define HEUR_DISPCHAR
    #define HEUR_MAXDEPTH
    static SCIP_DECL_HEUREXIT(heurExitGuideddiving)
    #define HEUR_PRIORITY
    #define DEFAULT_MAXRELDEPTH
    #define DEFAULT_MAXLPITEROFS
    #define HEUR_NAME
    static SCIP_DECL_DIVESETAVAILABLE(divesetAvailableGuideddiving)
    #define DEFAULT_RANDSEED
    #define DIVESET_DIVETYPES
    static SCIP_DECL_HEURFREE(heurFreeGuideddiving)
    static SCIP_DECL_HEUREXEC(heurExecGuideddiving)
    #define DIVESET_ISPUBLIC
    #define HEUR_FREQ
    #define DEFAULT_MINRELDEPTH
    static SCIP_DECL_HEURINIT(heurInitGuideddiving)
    #define HEUR_USESSUBSCIP
    static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreGuideddiving)
    LP diving heuristic that chooses fixings in direction of incumbent solutions.
    methods commonly used by primal heuristics
    public methods for primal heuristics
    public methods for message output
    public methods for primal CIP solutions
    public methods for problem variables
    public methods for primal heuristic plugins and divesets
    public methods for the LP relaxation, rows and columns
    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
    @ 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