SCIP

    Solving Constraint Integer Programs

    heur_nlpdiving.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_nlpdiving.c
    26 * @ingroup DEFPLUGINS_HEUR
    27 * @brief NLP diving heuristic that chooses fixings w.r.t. the fractionalities
    28 * @author Timo Berthold
    29 * @author Stefan Vigerske
    30 */
    31
    32/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    33
    35#include "scip/heur_nlpdiving.h"
    36#include "scip/heur_subnlp.h"
    38#include "scip/pub_event.h"
    39#include "scip/pub_heur.h"
    40#include "scip/pub_message.h"
    41#include "scip/pub_misc.h"
    42#include "scip/pub_sol.h"
    43#include "scip/pub_var.h"
    44#include "scip/scip_branch.h"
    45#include "scip/scip_copy.h"
    46#include "scip/scip_event.h"
    47#include "scip/scip_general.h"
    48#include "scip/scip_heur.h"
    49#include "scip/scip_lp.h"
    50#include "scip/scip_mem.h"
    51#include "scip/scip_message.h"
    52#include "scip/scip_nlp.h"
    53#include "scip/scip_nlpi.h"
    54#include "scip/scip_nodesel.h"
    55#include "scip/scip_numerics.h"
    56#include "scip/scip_param.h"
    57#include "scip/scip_prob.h"
    58#include "scip/scip_probing.h"
    60#include "scip/scip_sol.h"
    61#include "scip/scip_solve.h"
    63#include "scip/scip_timing.h"
    64#include "scip/scip_tree.h"
    65#include "scip/scip_var.h"
    66
    67
    68#define HEUR_NAME "nlpdiving"
    69#define HEUR_DESC "NLP diving heuristic that chooses fixings w.r.t. the fractionalities"
    70#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_DIVING
    71#define HEUR_PRIORITY -1003010
    72#define HEUR_FREQ 10
    73#define HEUR_FREQOFS 3
    74#define HEUR_MAXDEPTH -1
    75#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
    76#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
    77
    78/* event handler properties */
    79#define EVENTHDLR_NAME "Nlpdiving"
    80#define EVENTHDLR_DESC "bound change event handler for " HEUR_NAME " heuristic"
    81
    82
    83/*
    84 * Default parameter settings
    85 */
    86
    87#define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
    88#define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
    89#define DEFAULT_MAXNLPITERABS 200 /**< minimial absolute number of allowed NLP iterations */
    90#define DEFAULT_MAXNLPITERREL 10 /**< additional allowed number of NLP iterations relative to successfully found solutions */
    91#define DEFAULT_MAXDIVEUBQUOT 0.8 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
    92 * where diving is performed (0.0: no limit) */
    93#define DEFAULT_MAXDIVEAVGQUOT 0.0 /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
    94 * where diving is performed (0.0: no limit) */
    95#define DEFAULT_MAXDIVEUBQUOTNOSOL 0.1 /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
    96#define DEFAULT_MAXDIVEAVGQUOTNOSOL 0.0 /**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
    97#define DEFAULT_MINSUCCQUOT 0.1 /**< heuristic will not run if less then this percentage of calls succeeded (0.0: no limit) */
    98#define DEFAULT_MAXFEASNLPS 10 /**< maximal number of NLPs with feasible solution to solve during one dive */
    99#define DEFAULT_FIXQUOT 0.2 /**< percentage of fractional variables that should be fixed before the next NLP solve */
    100#define DEFAULT_BACKTRACK TRUE /**< use one level of backtracking if infeasibility is encountered? */
    101#define DEFAULT_LP FALSE /**< should the LP relaxation be solved before the NLP relaxation? */
    102#define DEFAULT_PREFERLPFRACS FALSE /**< prefer variables that are also fractional in LP solution? */
    103#define DEFAULT_PREFERCOVER TRUE /**< should variables in a minimal cover be preferred? */
    104#define DEFAULT_SOLVESUBMIP FALSE /**< should a sub-MIP be solved if all cover variables are fixed? */
    105#define DEFAULT_NLPSTART 's' /**< which point should be used as starting point for the NLP solver? */
    106#define DEFAULT_VARSELRULE 'd' /**< which variable selection should be used? ('f'ractionality, 'c'oefficient,
    107 * 'p'seudocost, 'g'uided, 'd'ouble)
    108 */
    109#define DEFAULT_NLPFASTFAIL TRUE /**< should the NLP solver stop early if it converges slow? */
    110#define DEFAULT_RANDSEED 97 /**< initial random seed */
    111
    112#define MINNLPITER 10 /**< minimal number of NLP iterations allowed in each NLP solving call */
    113
    114/* locally defined heuristic data */
    115struct SCIP_HeurData
    116{
    117 SCIP_SOL* sol; /**< working solution */
    118 SCIP_Real minreldepth; /**< minimal relative depth to start diving */
    119 SCIP_Real maxreldepth; /**< maximal relative depth to start diving */
    120 int maxnlpiterabs; /**< minimial absolute number of allowed NLP iterations */
    121 int maxnlpiterrel; /**< additional allowed number of NLP iterations relative to successfully found solutions */
    122 SCIP_Real maxdiveubquot; /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
    123 * where diving is performed (0.0: no limit) */
    124 SCIP_Real maxdiveavgquot; /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
    125 * where diving is performed (0.0: no limit) */
    126 SCIP_Real maxdiveubquotnosol; /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
    127 SCIP_Real maxdiveavgquotnosol;/**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
    128 int maxfeasnlps; /**< maximal number of NLPs with feasible solution to solve during one dive */
    129 SCIP_Real minsuccquot; /**< heuristic will not run if less then this percentage of calls succeeded (0.0: no limit) */
    130 SCIP_Real fixquot; /**< percentage of fractional variables that should be fixed before the next NLP solve */
    131 SCIP_Bool backtrack; /**< use one level of backtracking if infeasibility is encountered? */
    132 SCIP_Bool lp; /**< should the LP relaxation be solved before the NLP relaxation? */
    133 SCIP_Bool preferlpfracs; /**< prefer variables that are also fractional in LP solution? */
    134 SCIP_Bool prefercover; /**< should variables in a minimal cover be preferred? */
    135 SCIP_Bool solvesubmip; /**< should a sub-MIP be solved if all cover variables are fixed? */
    136 SCIP_Bool nlpfastfail; /**< should the NLP solver stop early if it converges slow? */
    137 char nlpstart; /**< which point should be used as starting point for the NLP solver? */
    138 char varselrule; /**< which variable selection should be used? ('f'ractionality, 'c'oefficient,
    139 * 'p'seudocost, 'g'uided, 'd'ouble)
    140 */
    141
    142 int nnlpiterations; /**< NLP iterations used in this heuristic */
    143 int nsuccess; /**< number of runs that produced at least one feasible solution */
    144 int nfixedcovervars; /**< number of variables in the cover that are already fixed */
    145#ifdef SCIP_STATISTIC
    146 int nnlpsolves; /**< number of NLP solves */
    147 int nfailcutoff; /**< number of fails due to cutoff */
    148 int nfaildepth; /**< number of fails due to too deep */
    149 int nfailnlperror; /**< number of fails due to NLP error */
    150#endif
    151 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
    152 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
    153 SCIP_HEURTIMING inittiming; /**< initial heuristic timing */
    154};
    155
    156
    157/*
    158 * local methods
    159 */
    160
    161/** gets fractional variables of last NLP solution along with solution values and fractionalities
    162 *
    163 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    164 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    165 *
    166 * @pre This method can be called if SCIP is in one of the following stages:
    167 * - \ref SCIP_STAGE_INITSOLVE
    168 * - \ref SCIP_STAGE_SOLVING
    169 */
    170static
    172 SCIP* scip, /**< SCIP data structure */
    173 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
    174 SCIP_VAR*** nlpcands, /**< pointer to store the array of NLP fractional variables, or NULL */
    175 SCIP_Real** nlpcandssol, /**< pointer to store the array of NLP fractional variables solution values, or NULL */
    176 SCIP_Real** nlpcandsfrac, /**< pointer to store the array of NLP fractional variables fractionalities, or NULL */
    177 int* nnlpcands /**< pointer to store the number of NLP fractional variables , or NULL */
    178 )
    179{
    180 int c;
    181
    182 assert(scip != NULL);
    183 assert(heurdata != NULL);
    184 assert(nlpcands != NULL);
    185 assert(nlpcandssol != NULL);
    186 assert(nlpcandsfrac != NULL);
    187 assert(nnlpcands != NULL);
    188
    189 /* get fractional variables that should be integral */
    190 SCIP_CALL( SCIPgetNLPFracVars(scip, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, NULL) );
    191
    192 /* values may be outside the domain in exact arithmetic, but inside the domain within relative tolerance, and still
    193 * slightly fractional, because SCIPisFeasIntegral() uses absolute tolerance; project value onto domain to avoid this
    194 * (example: primsol=29.99999853455704, lower bound = 30)
    195 */
    196 for( c = 0; c < *nnlpcands; ++c )
    197 {
    198 assert(!SCIPisFeasIntegral(scip, (*nlpcandssol)[c]));
    199
    200 if( (*nlpcandssol)[c] < SCIPvarGetLbLocal((*nlpcands)[c]) || (*nlpcandssol)[c] > SCIPvarGetUbLocal((*nlpcands)[c]) )
    201 {
    202 SCIP_Real newval;
    203
    204 newval = ((*nlpcandssol)[c] < SCIPvarGetLbLocal((*nlpcands)[c]))
    205 ? SCIPvarGetLbLocal((*nlpcands)[c]) - 0.5*SCIPfeastol(scip)
    206 : SCIPvarGetUbLocal((*nlpcands)[c]) + 0.5*SCIPfeastol(scip);
    207
    208 assert(SCIPisFeasIntegral(scip, newval));
    209
    210 SCIP_CALL( SCIPsetSolVal(scip, heurdata->sol, (*nlpcands)[c], newval) );
    211
    212 (*nnlpcands)--;
    213
    214 if( c < *nnlpcands )
    215 {
    216 (*nlpcands)[c] = (*nlpcands)[*nnlpcands];
    217 (*nlpcandssol)[c] = (*nlpcandssol)[*nnlpcands];
    218 (*nlpcandsfrac)[c] = (*nlpcandsfrac)[*nnlpcands];
    219 }
    220 }
    221 }
    222
    223 /* prefer decisions on variables which are also fractional in LP solution */
    224 if( heurdata->preferlpfracs && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
    225 {
    226 for( c = 0; c < *nnlpcands; ++c )
    227 {
    228 if( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, NULL, (*nlpcands)[c])) )
    229 (*nlpcandsfrac)[c] *= 100.0;
    230 }
    231 }
    232
    233 return SCIP_OKAY;
    234}
    235
    236/** finds best candidate variable w.r.t. fractionality:
    237 * - prefer variables that may not be rounded without destroying NLP feasibility:
    238 * - of these variables, round least fractional variable in corresponding direction
    239 * - if all remaining fractional variables may be rounded without destroying NLP feasibility:
    240 * - round variable with least increasing objective value
    241 * - binary variables are prefered
    242 * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
    243 * also be prefered if a correpsonding parameter is set
    244 */
    245static
    247 SCIP* scip, /**< original SCIP data structure */
    248 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
    249 SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
    250 SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
    251 SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
    252 int nnlpcands, /**< number of NLP fractional variables */
    253 SCIP_HASHMAP* varincover, /**< hash map for variables */
    254 SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
    255 int* bestcand, /**< pointer to store the index of the best candidate variable */
    256 SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
    257 SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
    258 )
    259{
    260 SCIP_Real bestobjgain;
    261 SCIP_Real bestfrac;
    262 SCIP_Bool bestcandmayrounddown;
    263 SCIP_Bool bestcandmayroundup;
    264 int c;
    265
    266 /* check preconditions */
    267 assert(scip != NULL);
    268 assert(heurdata != NULL);
    269 assert(nlpcands != NULL);
    270 assert(nlpcandssol != NULL);
    271 assert(nlpcandsfrac != NULL);
    272 assert(covercomputed == (varincover != NULL));
    273 assert(bestcand != NULL);
    274 assert(bestcandmayround != NULL);
    275 assert(bestcandroundup != NULL);
    276
    277 bestcandmayrounddown = TRUE;
    278 bestcandmayroundup = TRUE;
    279 bestobjgain = SCIPinfinity(scip);
    280 bestfrac = SCIP_INVALID;
    281
    282 for( c = 0; c < nnlpcands; ++c )
    283 {
    284 SCIP_VAR* var;
    285 SCIP_Bool mayrounddown;
    286 SCIP_Bool mayroundup;
    287 SCIP_Bool roundup;
    288 SCIP_Real frac;
    289 SCIP_Real obj;
    290 SCIP_Real objgain;
    291
    292 var = nlpcands[c];
    293
    294 mayrounddown = SCIPvarMayRoundDown(var);
    295 mayroundup = SCIPvarMayRoundUp(var);
    296 frac = nlpcandsfrac[c];
    297 obj = SCIPvarGetObj(var);
    298
    299 /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
    300 if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
    301 continue;
    302
    303 if( mayrounddown || mayroundup )
    304 {
    305 /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
    306 if( bestcandmayrounddown || bestcandmayroundup )
    307 {
    308 /* choose rounding direction:
    309 * - if variable may be rounded in both directions, round corresponding to the fractionality
    310 * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
    311 * the current fractional solution
    312 */
    313 if( mayrounddown && mayroundup )
    314 {
    315 if( SCIPisEQ(scip, frac, 0.5) )
    316 roundup = (SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0);
    317 else
    318 roundup = (frac > 0.5);
    319 }
    320 else
    321 roundup = mayrounddown;
    322
    323 if( roundup )
    324 {
    325 frac = 1.0 - frac;
    326 objgain = frac*obj;
    327 }
    328 else
    329 objgain = -frac*obj;
    330
    331 /* penalize too small fractions */
    332 if( SCIPisEQ(scip, frac, 0.01) )
    333 {
    334 /* try to avoid variability; decide randomly if the LP solution can contain some noise.
    335 * use a 1:SCIP_PROBINGSCORE_PENALTYRATIO chance for increasing the fractionality, i.e., the score.
    336 */
    337 if( SCIPrandomGetInt(heurdata->randnumgen, 0, SCIP_PROBINGSCORE_PENALTYRATIO) == 0 )
    338 objgain *= 1000.0;
    339 }
    340 else if( frac < 0.01 )
    341 objgain *= 1000.0;
    342
    343 /* prefer decisions on binary variables */
    344 if( !SCIPvarIsBinary(var) )
    345 objgain *= 1000.0;
    346
    347 /* prefer decisions on cover variables */
    348 if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
    349 objgain *= 1000.0;
    350
    351 /* check, if candidate is new best candidate */
    352 if( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) )
    353 {
    354 *bestcand = c;
    355 bestobjgain = objgain;
    356 bestfrac = frac;
    357 bestcandmayrounddown = mayrounddown;
    358 bestcandmayroundup = mayroundup;
    359 *bestcandroundup = roundup;
    360 }
    361 }
    362 }
    363 else
    364 {
    365 /* the candidate may not be rounded */
    366 if( SCIPisEQ(scip, frac, 0.5) )
    367 roundup = (SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0);
    368 else if( frac < 0.5 )
    369 roundup = FALSE;
    370 else
    371 roundup = TRUE;
    372
    373 /* adjust fractional part */
    374 if( roundup )
    375 frac = 1.0 - frac;
    376
    377 /* penalize too small fractions */
    378 if( SCIPisEQ(scip, frac, 0.01) )
    379 {
    380 /* try to avoid variability; decide randomly if the LP solution can contain some noise.
    381 * use a 1:SCIP_PROBINGSCORE_PENALTYRATIO chance for increasing the fractionality, i.e., the score.
    382 */
    383 if( SCIPrandomGetInt(heurdata->randnumgen, 0, SCIP_PROBINGSCORE_PENALTYRATIO) == 0 )
    384 frac += 10.0;
    385 }
    386 else if( frac < 0.01 )
    387 frac += 10.0;
    388
    389 /* prefer decisions on binary variables */
    390 if( !SCIPvarIsBinary(var) )
    391 frac *= 1000.0;
    392
    393 /* prefer decisions on cover variables */
    394 if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
    395 frac *= 1000.0;
    396
    397 /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
    398 if( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac )
    399 {
    400 *bestcand = c;
    401 bestfrac = frac;
    402 bestcandmayrounddown = FALSE;
    403 bestcandmayroundup = FALSE;
    404 *bestcandroundup = roundup;
    405 }
    406 assert(bestfrac < SCIP_INVALID);
    407 }
    408 }
    409
    410 *bestcandmayround = bestcandmayroundup || bestcandmayrounddown;
    411
    412 return SCIP_OKAY;
    413}
    414
    415/** finds best candidate variable w.r.t. vector length:
    416 * - round variable with a small ratio between the increase in the objective and the locking numbers
    417 * - binary variables are prefered
    418 * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
    419 * also be prefered if a corresponding parameter is set
    420 */
    421static
    423 SCIP* scip, /**< original SCIP data structure */
    424 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
    425 SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
    426 SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
    427 SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
    428 int nnlpcands, /**< number of NLP fractional variables */
    429 SCIP_HASHMAP* varincover, /**< hash map for variables */
    430 SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
    431 int* bestcand, /**< pointer to store the index of the best candidate variable */
    432 SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
    433 SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
    434 )
    435{
    436 SCIP_Real bestscore;
    437 int c;
    438
    439 /* check preconditions */
    440 assert(scip != NULL);
    441 assert(heurdata != NULL);
    442 assert(nlpcands != NULL);
    443 assert(nlpcandsfrac != NULL);
    444 assert(nlpcandssol != NULL);
    445 assert(bestcand != NULL);
    446 assert(bestcandmayround != NULL);
    447 assert(bestcandroundup != NULL);
    448
    449 *bestcandmayround = TRUE;
    450 bestscore = SCIP_REAL_MAX;
    451
    452 /* get best candidate */
    453 for( c = 0; c < nnlpcands; ++c )
    454 {
    455 SCIP_VAR* var;
    456
    457 SCIP_Real obj;
    458 SCIP_Real objdelta;
    459 SCIP_Real frac;
    460 SCIP_Real score;
    461
    462 int nlocks;
    463
    464 SCIP_Bool roundup;
    465
    466 var = nlpcands[c];
    467
    468 /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
    469 if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
    470 continue;
    471
    472 frac = nlpcandsfrac[c];
    473 obj = SCIPvarGetObj(var);
    474 roundup = (obj >= 0.0);
    475 objdelta = (roundup ? (1.0-frac)*obj : -frac * obj);
    476 assert(objdelta >= 0.0);
    477
    478 /* check whether the variable is roundable */
    479 *bestcandmayround = *bestcandmayround && (SCIPvarMayRoundDown(var) || SCIPvarMayRoundUp(var));
    481
    482 /* smaller score is better */
    483 score = (objdelta + SCIPsumepsilon(scip))/((SCIP_Real)nlocks+1.0);
    484
    485 /* prefer decisions on binary variables */
    487 score *= 1000.0;
    488
    489 /* prefer decisions on cover variables */
    490 if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
    491 score *= 1000;
    492
    493 /* check, if candidate is new best candidate */
    494 if( score < bestscore )
    495 {
    496 *bestcand = c;
    497 bestscore = score;
    498 *bestcandroundup = roundup;
    499 }
    500 }
    501
    502 return SCIP_OKAY;
    503}
    504
    505
    506/** finds best candidate variable w.r.t. locking numbers:
    507 * - prefer variables that may not be rounded without destroying LP feasibility:
    508 * - of these variables, round variable with least number of locks in corresponding direction
    509 * - if all remaining fractional variables may be rounded without destroying LP feasibility:
    510 * - round variable with least number of locks in opposite of its feasible rounding direction
    511 * - binary variables are prefered
    512 * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
    513 * also be prefered if a correpsonding parameter is set
    514 */
    515static
    517 SCIP* scip, /**< original SCIP data structure */
    518 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
    519 SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
    520 SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
    521 SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
    522 int nnlpcands, /**< number of NLP fractional variables */
    523 SCIP_HASHMAP* varincover, /**< hash map for variables */
    524 SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
    525 int* bestcand, /**< pointer to store the index of the best candidate variable */
    526 SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
    527 SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
    528 )
    529{
    530 SCIP_Bool bestcandmayrounddown;
    531 SCIP_Bool bestcandmayroundup;
    532 int bestnviolrows; /* number of violated rows for best candidate */
    533 SCIP_Real bestcandfrac; /* fractionality of best candidate */
    534 int c;
    535
    536 /* check preconditions */
    537 assert(scip != NULL);
    538 assert(heurdata != NULL);
    539 assert(nlpcands != NULL);
    540 assert(nlpcandsfrac != NULL);
    541 assert(nlpcandssol != NULL);
    542 assert(bestcand != NULL);
    543 assert(bestcandmayround != NULL);
    544 assert(bestcandroundup != NULL);
    545
    546 bestcandmayrounddown = TRUE;
    547 bestcandmayroundup = TRUE;
    548 bestnviolrows = INT_MAX;
    549 bestcandfrac = SCIP_INVALID;
    550
    551 /* get best candidate */
    552 for( c = 0; c < nnlpcands; ++c )
    553 {
    554 SCIP_VAR* var;
    555
    556 int nlocksdown;
    557 int nlocksup;
    558 int nviolrows;
    559
    560 SCIP_Bool mayrounddown;
    561 SCIP_Bool mayroundup;
    562 SCIP_Bool roundup;
    563 SCIP_Real frac;
    564
    565 var = nlpcands[c];
    566 mayrounddown = SCIPvarMayRoundDown(var);
    567 mayroundup = SCIPvarMayRoundUp(var);
    568 frac = nlpcandsfrac[c];
    569
    570 /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
    571 if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
    572 continue;
    573
    574 if( mayrounddown || mayroundup )
    575 {
    576 /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
    577 if( bestcandmayrounddown || bestcandmayroundup )
    578 {
    579 /* choose rounding direction:
    580 * - if variable may be rounded in both directions, round corresponding to the fractionality
    581 * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
    582 * the current fractional solution
    583 */
    584 if( mayrounddown && mayroundup )
    585 {
    586 if( SCIPisEQ(scip, frac, 0.5) )
    587 roundup = (SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0);
    588 else
    589 roundup = (frac > 0.5);
    590 }
    591 else
    592 roundup = mayrounddown;
    593
    594 if( roundup )
    595 {
    596 frac = 1.0 - frac;
    598 }
    599 else
    601
    602 /* penalize too small fractions */
    603 if( SCIPisEQ(scip, frac, 0.01) )
    604 {
    605 /* try to avoid variability; decide randomly if the LP solution can contain some noise.
    606 * use a 1:SCIP_PROBINGSCORE_PENALTYRATIO chance for increasing the fractionality, i.e., the score.
    607 */
    608 if( SCIPrandomGetInt(heurdata->randnumgen, 0, SCIP_PROBINGSCORE_PENALTYRATIO) == 0 )
    609 nviolrows *= 100;
    610 }
    611 else if( frac < 0.01 )
    612 nviolrows *= 100;
    613
    614 /* prefer decisions on binary variables */
    615 if( !SCIPvarIsBinary(var) )
    616 nviolrows *= 1000;
    617
    618 /* prefer decisions on cover variables */
    619 if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
    620 nviolrows *= 1000;
    621
    622 /* check, if candidate is new best candidate */
    623 assert( (0.0 < frac && frac < 1.0) || SCIPvarIsBinary(var) );
    624 if( nviolrows + frac < bestnviolrows + bestcandfrac )
    625 {
    626 *bestcand = c;
    627 bestnviolrows = nviolrows;
    628 bestcandfrac = frac;
    629 bestcandmayrounddown = mayrounddown;
    630 bestcandmayroundup = mayroundup;
    631 *bestcandroundup = roundup;
    632 }
    633 }
    634 }
    635 else
    636 {
    637 /* the candidate may not be rounded */
    640
    641 roundup = (nlocksdown > nlocksup);
    642 if( !roundup )
    643 {
    644 roundup = (nlocksdown == nlocksup);
    645 if( SCIPisEQ(scip, frac, 0.5) )
    646 roundup = (roundup && (SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0));
    647 else
    648 roundup = (roundup && frac > 0.5);
    649 }
    650
    651 if( roundup )
    652 {
    653 nviolrows = nlocksup;
    654 frac = 1.0 - frac;
    655 }
    656 else
    657 nviolrows = nlocksdown;
    658
    659 /* penalize too small fractions */
    660 if( SCIPisEQ(scip, frac, 0.01) )
    661 {
    662 /* try to avoid variability; decide randomly if the LP solution can contain some noise.
    663 * use a 1:SCIP_PROBINGSCORE_PENALTYRATIO chance for increasing the fractionality, i.e., the score.
    664 */
    665 if( SCIPrandomGetInt(heurdata->randnumgen, 0, SCIP_PROBINGSCORE_PENALTYRATIO) == 0 )
    666 nviolrows *= 100;
    667 }
    668 else if( frac < 0.01 )
    669 nviolrows *= 100;
    670
    671 /* prefer decisions on binary variables */
    672 if( !SCIPvarIsBinary(var) )
    673 nviolrows *= 100;
    674
    675 /* prefer decisions on cover variables */
    676 if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
    677 nviolrows *= 1000;
    678
    679 /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
    680 assert((0.0 < frac && frac < 1.0) || SCIPvarIsBinary(var));
    681 if( bestcandmayrounddown || bestcandmayroundup || nviolrows + frac < bestnviolrows + bestcandfrac )
    682 {
    683 *bestcand = c;
    684 bestnviolrows = nviolrows;
    685 bestcandfrac = frac;
    686 bestcandmayrounddown = FALSE;
    687 bestcandmayroundup = FALSE;
    688 *bestcandroundup = roundup;
    689 }
    690 assert(bestcandfrac < SCIP_INVALID);
    691 }
    692 }
    693
    694 *bestcandmayround = bestcandmayroundup || bestcandmayrounddown;
    695
    696 return SCIP_OKAY;
    697}
    698
    699/** calculates the pseudocost score for a given variable w.r.t. a given solution value and a given rounding direction */
    700static
    702 SCIP* scip, /**< SCIP data structure */
    703 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
    704 SCIP_VAR* var, /**< problem variable */
    705 SCIP_Real primsol, /**< primal solution of variable */
    706 SCIP_Real frac, /**< fractionality of variable */
    707 int rounddir, /**< -1: round down, +1: round up, 0: select due to pseudo cost values */
    708 SCIP_Real* pscostquot, /**< pointer to store pseudo cost quotient */
    709 SCIP_Bool* roundup, /**< pointer to store whether the variable should be rounded up */
    710 SCIP_Bool prefvar /**< should this variable be preferred because it is in a minimal cover? */
    711 )
    712{
    713 SCIP_Real pscostdown;
    714 SCIP_Real pscostup;
    715
    716 assert(heurdata != NULL);
    717 assert(pscostquot != NULL);
    718 assert(roundup != NULL);
    719 assert(SCIPisEQ(scip, frac, primsol - SCIPfeasFloor(scip, primsol)));
    720
    721 /* bound fractions to not prefer variables that are nearly integral */
    722 frac = MAX(frac, 0.1);
    723 frac = MIN(frac, 0.9);
    724
    725 /* get pseudo cost quotient */
    726 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0-frac);
    727 pscostup = SCIPgetVarPseudocostVal(scip, var, 1.0-frac);
    728 assert(pscostdown >= 0.0 && pscostup >= 0.0);
    729
    730 /* choose rounding direction
    731 *
    732 * to avoid performance variability caused by numerics we use random numbers to decide whether we want to roundup or
    733 * round down if the values to compare are equal within tolerances.
    734 */
    735 if( rounddir == -1 )
    736 *roundup = FALSE;
    737 else if( rounddir == +1 )
    738 *roundup = TRUE;
    739 else if( SCIPisLT(scip, primsol, SCIPvarGetRootSol(var) - 0.4)
    740 || (SCIPisEQ(scip, primsol, SCIPvarGetRootSol(var) - 0.4) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0) )
    741 *roundup = FALSE;
    742 else if( SCIPisGT(scip, primsol, SCIPvarGetRootSol(var) + 0.4)
    743 || (SCIPisEQ(scip, primsol, SCIPvarGetRootSol(var) + 0.4) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0) )
    744 *roundup = TRUE;
    745 else if( SCIPisLT(scip, frac, 0.3) || (SCIPisEQ(scip, frac, 0.3) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0) )
    746 *roundup = FALSE;
    747 else if( SCIPisGT(scip, frac, 0.7) || (SCIPisEQ(scip, frac, 0.7) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0) )
    748 *roundup = TRUE;
    749 else if( SCIPisLT(scip, pscostdown, pscostup)
    750 || (SCIPisEQ(scip, pscostdown, pscostup) && SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0))
    751 *roundup = FALSE;
    752 else
    753 *roundup = TRUE;
    754
    755 /* calculate pseudo cost quotient */
    756 if( *roundup )
    757 *pscostquot = sqrt(frac) * (1.0+pscostdown) / (1.0+pscostup);
    758 else
    759 *pscostquot = sqrt(1.0-frac) * (1.0+pscostup) / (1.0+pscostdown);
    760
    761 /* prefer decisions on binary variables */
    762 if( SCIPvarIsBinary(var) )
    763 (*pscostquot) *= 1000.0;
    764
    765 /* prefer decisions on cover variables */
    766 if( prefvar )
    767 (*pscostquot) *= 1000.0;
    768}
    769
    770/** finds best candidate variable w.r.t. pseudo costs:
    771 * - prefer variables that may not be rounded without destroying LP feasibility:
    772 * - of these variables, round variable with largest rel. difference of pseudo cost values in corresponding
    773 * direction
    774 * - if all remaining fractional variables may be rounded without destroying LP feasibility:
    775 * - round variable in the objective value direction
    776 * - binary variables are prefered
    777 * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
    778 * also be prefered if a correpsonding parameter is set
    779 */
    780static
    782 SCIP* scip, /**< original SCIP data structure */
    783 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
    784 SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
    785 SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
    786 SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
    787 int nnlpcands, /**< number of NLP fractional variables */
    788 SCIP_HASHMAP* varincover, /**< hash map for variables */
    789 SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
    790 int* bestcand, /**< pointer to store the index of the best candidate variable */
    791 SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
    792 SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
    793 )
    794{
    795 SCIP_Bool bestcandmayrounddown;
    796 SCIP_Bool bestcandmayroundup;
    797 SCIP_Real bestpscostquot;
    798 int c;
    799
    800 /* check preconditions */
    801 assert(scip != NULL);
    802 assert(heurdata != NULL);
    803 assert(nlpcands != NULL);
    804 assert(nlpcandsfrac != NULL);
    805 assert(nlpcandssol != NULL);
    806 assert(bestcand != NULL);
    807 assert(bestcandmayround != NULL);
    808 assert(bestcandroundup != NULL);
    809
    810 bestcandmayrounddown = TRUE;
    811 bestcandmayroundup = TRUE;
    812 bestpscostquot = -1.0;
    813
    814 for( c = 0; c < nnlpcands; ++c )
    815 {
    816 SCIP_VAR* var;
    817 SCIP_Real primsol;
    818
    819 SCIP_Bool mayrounddown;
    820 SCIP_Bool mayroundup;
    821 SCIP_Bool roundup;
    822 SCIP_Bool prefvar;
    823 SCIP_Real frac;
    824 SCIP_Real pscostquot;
    825
    826 var = nlpcands[c];
    827 mayrounddown = SCIPvarMayRoundDown(var);
    828 mayroundup = SCIPvarMayRoundUp(var);
    829 primsol = nlpcandssol[c];
    830 frac = nlpcandsfrac[c];
    831 prefvar = covercomputed && heurdata->prefercover && SCIPhashmapExists(varincover, var);
    832 pscostquot = SCIP_INVALID;
    833
    834 if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
    835 continue;
    836
    837 if( mayrounddown || mayroundup )
    838 {
    839 /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
    840 if( bestcandmayrounddown || bestcandmayroundup )
    841 {
    842 /* choose rounding direction:
    843 * - if variable may be rounded in both directions, round corresponding to the pseudo cost values
    844 * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
    845 * the current fractional solution
    846 */
    847 roundup = FALSE;
    848 if( mayrounddown && mayroundup )
    849 calcPscostQuot(scip, heurdata, var, primsol, frac, 0, &pscostquot, &roundup, prefvar);
    850 else if( mayrounddown )
    851 calcPscostQuot(scip, heurdata, var, primsol, frac, +1, &pscostquot, &roundup, prefvar);
    852 else
    853 calcPscostQuot(scip, heurdata, var, primsol, frac, -1, &pscostquot, &roundup, prefvar);
    854
    855 assert(!SCIPisInfinity(scip,ABS(pscostquot)));
    856
    857 /* check, if candidate is new best candidate */
    858 if( pscostquot > bestpscostquot )
    859 {
    860 *bestcand = c;
    861 bestpscostquot = pscostquot;
    862 bestcandmayrounddown = mayrounddown;
    863 bestcandmayroundup = mayroundup;
    864 *bestcandroundup = roundup;
    865 }
    866 }
    867 }
    868 else
    869 {
    870 /* the candidate may not be rounded: calculate pseudo cost quotient and preferred direction */
    871 calcPscostQuot(scip, heurdata, var, primsol, frac, 0, &pscostquot, &roundup, prefvar);
    872 assert(!SCIPisInfinity(scip,ABS(pscostquot)));
    873
    874 /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
    875 if( bestcandmayrounddown || bestcandmayroundup || pscostquot > bestpscostquot )
    876 {
    877 *bestcand = c;
    878 bestpscostquot = pscostquot;
    879 bestcandmayrounddown = FALSE;
    880 bestcandmayroundup = FALSE;
    881 *bestcandroundup = roundup;
    882 }
    883 }
    884 }
    885
    886 *bestcandmayround = bestcandmayroundup || bestcandmayrounddown;
    887
    888 return SCIP_OKAY;
    889}
    890
    891/** finds best candidate variable w.r.t. the incumbent solution:
    892 * - prefer variables that may not be rounded without destroying LP feasibility:
    893 * - of these variables, round a variable to its value in direction of incumbent solution, and choose the
    894 * variable that is closest to its rounded value
    895 * - if all remaining fractional variables may be rounded without destroying LP feasibility:
    896 * - round variable in direction that destroys LP feasibility (other direction is checked by SCIProundSol())
    897 * - round variable with least increasing objective value
    898 * - binary variables are prefered
    899 * - variables in a minimal cover or variables that are also fractional in an optimal LP solution might
    900 * also be prefered if a correpsonding parameter is set
    901 */
    902static
    904 SCIP* scip, /**< original SCIP data structure */
    905 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
    906 SCIP_VAR** nlpcands, /**< array of NLP fractional variables */
    907 SCIP_Real* nlpcandssol, /**< array of NLP fractional variables solution values */
    908 SCIP_Real* nlpcandsfrac, /**< array of NLP fractional variables fractionalities */
    909 int nnlpcands, /**< number of NLP fractional variables */
    910 SCIP_SOL* bestsol, /**< incumbent solution */
    911 SCIP_HASHMAP* varincover, /**< hash map for variables */
    912 SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
    913 int* bestcand, /**< pointer to store the index of the best candidate variable */
    914 SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
    915 SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
    916 )
    917{
    918 SCIP_Real bestobjgain;
    919 SCIP_Real bestfrac;
    920 SCIP_Bool bestcandmayrounddown;
    921 SCIP_Bool bestcandmayroundup;
    922 int c;
    923
    924 /* check preconditions */
    925 assert(scip != NULL);
    926 assert(heurdata != NULL);
    927 assert(nlpcands != NULL);
    928 assert(nlpcandsfrac != NULL);
    929 assert(nlpcandssol != NULL);
    930 assert(bestcand != NULL);
    931 assert(bestcandmayround != NULL);
    932 assert(bestcandroundup != NULL);
    933
    934 bestcandmayrounddown = TRUE;
    935 bestcandmayroundup = TRUE;
    936 bestobjgain = SCIPinfinity(scip);
    937 bestfrac = SCIP_INVALID;
    938
    939 for( c = 0; c < nnlpcands; ++c )
    940 {
    941 SCIP_VAR* var;
    942 SCIP_Real bestsolval;
    943 SCIP_Real solval;
    944 SCIP_Real obj;
    945 SCIP_Real frac;
    946 SCIP_Real objgain;
    947
    948 SCIP_Bool mayrounddown;
    949 SCIP_Bool mayroundup;
    950 SCIP_Bool roundup;
    951
    952 var = nlpcands[c];
    953 mayrounddown = SCIPvarMayRoundDown(var);
    954 mayroundup = SCIPvarMayRoundUp(var);
    955 solval = nlpcandssol[c];
    956 frac = nlpcandsfrac[c];
    957 obj = SCIPvarGetObj(var);
    958 bestsolval = SCIPgetSolVal(scip, bestsol, var);
    959
    960 /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
    961 if( SCIPisLT(scip, solval, SCIPvarGetLbLocal(var)) || SCIPisGT(scip, solval, SCIPvarGetUbLocal(var)) )
    962 continue;
    963
    964 /* select default rounding direction
    965 * try to avoid variability; decide randomly if the LP solution can contain some noise
    966 */
    967 if( SCIPisEQ(scip, solval, bestsolval) )
    968 roundup = (SCIPrandomGetInt(heurdata->randnumgen, 0, 1) == 0);
    969 else
    970 roundup = (solval < bestsolval);
    971
    972 if( mayrounddown || mayroundup )
    973 {
    974 /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
    975 if( bestcandmayrounddown || bestcandmayroundup )
    976 {
    977 /* choose rounding direction:
    978 * - if variable may be rounded in both directions, round corresponding to its value in incumbent solution
    979 * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
    980 * the current fractional solution with SCIProundSol()
    981 */
    982 if( !mayrounddown || !mayroundup )
    983 roundup = mayrounddown;
    984
    985 if( roundup )
    986 {
    987 frac = 1.0 - frac;
    988 objgain = frac*obj;
    989 }
    990 else
    991 objgain = -frac*obj;
    992
    993 /* penalize too small fractions */
    994 if( SCIPisEQ(scip, frac, 0.01) )
    995 {
    996 /* try to avoid variability; decide randomly if the LP solution can contain some noise.
    997 * use a 1:SCIP_PROBINGSCORE_PENALTYRATIO chance for increasing the fractionality, i.e., the score.
    998 */
    999 if( SCIPrandomGetInt(heurdata->randnumgen, 0, SCIP_PROBINGSCORE_PENALTYRATIO) == 0 )
    1000 objgain *= 1000.0;
    1001 }
    1002 else if( frac < 0.01 )
    1003 objgain *= 1000.0;
    1004
    1005 /* prefer decisions on binary variables */
    1006 if( !SCIPvarIsBinary(var) )
    1007 objgain *= 1000.0;
    1008
    1009 /* prefer decisions on cover variables */
    1010 if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
    1011 objgain *= 1000.0;
    1012
    1013 /* check, if candidate is new best candidate */
    1014 if( SCIPisLT(scip, objgain, bestobjgain) || (SCIPisEQ(scip, objgain, bestobjgain) && frac < bestfrac) )
    1015 {
    1016 *bestcand = c;
    1017 bestobjgain = objgain;
    1018 bestfrac = frac;
    1019 bestcandmayrounddown = mayrounddown;
    1020 bestcandmayroundup = mayroundup;
    1021 *bestcandroundup = roundup;
    1022 }
    1023 }
    1024 }
    1025 else
    1026 {
    1027 /* the candidate may not be rounded */
    1028 if( roundup )
    1029 frac = 1.0 - frac;
    1030
    1031 /* penalize too small fractions */
    1032 if( SCIPisEQ(scip, frac, 0.01) )
    1033 {
    1034 /* try to avoid variability; decide randomly if the LP solution can contain some noise.
    1035 * use a 1:SCIP_PROBINGSCORE_PENALTYRATIO chance for increasing the fractionality, i.e., the score.
    1036 */
    1037 if( SCIPrandomGetInt(heurdata->randnumgen, 0, SCIP_PROBINGSCORE_PENALTYRATIO) == 0 )
    1038 frac += 10.0;
    1039 }
    1040 else if( frac < 0.01 )
    1041 frac += 10.0;
    1042
    1043 /* prefer decisions on binary variables */
    1044 if( !SCIPvarIsBinary(var) )
    1045 frac *= 1000.0;
    1046
    1047 /* prefer decisions on cover variables */
    1048 if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
    1049 frac *= 1000.0;
    1050
    1051 /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
    1052 if( bestcandmayrounddown || bestcandmayroundup || frac < bestfrac )
    1053 {
    1054 *bestcand = c;
    1055 bestfrac = frac;
    1056 bestcandmayrounddown = FALSE;
    1057 bestcandmayroundup = FALSE;
    1058 *bestcandroundup = roundup;
    1059 }
    1060 }
    1061 }
    1062
    1063 *bestcandmayround = bestcandmayroundup || bestcandmayrounddown;
    1064
    1065 return SCIP_OKAY;
    1066}
    1067
    1068/** finds best candidate variable w.r.t. both, the LP and the NLP solution:
    1069 * - choose a variable for which the sum of the distances from the relaxations' solutions to a common
    1070 * integer value is minimal
    1071 * - binary variables are prefered
    1072 * - variables in a minimal cover might be prefered if a corresponding parameter is set
    1073 */
    1074static
    1076 SCIP* scip, /**< original SCIP data structure */
    1077 SCIP_HEURDATA* heurdata, /**< heuristic data structure */
    1078 SCIP_VAR** pseudocands, /**< array of non-fixed variables */
    1079 SCIP_Real* pseudocandsnlpsol, /**< array of NLP solution values */
    1080 SCIP_Real* pseudocandslpsol, /**< array of LP solution values */
    1081 int npseudocands, /**< number of NLP fractional variables */
    1082 SCIP_HASHMAP* varincover, /**< hash map for variables */
    1083 SCIP_Bool covercomputed, /**< has a minimal cover been computed? */
    1084 int* bestcand, /**< pointer to store the index of the best candidate variable */
    1085 SCIP_Real* bestboundval, /**< pointer to store the bound, the best candidate should be rounded to */
    1086 SCIP_Bool* bestcandmayround, /**< pointer to store whether best candidate is trivially roundable */
    1087 SCIP_Bool* bestcandroundup /**< pointer to store whether best candidate should be rounded up */
    1088 )
    1089{
    1090 SCIP_Real bestfrac;
    1091 int c;
    1092
    1093 /* check preconditions */
    1094 assert(scip != NULL);
    1095 assert(heurdata != NULL);
    1096 assert(pseudocands != NULL);
    1097 assert(pseudocandsnlpsol != NULL);
    1098 assert(pseudocandslpsol != NULL);
    1099 assert(covercomputed == (varincover != NULL));
    1100 assert(bestcand != NULL);
    1101 assert(bestcandmayround != NULL);
    1102 assert(bestcandroundup != NULL);
    1103
    1104 bestfrac = SCIP_INVALID;
    1105
    1106 for( c = 0; c < npseudocands; ++c )
    1107 {
    1108 SCIP_VAR* var;
    1109 SCIP_Bool mayround;
    1110 SCIP_Bool roundup;
    1111
    1112 SCIP_Real frac;
    1113 SCIP_Real lpsol;
    1114 SCIP_Real nlpsol;
    1115 SCIP_Real lpsolfloor;
    1116 SCIP_Real nlpsolfloor;
    1117 SCIP_Real lpsolceil;
    1118 SCIP_Real nlpsolceil;
    1119 SCIP_Real boundval;
    1120 SCIP_Real floorval;
    1121 SCIP_Real ceilval;
    1122
    1123 var = pseudocands[c];
    1124 lpsol = pseudocandslpsol[c];
    1125 nlpsol = pseudocandsnlpsol[c];
    1126
    1127 assert(SCIPvarGetUbLocal(var)-SCIPvarGetLbLocal(var) > 0.5);
    1128 assert(SCIPisLE(scip, SCIPvarGetLbLocal(var), lpsol) && SCIPisLE(scip, lpsol, SCIPvarGetUbLocal(var)));
    1129
    1130 /* since we are not solving the NLP after each fixing, the old NLP solution might be outside the propagated bounds */
    1131 if( SCIPisLT(scip, nlpsol, SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpsol, SCIPvarGetUbLocal(var)) )
    1132 continue;
    1133
    1134 mayround = SCIPvarMayRoundDown(var) || SCIPvarMayRoundUp(var);
    1135
    1136 /* if this candidate is trivially roundable, and we already know a candidate that is not, continue */
    1137 if( mayround && !(*bestcandmayround) )
    1138 continue;
    1139
    1140 if( SCIPisFeasEQ(scip, lpsol, nlpsol) && SCIPisFeasIntegral(scip, lpsol))
    1141 continue;
    1142
    1143 lpsolfloor = SCIPfeasFloor(scip, lpsol);
    1144 nlpsolfloor = SCIPfeasFloor(scip, nlpsol);
    1145 lpsolceil = SCIPfeasCeil(scip, lpsol);
    1146 nlpsolceil = SCIPfeasCeil(scip, nlpsol);
    1147 floorval = MIN(lpsolfloor,nlpsolfloor);
    1148 ceilval = MAX(lpsolceil,nlpsolceil);
    1149
    1150 /* if both values are in the same interval, find out which integer is (in sum) the closer one, this will be the
    1151 * new bound. The minima and maxima are necessary since one or both values with be integer
    1152 */
    1153 if( SCIPvarIsBinary(var) || ceilval-floorval < 1.5 )
    1154 {
    1155 frac = 0.33*(lpsol-floorval) + 0.67*(nlpsol-floorval);
    1156 if( frac < 0.5 )
    1157 {
    1158 roundup = FALSE;
    1159 boundval = MIN(lpsolfloor,nlpsolfloor);
    1160 }
    1161 else
    1162 {
    1163 roundup = TRUE;
    1164 frac = 1.0-frac;
    1165 boundval = MAX(nlpsolceil,lpsolceil);
    1166 }
    1167 }
    1168 else
    1169 {
    1170 /* determine new bound in the middle of both relaxations, such that the NLP stays feasible */
    1171 SCIP_Real midval;
    1172 midval = (nlpsol+lpsol)/2.0;
    1173 roundup = nlpsol > lpsol;
    1174 frac = ABS(nlpsol-lpsol);
    1175
    1176 if( roundup )
    1177 boundval = SCIPfeasCeil(scip, midval);
    1178 else
    1179 boundval = SCIPfeasFloor(scip, midval);
    1180
    1181 assert(roundup == SCIPisGT(scip, nlpsol, boundval));
    1182 }
    1183
    1184 /* penalize too small fractions */
    1185 if( SCIPisEQ(scip, frac, 0.01) )
    1186 {
    1187 /* try to avoid variability; decide randomly if the LP solution can contain some noise.
    1188 * use a 1:SCIP_PROBINGSCORE_PENALTYRATIO chance for increasing the fractionality, i.e., the score.
    1189 */
    1190 if( SCIPrandomGetInt(heurdata->randnumgen, 0, SCIP_PROBINGSCORE_PENALTYRATIO) == 0 )
    1191 frac += 10.0;
    1192 }
    1193 else if( frac < 0.01 )
    1194 frac += 10.0;
    1195
    1196 /* prefer decisions on binary variables */
    1197 if( !SCIPvarIsBinary(var) )
    1198 frac *= 1000.0;
    1199
    1200 /* prefer decisions on cover variables */
    1201 if( covercomputed && heurdata->prefercover && !SCIPhashmapExists(varincover, var) )
    1202 frac *= 1000.0;
    1203
    1204 /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
    1205 if( frac < bestfrac || (*bestcandmayround && !mayround) )
    1206 {
    1207 *bestcand = c;
    1208 bestfrac = frac;
    1209 *bestcandmayround = FALSE;
    1210 *bestcandroundup = roundup;
    1211 *bestboundval = boundval;
    1212 }
    1213 assert(bestfrac < SCIP_INVALID);
    1214 }
    1215
    1216 if( *bestcandroundup )
    1217 *bestboundval -= 0.5;
    1218 else
    1219 *bestboundval += 0.5;
    1220
    1221 return SCIP_OKAY;
    1222}
    1223
    1224/** creates a new solution for the original problem by copying the solution of the subproblem */
    1225static
    1227 SCIP* scip, /**< original SCIP data structure */
    1228 SCIP* subscip, /**< SCIP structure of the subproblem */
    1229 SCIP_HEUR* heur, /**< heuristic structure */
    1230 SCIP_HASHMAP* varmap, /**< hash map for variables */
    1231 SCIP_SOL* subsol, /**< solution of the subproblem */
    1232 SCIP_Bool* success /**< used to store whether new solution was found or not */
    1233 )
    1234{
    1235 SCIP_VAR** vars; /* the original problem's variables */
    1236 SCIP_Real* subsolvals; /* solution values of the subproblem */
    1237 SCIP_SOL* newsol; /* solution to be created for the original problem */
    1238 int nvars; /* the original problem's number of variables */
    1239 SCIP_VAR* subvar;
    1240 int i;
    1241
    1242 assert(scip != NULL);
    1243 assert(subscip != NULL);
    1244 assert(subsol != NULL);
    1245
    1246 /* get variables' data */
    1247 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    1248
    1249 SCIP_CALL( SCIPallocBufferArray(scip, &subsolvals, nvars) );
    1250
    1251 /* copy the solution */
    1252 for( i = 0; i < nvars; ++i )
    1253 {
    1254 subvar = (SCIP_VAR*) SCIPhashmapGetImage(varmap, vars[i]);
    1255 if( subvar == NULL )
    1256 subsolvals[i] = MIN(MAX(0.0, SCIPvarGetLbLocal(vars[i])), SCIPvarGetUbLocal(vars[i])); /*lint !e666*/
    1257 else
    1258 subsolvals[i] = SCIPgetSolVal(subscip, subsol, subvar);
    1259 }
    1260
    1261 /* create new solution for the original problem */
    1262 SCIP_CALL( SCIPcreateSol(scip, &newsol, heur) );
    1263 SCIP_CALL( SCIPsetSolVals(scip, newsol, nvars, vars, subsolvals) );
    1264
    1265 /* try to add new solution to scip and free it immediately */
    1266 SCIP_CALL( SCIPtrySolFree(scip, &newsol, FALSE, FALSE, TRUE, TRUE, TRUE, success) );
    1267
    1268 SCIPfreeBufferArray(scip, &subsolvals);
    1269
    1270 return SCIP_OKAY;
    1271}
    1272
    1273/** todo setup and solve the subMIP */
    1274static
    1276 SCIP* scip, /**< SCIP data structure */
    1277 SCIP* subscip, /**< NLP diving subscip */
    1278 SCIP_HEUR* heur, /**< heuristic data structure */
    1279 SCIP_VAR** covervars, /**< variables in the cover, should be fixed locally */
    1280 int ncovervars, /**< number of variables in the cover */
    1281 SCIP_Bool* success /**< pointer to store whether a solution was found */
    1282 )
    1283{
    1284 SCIP_HASHMAP* varmap;
    1285 SCIP_SOL** subsols;
    1286 int c;
    1287 int nsubsols;
    1288
    1289 assert(subscip != NULL);
    1290 assert(scip != NULL);
    1291 assert(heur != NULL);
    1292
    1293 /* create the variable mapping hash map */
    1294 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(subscip), SCIPgetNVars(scip)) );
    1295
    1296 *success = FALSE;
    1297
    1298 /* copy original problem to subproblem; do not copy pricers */
    1299 SCIP_CALL( SCIPcopyConsCompression(scip, subscip, varmap, NULL, "undercoversub", NULL, NULL, 0, FALSE, FALSE, FALSE,
    1300 TRUE, NULL) );
    1301
    1302 /* assert that cover variables are fixed in source and target SCIP */
    1303 for( c = 0; c < ncovervars; c++)
    1304 {
    1305 assert(SCIPhashmapGetImage(varmap, covervars[c]) != NULL); /* cover variable cannot be relaxation-only, thus must have been copied */
    1306 assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(covervars[c]), SCIPvarGetUbLocal(covervars[c])));
    1307 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal((SCIP_VAR*) SCIPhashmapGetImage(varmap, covervars[c])),
    1308 SCIPvarGetUbGlobal((SCIP_VAR*) SCIPhashmapGetImage(varmap, covervars[c]))));
    1309 }
    1310
    1311 /* set parameters for sub-SCIP */
    1312
    1313 /* do not abort subproblem on CTRL-C */
    1314 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
    1315
    1316#ifdef SCIP_DEBUG
    1317 /* for debugging, enable full output */
    1318 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) );
    1319 SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 100000000) );
    1320#else
    1321 /* disable statistic timing inside sub SCIP and output to console */
    1322 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
    1323 SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) );
    1324#endif
    1325
    1326 /* set limits for the subproblem */
    1327 SCIP_CALL( SCIPcopyLimits(scip, subscip) );
    1328 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", (SCIP_Longint)100) );
    1329 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", (SCIP_Longint)500) );
    1330
    1331 /* forbid recursive call of heuristics and separators solving sub-SCIPs */
    1332 SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
    1333
    1334 /* disable cutting plane separation */
    1336
    1337 /* disable expensive presolving */
    1339
    1340 /* use best estimate node selection */
    1341 if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") )
    1342 {
    1343 SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) );
    1344 }
    1345
    1346 /* use inference branching */
    1347 if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") )
    1348 {
    1349 SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) );
    1350 }
    1351
    1352 /* enable conflict analysis, disable analysis of boundexceeding LPs, and restrict conflict pool */
    1353 if( !SCIPisParamFixed(subscip, "conflict/enable") )
    1354 {
    1355 SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/enable", TRUE) );
    1356 }
    1357 if( !SCIPisParamFixed(subscip, "conflict/useboundlp") )
    1358 {
    1359 SCIP_CALL( SCIPsetCharParam(subscip, "conflict/useboundlp", 'o') );
    1360 }
    1361 if( !SCIPisParamFixed(subscip, "conflict/maxstoresize") )
    1362 {
    1363 SCIP_CALL( SCIPsetIntParam(subscip, "conflict/maxstoresize", 100) );
    1364 }
    1365
    1366 if( SCIPgetNSols(scip) > 0 )
    1367 {
    1368 SCIP_Real upperbound;
    1369 SCIP_Real cutoffbound;
    1370 SCIP_Real minimprove;
    1371
    1373
    1374 upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip);
    1375 minimprove = 0.01;
    1376
    1378 {
    1379 cutoffbound = (1-minimprove)*SCIPgetUpperbound(scip) + minimprove*SCIPgetLowerbound(scip);
    1380 }
    1381 else
    1382 {
    1383 if( SCIPgetUpperbound(scip) >= 0 )
    1384 cutoffbound = (1 - minimprove)*SCIPgetUpperbound(scip);
    1385 else
    1386 cutoffbound = (1 + minimprove)*SCIPgetUpperbound(scip);
    1387 }
    1388 cutoffbound = MIN(upperbound, cutoffbound);
    1389 SCIP_CALL( SCIPsetObjlimit(subscip, cutoffbound) );
    1390 }
    1391
    1392 SCIP_CALL_ABORT( SCIPsolve(subscip) );
    1393
    1394 /* check, whether a solution was found;
    1395 * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted
    1396 */
    1397 nsubsols = SCIPgetNSols(subscip);
    1398 subsols = SCIPgetSols(subscip);
    1399 for( c = 0; c < nsubsols && !(*success); ++c )
    1400 {
    1401 SCIP_CALL( createNewSol(scip, subscip, heur, varmap, subsols[c], success) );
    1402 }
    1403
    1404 SCIPhashmapFree(&varmap);
    1405
    1406 return SCIP_OKAY;
    1407}
    1408
    1409
    1410/** solves subproblem and passes best feasible solution to original SCIP instance */
    1411static
    1413 SCIP* scip, /**< SCIP data structure of the original problem */
    1414 SCIP_HEUR* heur, /**< heuristic data structure */
    1415 SCIP_VAR** covervars, /**< variables in the cover, should be fixed locally */
    1416 int ncovervars, /**< number of variables in the cover */
    1417 SCIP_Bool* success /**< pointer to store whether a solution was found */
    1418 )
    1419{
    1420 SCIP* subscip;
    1421 SCIP_RETCODE retcode;
    1422
    1423 /* check whether there is enough time and memory left */
    1424 SCIP_CALL( SCIPcheckCopyLimits(scip, success) );
    1425
    1426 if( !(*success) )
    1427 return SCIP_OKAY;
    1428
    1429 /* create subproblem */
    1430 SCIP_CALL( SCIPcreate(&subscip) );
    1431
    1432 retcode = doSolveSubMIP(scip, subscip, heur, covervars, ncovervars, success);
    1433
    1434 /* free sub-SCIP even if an error occurred during the subscip solve */
    1435 SCIP_CALL( SCIPfree(&subscip) );
    1436
    1437 SCIP_CALL( retcode );
    1438
    1439 return SCIP_OKAY;
    1440}
    1441
    1442/* ---------------- Callback methods of event handler ---------------- */
    1443
    1444/* exec the event handler
    1445 *
    1446 * We update the number of variables fixed in the cover
    1447 */
    1448static
    1449SCIP_DECL_EVENTEXEC(eventExecNlpdiving)
    1450{
    1451 SCIP_EVENTTYPE eventtype;
    1452 SCIP_HEURDATA* heurdata;
    1453 SCIP_VAR* var;
    1454
    1455 SCIP_Real oldbound;
    1456 SCIP_Real newbound;
    1457 SCIP_Real otherbound;
    1458
    1459 assert(eventhdlr != NULL);
    1460 assert(eventdata != NULL);
    1461 assert(event != NULL);
    1462
    1464
    1465 heurdata = (SCIP_HEURDATA*)eventdata;
    1466 assert(heurdata != NULL);
    1467 assert(0 <= heurdata->nfixedcovervars && heurdata->nfixedcovervars <= SCIPgetNVars(scip));
    1468
    1469 oldbound = SCIPeventGetOldbound(event);
    1470 newbound = SCIPeventGetNewbound(event);
    1471 var = SCIPeventGetVar(event);
    1472
    1473 eventtype = SCIPeventGetType(event);
    1474 otherbound = (eventtype & SCIP_EVENTTYPE_LBCHANGED) ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
    1475
    1476 switch( eventtype )
    1477 {
    1480 /* if cover variable is now fixed */
    1481 if( SCIPisFeasEQ(scip, newbound, otherbound) && !SCIPisFeasEQ(scip, oldbound, otherbound) )
    1482 {
    1483 assert(!SCIPisEQ(scip, oldbound, otherbound));
    1484 ++(heurdata->nfixedcovervars);
    1485 }
    1486 break;
    1489 /* if cover variable is now unfixed */
    1490 if( SCIPisFeasEQ(scip, oldbound, otherbound) && !SCIPisFeasEQ(scip, newbound, otherbound) )
    1491 {
    1492 assert(!SCIPisEQ(scip, newbound, otherbound));
    1493 --(heurdata->nfixedcovervars);
    1494 }
    1495 break;
    1496 default:
    1497 SCIPerrorMessage("invalid event type.\n");
    1498 return SCIP_INVALIDDATA;
    1499 }
    1500 assert(0 <= heurdata->nfixedcovervars && heurdata->nfixedcovervars <= SCIPgetNVars(scip));
    1501
    1502 /* SCIPdebugMsg(scip, "changed bound of cover variable <%s> from %f to %f (nfixedcovervars: %d).\n", SCIPvarGetName(var),
    1503 oldbound, newbound, heurdata->nfixedcovervars); */
    1504
    1505 return SCIP_OKAY;
    1506}
    1507
    1508
    1509/*
    1510 * Callback methods
    1511 */
    1512
    1513/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    1514static
    1515SCIP_DECL_HEURCOPY(heurCopyNlpdiving)
    1516{ /*lint --e{715}*/
    1517 assert(scip != NULL);
    1518 assert(heur != NULL);
    1519
    1521
    1522 /* call inclusion method of primal heuristic */
    1524
    1525 return SCIP_OKAY;
    1526}
    1527
    1528/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    1529static
    1530SCIP_DECL_HEURFREE(heurFreeNlpdiving) /*lint --e{715}*/
    1531{ /*lint --e{715}*/
    1532 SCIP_HEURDATA* heurdata;
    1533
    1534 assert(heur != NULL);
    1535 assert(scip != NULL);
    1536
    1538
    1539 /* free heuristic data */
    1540 heurdata = SCIPheurGetData(heur);
    1541 assert(heurdata != NULL);
    1542 SCIPfreeBlockMemory(scip, &heurdata);
    1543 SCIPheurSetData(heur, NULL);
    1544
    1545 return SCIP_OKAY;
    1546}
    1547
    1548
    1549/** initialization method of primal heuristic (called after problem was transformed) */
    1550static
    1551SCIP_DECL_HEURINIT(heurInitNlpdiving) /*lint --e{715}*/
    1552{ /*lint --e{715}*/
    1553 SCIP_HEURDATA* heurdata;
    1554
    1555 assert(heur != NULL);
    1556
    1558
    1559 /* get heuristic data */
    1560 heurdata = SCIPheurGetData(heur);
    1561 assert(heurdata != NULL);
    1562
    1563 /* create working solution */
    1564 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    1565
    1566 /* create random number generator */
    1567 SCIP_CALL( SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE) );
    1568
    1569 /* initialize data */
    1570 heurdata->nnlpiterations = 0;
    1571 heurdata->nsuccess = 0;
    1572 heurdata->nfixedcovervars = 0;
    1574 heurdata->nnlpsolves = 0;
    1575 heurdata->nfailcutoff = 0;
    1576 heurdata->nfaildepth = 0;
    1577 heurdata->nfailnlperror = 0;
    1578 );
    1579
    1580 return SCIP_OKAY;
    1581}
    1582
    1583
    1584/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    1585static
    1586SCIP_DECL_HEUREXIT(heurExitNlpdiving) /*lint --e{715}*/
    1587{ /*lint --e{715}*/
    1588 SCIP_HEURDATA* heurdata;
    1589
    1590 assert(heur != NULL);
    1591
    1593
    1594 /* get heuristic data */
    1595 heurdata = SCIPheurGetData(heur);
    1596 assert(heurdata != NULL);
    1597
    1598 /* free random number generator */
    1599 SCIPfreeRandom(scip, &heurdata->randnumgen);
    1600
    1601 /* free working solution */
    1602 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    1603
    1605 if( strstr(SCIPgetProbName(scip), "_covering") == NULL && SCIPheurGetNCalls(heur) > 0 )
    1606 {
    1607 SCIPstatisticMessage("%-30s %5" SCIP_LONGINT_FORMAT " sols in %5" SCIP_LONGINT_FORMAT " runs, %6.1fs, %7d NLP iters in %5d NLP solves, %5.1f avg., %3d%% success %3d%% cutoff %3d%% depth %3d%% nlperror\n",
    1609 heurdata->nnlpiterations, heurdata->nnlpsolves, heurdata->nnlpiterations/MAX(1.0,(SCIP_Real)heurdata->nnlpsolves),
    1610 (100*heurdata->nsuccess) / (int)SCIPheurGetNCalls(heur), (100*heurdata->nfailcutoff) / (int)SCIPheurGetNCalls(heur), (100*heurdata->nfaildepth) / (int)SCIPheurGetNCalls(heur), (100*heurdata->nfailnlperror) / (int)SCIPheurGetNCalls(heur)
    1611 );
    1612 }
    1613 );
    1614
    1615 return SCIP_OKAY;
    1616}
    1617
    1618
    1619/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
    1620static
    1621SCIP_DECL_HEURINITSOL(heurInitsolNlpdiving)
    1622{ /*lint --e{715}*/
    1623 SCIP_HEURDATA* heurdata;
    1624
    1625 assert(heur != NULL);
    1626
    1627 /* get heuristic data */
    1628 heurdata = SCIPheurGetData(heur);
    1629 assert(heurdata != NULL);
    1630
    1631 /* store nlpdiving timing */
    1632 heurdata->inittiming = SCIPheurGetTimingmask(heur);
    1633
    1634 /* disable nlpdiving heuristic */
    1637
    1638 return SCIP_OKAY;
    1639}
    1640
    1641
    1642/** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
    1643static
    1644SCIP_DECL_HEUREXITSOL(heurExitsolNlpdiving)
    1645{ /*lint --e{715}*/
    1646 SCIP_HEURDATA* heurdata;
    1647
    1648 assert(heur != NULL);
    1649
    1650 /* get heuristic data */
    1651 heurdata = SCIPheurGetData(heur);
    1652 assert(heurdata != NULL);
    1653
    1654 /* reset nlpdiving timing */
    1655 SCIPheurSetTimingmask(heur, heurdata->inittiming);
    1656
    1657 return SCIP_OKAY;
    1658}
    1659
    1660
    1661/** execution method of primal heuristic */
    1662static
    1663SCIP_DECL_HEUREXEC(heurExecNlpdiving)
    1664{ /*lint --e{715}*/
    1665 SCIP_HEURDATA* heurdata;
    1666 SCIP_NLPSOLSTAT nlpsolstat;
    1667 SCIP_LPSOLSTAT lpsolstat;
    1668 SCIP_SOL* nlpstartsol;
    1669 SCIP_SOL* bestsol;
    1670 SCIP_VAR** nlpcands;
    1671 SCIP_VAR** covervars;
    1672 SCIP_Real* nlpcandssol;
    1673 SCIP_Real* nlpcandsfrac;
    1674 SCIP_Real* pseudocandslpsol;
    1675 SCIP_Real* pseudocandsnlpsol;
    1676 SCIP_HASHMAP* varincover;
    1677 SCIP_Real searchubbound;
    1678 SCIP_Real searchavgbound;
    1679 SCIP_Real searchbound;
    1680 SCIP_Real objval;
    1681 SCIP_Real oldobjval;
    1682 SCIP_Real fixquot;
    1683 SCIP_Real bestboundval;
    1684 SCIP_Bool bestcandmayround;
    1685 SCIP_Bool bestcandroundup;
    1686 SCIP_Bool nlperror;
    1687 SCIP_Bool lperror;
    1688 SCIP_Bool cutoff;
    1689 SCIP_Bool backtracked;
    1690 SCIP_Bool solvenlp;
    1691 SCIP_Bool covercomputed;
    1692 SCIP_Bool solvesubmip;
    1693 SCIP_Longint ncalls;
    1694 SCIP_Longint nsolsfound;
    1695 SCIP_VAR* backtrackvar; /* (first) variable to fix differently in backtracking */
    1696 SCIP_Real backtrackvarval; /* (fractional) value of backtrack variable */
    1697 SCIP_Bool backtrackroundup; /* whether variable should be rounded up in backtracking */
    1698 int backtrackdepth; /* depth where to go when backtracking */
    1699 int avgnnlpiterations;
    1700 int maxnnlpiterations;
    1701 int npseudocands;
    1702 int nlpbranchcands;
    1703 int ncovervars;
    1704 int nnlpcands;
    1705 int startnnlpcands;
    1706 int depth;
    1707 int maxdepth;
    1708 int maxdivedepth;
    1709 int divedepth;
    1710 int lastnlpsolvedepth;
    1711 int nfeasnlps;
    1712 int bestcand;
    1713 int c;
    1714
    1715 assert(scip != NULL);
    1716 assert(result != NULL);
    1717 assert(SCIPisNLPConstructed(scip));
    1718 assert(SCIPgetNNlpis(scip) >= 1);
    1719
    1721
    1722 *result = SCIP_DIDNOTRUN;
    1723
    1724 /* do not call heuristic of node was already detected to be infeasible */
    1725 if( nodeinfeasible )
    1726 return SCIP_OKAY;
    1727
    1728 /* only call heuristic if the current node will not be cutoff, e.g., due to a (integer and NLP-)feasible LP solution */
    1730 return SCIP_OKAY;
    1731
    1732 /* get heuristic's data */
    1733 heurdata = SCIPheurGetData(heur);
    1734 assert(heurdata != NULL);
    1735
    1736 /* do not call heuristic if it barely succeded */
    1737 if( (SCIPheurGetNSolsFound(heur) + 1.0) / (SCIP_Real)(SCIPheurGetNCalls(heur) + 1.0) < heurdata->minsuccquot )
    1738 return SCIP_OKAY;
    1739
    1740 *result = SCIP_DELAYED;
    1741
    1742 /* don't dive two times at the same node */
    1744 return SCIP_OKAY;
    1745
    1746 *result = SCIP_DIDNOTRUN;
    1747
    1748 /* only try to dive if we are in the correct part of the tree, given by minreldepth and maxreldepth */
    1749 depth = SCIPgetDepth(scip);
    1750 maxdepth = SCIPgetMaxDepth(scip);
    1751 maxdepth = MAX(maxdepth, 30);
    1752 if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
    1753 return SCIP_OKAY;
    1754
    1755 /* calculate the maximal number of NLP iterations until heuristic is aborted
    1756 * maximal number is maxnlpiterabs plus a success-depending multiplier of maxnlpiterrel
    1757 */
    1758 ncalls = SCIPheurGetNCalls(heur);
    1759 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
    1760 maxnnlpiterations = heurdata->maxnlpiterabs;
    1761 maxnnlpiterations += (int)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxnlpiterrel);
    1762
    1763 /* don't try to dive if we took too many NLP iterations during diving */
    1764 if( heurdata->nnlpiterations >= maxnnlpiterations )
    1765 return SCIP_OKAY;
    1766
    1767 /* allow at least a bit more than the so far average number of NLP iterations per dive */
    1768 avgnnlpiterations = (int)(heurdata->nnlpiterations / MAX(ncalls, 1.0));
    1769 maxnnlpiterations = (int)MAX((SCIP_Real) maxnnlpiterations, (SCIP_Real) heurdata->nnlpiterations + 1.2*avgnnlpiterations);
    1770
    1771 /* don't try to dive if there are no unfixed discrete variables */
    1772 SCIP_CALL( SCIPgetPseudoBranchCands(scip, NULL, &npseudocands, NULL) );
    1773 if( npseudocands == 0 )
    1774 return SCIP_OKAY;
    1775
    1776 *result = SCIP_DIDNOTFIND;
    1777
    1778 /* set starting point to lp solution */
    1780
    1781 /* solve NLP relaxation if not solved already */
    1782 nlpsolstat = SCIPgetNLPSolstat(scip);
    1783 if( nlpsolstat > SCIP_NLPSOLSTAT_FEASIBLE )
    1784 {
    1785 SCIP_NLPSTATISTICS nlpstatistics;
    1786
    1788 .iterlimit = maxnnlpiterations - heurdata->nnlpiterations,
    1789 .fastfail = heurdata->nlpfastfail ? SCIP_NLPPARAM_FASTFAIL_AGGRESSIVE : SCIP_NLPPARAM_FASTFAIL_CONSERVATIVE) ); /*lint !e666*/
    1790 SCIPstatistic( ++heurdata->nnlpsolves );
    1791
    1792 /* update iteration count */
    1794 {
    1795 SCIP_CALL( SCIPgetNLPStatistics(scip, &nlpstatistics) );
    1796 heurdata->nnlpiterations += nlpstatistics.niterations;
    1797 }
    1798
    1799 nlpsolstat = SCIPgetNLPSolstat(scip);
    1800
    1801 /* give up, if no feasible solution found */
    1802 if( nlpsolstat >= SCIP_NLPSOLSTAT_LOCINFEASIBLE )
    1803 {
    1804 SCIPdebugMsg(scip, "initial NLP infeasible or not solvable --> stop\n");
    1805
    1808 heurdata->nfailcutoff++;
    1809 else
    1810 heurdata->nfailnlperror++;
    1811 )
    1812
    1813 return SCIP_OKAY;
    1814 }
    1815 }
    1816
    1817 /* get NLP solution */
    1818 SCIP_CALL( SCIPlinkNLPSol(scip, heurdata->sol) );
    1819
    1820 /* get fractional variables that should be integral */
    1821 SCIP_CALL( getNLPFracVars(scip, heurdata, &nlpcands, &nlpcandssol, &nlpcandsfrac, &nnlpcands) );
    1822 assert(nnlpcands <= npseudocands);
    1823
    1824 /* get LP candidates if LP solution is optimal */
    1825 lpsolstat = SCIPgetLPSolstat(scip);
    1826 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    1827 nlpbranchcands = SCIPgetNLPBranchCands(scip);
    1828 else
    1829 nlpbranchcands = 0;
    1830
    1831 /* don't try to dive, if there are no fractional variables */
    1832 if( nnlpcands == 0 )
    1833 {
    1834 SCIP_Bool success;
    1835
    1836 /* check, if solution was feasible and good enough
    1837 *
    1838 * Note that even if the NLP solver found a feasible solution it does not mean that is satisfy the integrality
    1839 * conditions for fixed variables. This happens because the NLP solver uses relative tolerances for the bound
    1840 * constraints but SCIP uses absolute tolerances for checking the integrality conditions.
    1841 */
    1842#ifdef SCIP_DEBUG
    1843 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, TRUE, TRUE, FALSE, TRUE, TRUE, &success) );
    1844#else
    1845 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, TRUE, TRUE, &success) );
    1846#endif
    1847 if( success )
    1848 {
    1849 SCIPdebugMsg(scip, " -> solution of first NLP was integral, feasible, and good enough\n");
    1850 *result = SCIP_FOUNDSOL;
    1851 }
    1852
    1853 return SCIP_OKAY;
    1854 }
    1855
    1856 /* for guided diving: don't dive, if no feasible solutions exist */
    1857 if( heurdata->varselrule == 'g' && SCIPgetNSols(scip) == 0 )
    1858 return SCIP_OKAY;
    1859
    1860 /* for guided diving: get best solution that should guide the search; if this solution lives in the original variable space,
    1861 * we cannot use it since it might violate the global bounds of the current problem
    1862 */
    1863 if( heurdata->varselrule == 'g' && SCIPsolIsOriginal(SCIPgetBestSol(scip)) )
    1864 return SCIP_OKAY;
    1865
    1866 nlpstartsol = NULL;
    1867 assert(nlpcandsfrac != NULL);
    1868 assert(nlpcands != NULL);
    1869 assert(nlpcandssol != NULL);
    1870
    1871 /* save solution of first NLP, if we may use it later */
    1872 if( heurdata->nlpstart != 'n' )
    1873 {
    1874 SCIP_CALL( SCIPcreateNLPSol(scip, &nlpstartsol, heur) );
    1875 SCIP_CALL( SCIPunlinkSol(scip, nlpstartsol) );
    1876 }
    1877
    1878 /* calculate the objective search bound */
    1879 if( SCIPgetNSolsFound(scip) == 0 )
    1880 {
    1881 if( heurdata->maxdiveubquotnosol > 0.0 )
    1882 searchubbound = SCIPgetLowerbound(scip)
    1883 + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
    1884 else
    1885 searchubbound = SCIPinfinity(scip);
    1886 if( heurdata->maxdiveavgquotnosol > 0.0 )
    1887 searchavgbound = SCIPgetLowerbound(scip)
    1888 + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
    1889 else
    1890 searchavgbound = SCIPinfinity(scip);
    1891 }
    1892 else
    1893 {
    1894 if( heurdata->maxdiveubquot > 0.0 )
    1895 searchubbound = SCIPgetLowerbound(scip)
    1896 + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
    1897 else
    1898 searchubbound = SCIPinfinity(scip);
    1899 if( heurdata->maxdiveavgquot > 0.0 )
    1900 searchavgbound = SCIPgetLowerbound(scip)
    1901 + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
    1902 else
    1903 searchavgbound = SCIPinfinity(scip);
    1904 }
    1905 searchbound = MIN(searchubbound, searchavgbound);
    1906 if( SCIPisObjIntegral(scip) )
    1907 searchbound = SCIPceil(scip, searchbound);
    1908
    1909 /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
    1911 assert(maxdivedepth >= 0);
    1912 maxdivedepth = MIN(maxdivedepth, maxdepth);
    1913 maxdivedepth *= 10;
    1914
    1915 /* initialize local variables */
    1916 backtrackdepth = -1;
    1917 backtrackvar = NULL;
    1918 backtrackvarval = 0.0;
    1919 backtrackroundup = FALSE;
    1920 bestsol = NULL;
    1921 pseudocandsnlpsol = NULL;
    1922 pseudocandslpsol = NULL;
    1923 covervars = NULL;
    1924 covercomputed = FALSE;
    1925 varincover = NULL;
    1926
    1927 /* compute cover, if required */
    1928 if( heurdata->prefercover || heurdata->solvesubmip )
    1929 {
    1930 SCIP_Real timelimit;
    1931 SCIP_Real memorylimit;
    1932
    1933 /* get limits */
    1934 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
    1935 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
    1936 if( !SCIPisInfinity(scip, timelimit) )
    1937 timelimit -= SCIPgetSolvingTime(scip);
    1938
    1939 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
    1940 if( !SCIPisInfinity(scip, memorylimit) )
    1941 {
    1942 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
    1943 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
    1944 }
    1945
    1946 /* compute cover; use local bounds; only cover "and" and nonlinear constraints (no bounddisjunction or indicator),
    1947 * including convex constraints */
    1948 ncovervars = -1;
    1950 if( memorylimit > 2.0*SCIPgetMemExternEstim(scip)/1048576.0 && timelimit > 0.05 )
    1951 {
    1952 SCIP_CALL( SCIPcomputeCoverUndercover(scip, &ncovervars, covervars, timelimit, memorylimit, SCIPinfinity(scip),
    1953 FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 'u', &covercomputed) );
    1954 }
    1955
    1956 if( covercomputed )
    1957 {
    1958 /* a cover can be empty, if the cover computation reveals that all nonlinear constraints are linear w.r.t. current variable fixations */
    1959 assert(ncovervars >= 0);
    1960
    1961 /* create hash map */
    1962 SCIP_CALL( SCIPhashmapCreate(&varincover, SCIPblkmem(scip), ncovervars) );
    1963
    1964 /* process variables in the cover */
    1965 for( c = 0; c < ncovervars; c++ )
    1966 {
    1967 /* insert variable into hash map */
    1968 if( SCIPvarGetType(covervars[c]) != SCIP_VARTYPE_CONTINUOUS )
    1969 {
    1970 assert(!SCIPhashmapExists(varincover, covervars[c]));
    1971 SCIP_CALL( SCIPhashmapInsertInt(varincover, covervars[c], c+1) );
    1972 }
    1973
    1974 /* catch bound change events of cover variables */
    1975 assert(heurdata->eventhdlr != NULL);
    1976 SCIP_CALL( SCIPcatchVarEvent(scip, covervars[c], SCIP_EVENTTYPE_BOUNDCHANGED, heurdata->eventhdlr,
    1977 (SCIP_EVENTDATA*) heurdata, NULL) );
    1978 assert(!SCIPisFeasEQ(scip, SCIPvarGetLbLocal(covervars[c]), SCIPvarGetUbLocal(covervars[c])));
    1979 }
    1980 }
    1981 }
    1982 else
    1983 {
    1984 covervars = NULL;
    1985 ncovervars = 0;
    1986 }
    1987
    1988 /* start diving */
    1990
    1991 /* enables collection of variable statistics during probing */
    1993
    1994 /* get NLP objective value*/
    1995 objval = SCIPgetNLPObjval(scip);
    1996
    1997 SCIPdebugMsg(scip, "(node %" SCIP_LONGINT_FORMAT ") executing nlpdiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n",
    1999
    2000 /* store a copy of the best solution, if guided diving should be used */
    2001 if( heurdata->varselrule == 'g' )
    2002 {
    2003 assert(SCIPgetNSols(scip) > 0);
    2005
    2007 }
    2008
    2009 /* if double diving should be used, create arrays to hold to entire LP and NLP solution */
    2010 if( heurdata->varselrule == 'd' )
    2011 {
    2012 SCIP_CALL( SCIPallocBufferArray(scip, &pseudocandslpsol, npseudocands) );
    2013 SCIP_CALL( SCIPallocBufferArray(scip, &pseudocandsnlpsol, npseudocands) );
    2014 }
    2015
    2016 /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
    2017 * - if possible, we dive at least with the depth 10
    2018 * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
    2019 */
    2020 nlperror = FALSE;
    2021 lperror = FALSE;
    2022 cutoff = FALSE;
    2023 divedepth = 0;
    2024 lastnlpsolvedepth = 0;
    2025 backtracked = FALSE; /* whether we are in backtracking */
    2026 fixquot = heurdata->fixquot;
    2027 nfeasnlps = 1;
    2028 startnnlpcands = nnlpcands;
    2029 solvesubmip = heurdata->solvesubmip;
    2030
    2031 while( !nlperror && !cutoff && (nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_UNKNOWN) && nnlpcands > 0
    2032 && (nfeasnlps < heurdata->maxfeasnlps
    2033 || nnlpcands <= startnnlpcands - divedepth/2
    2034 || (nfeasnlps < maxdivedepth && heurdata->nnlpiterations < maxnnlpiterations && objval < searchbound))
    2035 && !SCIPisStopped(scip) )
    2036 {
    2037 SCIP_VAR* var;
    2038 SCIP_Bool updatepscost;
    2039
    2040 /* open a new probing node if this will not exceed the maximal tree depth, otherwise stop here */
    2042 {
    2044 divedepth++;
    2045 }
    2046 else
    2047 break;
    2048
    2049 bestcand = -1;
    2050 bestcandmayround = TRUE;
    2051 bestcandroundup = FALSE;
    2052 bestboundval = SCIP_INVALID;
    2053 updatepscost = TRUE;
    2054 var = NULL;
    2055
    2056 /* find best candidate variable */
    2057 switch( heurdata->varselrule )
    2058 {
    2059 case 'c':
    2060 SCIP_CALL( chooseCoefVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
    2061 &bestcand, &bestcandmayround, &bestcandroundup) );
    2062 if( bestcand >= 0 )
    2063 {
    2064 var = nlpcands[bestcand];
    2065 bestboundval = nlpcandssol[bestcand];
    2066 }
    2067 break;
    2068 case 'v':
    2069 SCIP_CALL( chooseVeclenVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
    2070 &bestcand, &bestcandmayround, &bestcandroundup) );
    2071 if( bestcand >= 0 )
    2072 {
    2073 var = nlpcands[bestcand];
    2074 bestboundval = nlpcandssol[bestcand];
    2075 }
    2076 break;
    2077 case 'p':
    2078 SCIP_CALL( choosePscostVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
    2079 &bestcand, &bestcandmayround, &bestcandroundup) );
    2080 if( bestcand >= 0 )
    2081 {
    2082 var = nlpcands[bestcand];
    2083 bestboundval = nlpcandssol[bestcand];
    2084 }
    2085 break;
    2086 case 'g':
    2087 SCIP_CALL( chooseGuidedVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, bestsol, varincover, covercomputed,
    2088 &bestcand, &bestcandmayround, &bestcandroundup) );
    2089 if( bestcand >= 0 )
    2090 {
    2091 var = nlpcands[bestcand];
    2092 bestboundval = nlpcandssol[bestcand];
    2093 }
    2094 break;
    2095 case 'd':
    2096 /* double diving only works if we have both relaxations at hand, otherwise we fall back to fractional diving */
    2097 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    2098 {
    2099 SCIP_VAR** pseudocands;
    2100
    2101 SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &npseudocands, NULL) );
    2102 assert(backtrackdepth > 0 || nnlpcands <= npseudocands);
    2103 assert(SCIPgetNLPBranchCands(scip) <= npseudocands);
    2104 SCIP_CALL( SCIPgetSolVals(scip, NULL, npseudocands, pseudocands, pseudocandslpsol) );
    2105 SCIP_CALL( SCIPgetSolVals(scip, heurdata->sol, npseudocands, pseudocands, pseudocandsnlpsol) );
    2106 SCIP_CALL( chooseDoubleVar(scip, heurdata, pseudocands, pseudocandsnlpsol, pseudocandslpsol, npseudocands,
    2107 varincover, covercomputed, &bestcand, &bestboundval, &bestcandmayround, &bestcandroundup) );
    2108 if( bestcand >= 0 )
    2109 var = pseudocands[bestcand];
    2110 break;
    2111 }
    2112 else
    2113 updatepscost = FALSE;
    2114 /*lint -fallthrough*/
    2115 case 'f':
    2116 SCIP_CALL( chooseFracVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
    2117 &bestcand, &bestcandmayround, &bestcandroundup) );
    2118 if( bestcand >= 0 )
    2119 {
    2120 var = nlpcands[bestcand];
    2121 bestboundval = nlpcandssol[bestcand];
    2122 }
    2123 break;
    2124 default:
    2125 SCIPerrorMessage("invalid variable selection rule\n");
    2126 return SCIP_INVALIDDATA;
    2127 }
    2128
    2129 /* if all candidates are roundable, try to round the solution
    2130 * if var == NULL (i.e., bestcand == -1), then all solution candidates are outside bounds
    2131 * this should only happen if they are slightly outside bounds (i.e., still within feastol, relative tolerance),
    2132 * but far enough out to be considered as fractional (within feastol, but using absolute tolerance)
    2133 * in this case, we also try our luck with rounding
    2134 */
    2135 if( (var == NULL || bestcandmayround) && backtrackdepth == -1 )
    2136 {
    2137 SCIP_Bool success;
    2138
    2139 /* create solution from diving NLP and try to round it */
    2140 SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
    2141
    2142 if( success )
    2143 {
    2144 SCIPdebugMsg(scip, "nlpdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
    2145
    2146 /* try to add solution to SCIP */
    2147#ifdef SCIP_DEBUG
    2148 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, TRUE, TRUE, FALSE, FALSE, TRUE, &success) );
    2149#else
    2150 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, TRUE, &success) );
    2151#endif
    2152
    2153 /* check, if solution was feasible and good enough */
    2154 if( success )
    2155 {
    2156 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
    2157 *result = SCIP_FOUNDSOL;
    2158 }
    2159 }
    2160 }
    2161
    2162 /* if all variables have been found to be essentially integral (even though there is some numerical doubt, see comment above), then stop */
    2163 if( var == NULL )
    2164 break;
    2165
    2166 do
    2167 {
    2168 SCIP_Real frac;
    2169 frac = SCIP_INVALID;
    2170
    2171 if( backtracked && backtrackdepth > 0 )
    2172 {
    2173 assert(backtrackvar != NULL);
    2174
    2175 /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
    2176 * occurred or variable was fixed by propagation while backtracking => Abort diving!
    2177 */
    2178 if( SCIPvarGetLbLocal(backtrackvar) >= SCIPvarGetUbLocal(backtrackvar) - 0.5 )
    2179 {
    2180 SCIPdebugMsg(scip, "Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
    2181 SCIPvarGetName(backtrackvar), SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar), backtrackvarval);
    2182 cutoff = TRUE;
    2183 break;
    2184 }
    2185 if( SCIPisFeasLT(scip, backtrackvarval, SCIPvarGetLbLocal(backtrackvar)) || SCIPisFeasGT(scip, backtrackvarval, SCIPvarGetUbLocal(backtrackvar)) )
    2186 {
    2187 SCIPdebugMsg(scip, "selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
    2188 SCIPvarGetName(backtrackvar), SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar), backtrackvarval);
    2189 assert(backtracked);
    2190 break;
    2191 }
    2192
    2193 /* round backtrack variable up or down */
    2194 if( backtrackroundup )
    2195 {
    2196 SCIPdebugMsg(scip, " dive %d/%d, NLP iter %d/%d: var <%s>, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
    2197 divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
    2198 SCIPvarGetName(backtrackvar), backtrackvarval, SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar),
    2199 SCIPfeasCeil(scip, backtrackvarval), SCIPvarGetUbLocal(backtrackvar));
    2200 SCIP_CALL( SCIPchgVarLbProbing(scip, backtrackvar, SCIPfeasCeil(scip, backtrackvarval)) );
    2201 }
    2202 else
    2203 {
    2204 SCIPdebugMsg(scip, " dive %d/%d, NLP iter %d/%d: var <%s>, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
    2205 divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
    2206 SCIPvarGetName(backtrackvar), backtrackvarval, SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar),
    2207 SCIPvarGetLbLocal(backtrackvar), SCIPfeasFloor(scip, backtrackvarval));
    2208 SCIP_CALL( SCIPchgVarUbProbing(scip, backtrackvar, SCIPfeasFloor(scip, backtrackvarval)) );
    2209 }
    2210
    2211 /* forget about backtrack variable */
    2212 backtrackdepth = -1;
    2213
    2214 /* for pseudo cost computation */
    2215 bestcandroundup = backtrackroundup;
    2216 frac = SCIPfrac(scip, backtrackvarval);
    2217 var = backtrackvar;
    2218 }
    2219 else
    2220 {
    2221 assert(var != NULL);
    2222
    2223 /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
    2224 * occurred or variable was fixed by propagation while backtracking => Abort diving!
    2225 */
    2226 if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
    2227 {
    2228 SCIPdebugMsg(scip, "Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
    2229 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestboundval);
    2230 cutoff = TRUE;
    2231 break;
    2232 }
    2233 if( SCIPisFeasLT(scip, bestboundval, SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, bestboundval, SCIPvarGetUbLocal(var)) )
    2234 {
    2235 SCIPdebugMsg(scip, "selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
    2236 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestboundval);
    2237 assert(backtracked);
    2238 break;
    2239 }
    2240
    2241 /* apply rounding of best candidate */
    2242 if( bestcandroundup == !backtracked )
    2243 {
    2244 /* round variable up */
    2245 SCIPdebugMsg(scip, " dive %d/%d, NLP iter %d/%d: var <%s>, round=%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
    2246 divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
    2247 SCIPvarGetName(var), bestcandmayround,
    2248 bestboundval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
    2249 SCIPfeasCeil(scip, bestboundval), SCIPvarGetUbLocal(var));
    2250 SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, bestboundval)) );
    2251
    2252 /* remember variable for backtracking, if we have none yet (e.g., we are just after NLP solve) or we are half way to the next NLP solve */
    2253 if( backtrackdepth == -1 || (divedepth - lastnlpsolvedepth == (int)(MIN(fixquot * nnlpcands, nlpbranchcands)/2.0)) )
    2254 {
    2255 backtrackdepth = divedepth;
    2256 backtrackvar = var;
    2257 backtrackvarval = bestboundval;
    2258 backtrackroundup = FALSE;
    2259 }
    2260 }
    2261 else
    2262 {
    2263 /* round variable down */
    2264 SCIPdebugMsg(scip, " dive %d/%d, NLP iter %d/%d: var <%s>, round=%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
    2265 divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
    2266 SCIPvarGetName(var), bestcandmayround,
    2267 bestboundval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
    2268 SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, bestboundval));
    2269 SCIP_CALL( SCIPchgVarUbProbing(scip, var, SCIPfeasFloor(scip, bestboundval)) );
    2270
    2271 /* remember variable for backtracking, if we have none yet (e.g., we are just after NLP solve) or we are half way to the next NLP solve */
    2272 if( backtrackdepth == -1 || (divedepth - lastnlpsolvedepth == (int)(MIN(fixquot * nnlpcands, nlpbranchcands)/2.0)) )
    2273 {
    2274 backtrackdepth = divedepth;
    2275 backtrackvar = var;
    2276 backtrackvarval = bestboundval;
    2277 backtrackroundup = TRUE;
    2278 }
    2279 }
    2280
    2281 /* for pseudo-cost computation */
    2282 if( updatepscost && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
    2283 {
    2284 if( heurdata->varselrule == 'd' )
    2285 {
    2286 assert(pseudocandsnlpsol != NULL);
    2287 assert(0 <= bestcand && bestcand < npseudocands);
    2288 frac = SCIPfrac(scip, pseudocandsnlpsol[bestcand]);
    2289 }
    2290 else
    2291 frac = nlpcandsfrac[bestcand];
    2292 }
    2293 }
    2294
    2295 /* apply domain propagation */
    2296 SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
    2297 if( cutoff )
    2298 {
    2299 SCIPdebugMsg(scip, " *** cutoff detected in propagation at level %d\n", SCIPgetProbingDepth(scip));
    2300 }
    2301
    2302 /* if all variables in the cover are fixed or there is no fractional variable in the cover,
    2303 * then solve a sub-MIP
    2304 */
    2305 if( !cutoff && solvesubmip && covercomputed &&
    2306 (heurdata->nfixedcovervars == ncovervars ||
    2307 (heurdata->nfixedcovervars >= (ncovervars+1)/2 && !SCIPhashmapExists(varincover, var))) )
    2308 {
    2309 int probingdepth;
    2310
    2311 solvesubmip = FALSE;
    2312 probingdepth = SCIPgetProbingDepth(scip);
    2313 assert(probingdepth >= 1);
    2314 assert(covervars != NULL);
    2315
    2316 if( heurdata->nfixedcovervars != ncovervars )
    2317 {
    2318 /* fix all remaining cover variables */
    2319 for( c = 0; c < ncovervars && !cutoff ; c++ )
    2320 {
    2321 SCIP_Real lb;
    2322 SCIP_Real ub;
    2323 lb = SCIPvarGetLbLocal(covervars[c]);
    2324 ub = SCIPvarGetUbLocal(covervars[c]);
    2325 if( !SCIPisFeasEQ(scip, lb, ub) )
    2326 {
    2327 SCIP_Real nlpsolval;
    2328
    2329 /* adopt lpsolval w.r.t. intermediate bound changes by propagation */
    2330 nlpsolval = SCIPvarGetNLPSol(covervars[c]);
    2331 nlpsolval = MIN(nlpsolval,ub);
    2332 nlpsolval = MAX(nlpsolval,lb);
    2333 assert(SCIPvarGetType(covervars[c]) == SCIP_VARTYPE_CONTINUOUS || SCIPisFeasIntegral(scip, nlpsolval));
    2334
    2335 /* open a new probing node if this will not exceed the maximal tree depth,
    2336 * otherwise fix all the remaining variables at the same probing node
    2337 * @todo do we need a new probing node for each fixing? if one of these fixings leads to a cutoff
    2338 * we backtrack to the last probing node before we started to fix the covervars (and we do
    2339 * not solve the probing LP). thus, it would be less work load in SCIPendProbing
    2340 * and SCIPbacktrackProbing.
    2341 */
    2343 {
    2345 }
    2346
    2347 /* fix and propagate */
    2348 assert(SCIPisLbBetter(scip, nlpsolval, lb, ub) || SCIPisUbBetter(scip, nlpsolval, lb, ub));
    2349
    2350 if( SCIPisLbBetter(scip, nlpsolval, lb, ub) )
    2351 {
    2352 SCIP_CALL( SCIPchgVarLbProbing(scip, covervars[c], nlpsolval) );
    2353 /* if covervar was continuous implied integral and fractional, then nlpsolval may be below
    2354 * lower bound now, so adjust to new bound
    2355 */
    2356 nlpsolval = MAX(nlpsolval, SCIPvarGetLbLocal(covervars[c])); /*lint !e666*/
    2357 }
    2358 if( SCIPisUbBetter(scip, nlpsolval, lb, ub) )
    2359 {
    2360 SCIP_CALL( SCIPchgVarUbProbing(scip, covervars[c], nlpsolval) );
    2361 }
    2362
    2363 SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
    2364 }
    2365 }
    2366 }
    2367
    2368 /* solve sub-MIP or return to standard diving */
    2369 if( cutoff )
    2370 {
    2371 SCIP_CALL( SCIPbacktrackProbing(scip, probingdepth) );
    2372 }
    2373 else
    2374 {
    2375 SCIP_Bool success;
    2376 success = FALSE;
    2377
    2378 SCIP_CALL( solveSubMIP(scip, heur, covervars, ncovervars, &success) );
    2379 if( success )
    2380 *result = SCIP_FOUNDSOL;
    2381 backtracked = TRUE; /* to avoid backtracking */
    2382 nnlpcands = 0; /* to force termination */
    2383 cutoff = TRUE;
    2384 }
    2385 }
    2386
    2387 /* resolve the diving LP */
    2388 if( !cutoff && !lperror && (heurdata->lp || heurdata->varselrule == 'd')
    2390 {
    2391 SCIP_CALL( SCIPsolveProbingLP(scip, 100, &lperror, &cutoff) );
    2392
    2393 /* get LP solution status, objective value, and fractional variables, that should be integral */
    2394 lpsolstat = SCIPgetLPSolstat(scip);
    2395 assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
    2397
    2398 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    2399 {
    2400 nlpbranchcands = SCIPgetNLPBranchCands(scip);
    2401
    2402 /* get new objective value */
    2403 oldobjval = objval;
    2404 objval = SCIPgetLPObjval(scip);
    2405
    2406 /* update pseudo cost values */
    2407 if( updatepscost && SCIPisGT(scip, objval, oldobjval) )
    2408 {
    2409 assert(frac != SCIP_INVALID); /*lint !e777*/
    2410 if( bestcandroundup )
    2411 {
    2412 SCIP_CALL( SCIPupdateVarPseudocost(scip, var, 1.0-frac, objval - oldobjval, 1.0) );
    2413 }
    2414 else
    2415 {
    2416 SCIP_CALL( SCIPupdateVarPseudocost(scip, var, 0.0-frac, objval - oldobjval, 1.0) );
    2417 }
    2418 }
    2419 }
    2420 else
    2421 {
    2422 nlpbranchcands = 0;
    2423 }
    2424
    2425 if( cutoff )
    2426 {
    2427 SCIPdebugMsg(scip, " *** cutoff detected in LP solving at level %d, lpsolstat = %d\n", SCIPgetProbingDepth(scip), lpsolstat);
    2428 }
    2429 }
    2430 else
    2431 lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
    2432
    2433 /* check whether we want to solve the NLP, which is the case if
    2434 * - we are in backtracking, or
    2435 * - we have (actively) fixed/rounded fixquot*nnlpcands variables
    2436 * - all fractional variables were rounded/fixed (due to fixing and domain propagation)
    2437 */
    2438 solvenlp = backtracked;
    2439 if( !solvenlp && !cutoff )
    2440 {
    2441 solvenlp = (lastnlpsolvedepth < divedepth - fixquot * nnlpcands);
    2442 if( !solvenlp )
    2443 {
    2444 /* check if fractional NLP variables are left (some may have been fixed by propagation) */
    2445 for( c = 0; c < nnlpcands; ++c )
    2446 {
    2447 var = nlpcands[c];
    2448 if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
    2449 continue;
    2450 else
    2451 break;
    2452 }
    2453 if( c == nnlpcands )
    2454 solvenlp = TRUE;
    2455 }
    2456 }
    2457
    2458 nlpsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
    2459
    2460 /* resolve the diving NLP */
    2461 if( !cutoff && solvenlp )
    2462 {
    2463 SCIP_NLPTERMSTAT termstat;
    2464 SCIP_NLPSTATISTICS nlpstatistics;
    2465
    2466 /* set start solution, if we are in backtracking (previous NLP solve was infeasible) */
    2467 if( heurdata->nlpstart != 'n' && backtracked )
    2468 {
    2469 assert(nlpstartsol != NULL);
    2470
    2471 SCIPdebugMsg(scip, "setting NLP initial guess\n");
    2472
    2473 SCIP_CALL( SCIPsetNLPInitialGuessSol(scip, nlpstartsol) );
    2474 }
    2475
    2476 /* solve NLP; allow at least MINNLPITER many iterations */
    2478 .iterlimit = MAX(maxnnlpiterations - heurdata->nnlpiterations, MINNLPITER)) ); /*lint !e666*/
    2479 SCIPstatistic( ++heurdata->nnlpsolves );
    2480
    2481 termstat = SCIPgetNLPTermstat(scip);
    2482 if( termstat >= SCIP_NLPTERMSTAT_NUMERICERROR )
    2483 {
    2484 if( termstat >= SCIP_NLPTERMSTAT_LICENSEERROR )
    2485 {
    2487 "Error while solving NLP in nlpdiving heuristic; NLP solve terminated with code <%d>\n", termstat);
    2488 }
    2489 nlperror = TRUE;
    2490 break;
    2491 }
    2492
    2493 /* update iteration count */
    2494 SCIP_CALL( SCIPgetNLPStatistics(scip, &nlpstatistics) );
    2495 heurdata->nnlpiterations += nlpstatistics.niterations;
    2496
    2497 /* get NLP solution status, objective value, and fractional variables, that should be integral */
    2498 nlpsolstat = SCIPgetNLPSolstat(scip);
    2499 cutoff = (nlpsolstat > SCIP_NLPSOLSTAT_FEASIBLE);
    2500
    2501 if( cutoff )
    2502 {
    2503 SCIPdebugMsg(scip, " *** cutoff detected in NLP solving at level %d, nlpsolstat: %d\n", SCIPgetProbingDepth(scip), nlpsolstat);
    2504 }
    2505 else
    2506 {
    2507 SCIP_CALL( SCIPlinkNLPSol(scip, heurdata->sol) );
    2508
    2509 /* remember that we have solve NLP on this depth successfully */
    2510 lastnlpsolvedepth = divedepth;
    2511 /* forget previous backtrack variable, we will never go back to a depth before the current one */
    2512 backtrackdepth = -1;
    2513 /* store NLP solution for warmstarting, if nlpstart is 'f' */
    2514 if( heurdata->nlpstart == 'f' )
    2515 {
    2516 assert(nlpstartsol != NULL);
    2517
    2518 /* copy NLP solution values into nlpstartsol, is there a better way to do this???? */
    2519 SCIP_CALL( SCIPlinkNLPSol(scip, nlpstartsol) );
    2520 SCIP_CALL( SCIPunlinkSol(scip, nlpstartsol) );
    2521 }
    2522 /* increase counter on number of NLP solves with feasible solution */
    2523 ++nfeasnlps;
    2524 }
    2525 }
    2526
    2527 /* perform backtracking if a cutoff was detected */
    2528 if( cutoff && !backtracked && heurdata->backtrack )
    2529 {
    2530 if( backtrackdepth == -1 )
    2531 {
    2532 /* backtrack one step */
    2533 SCIPdebugMsg(scip, " *** cutoff detected at level %d - backtracking one step\n", SCIPgetProbingDepth(scip));
    2535
    2536 /* after backtracking there has to be at least one open node without exceeding the maximal tree depth */
    2538
    2540 }
    2541 else
    2542 {
    2543 /* if we have a stored a depth for backtracking, go there */
    2544 SCIPdebugMsg(scip, " *** cutoff detected at level %d - backtracking to depth %d\n", SCIPgetProbingDepth(scip), backtrackdepth);
    2545 SCIP_CALL( SCIPbacktrackProbing(scip, backtrackdepth-1) );
    2546
    2547 /* after backtracking there has to be at least one open node without exceeding the maximal tree depth */
    2549
    2551 divedepth = backtrackdepth;
    2552
    2553 /* do not update pseudocosts if backtracking by more than one level */
    2554 updatepscost = FALSE;
    2555
    2556 /* in case, we are feasible after backtracking, fix less variables at once in continuing diving
    2557 * @todo should we remember the fixquot in heurdata for the next run?
    2558 */
    2559 fixquot *= 0.5;
    2560 }
    2561 /* remember that we are backtracking now */
    2562 backtracked = TRUE;
    2563 }
    2564 else
    2565 backtracked = FALSE;
    2566 }
    2567 while( backtracked );
    2568
    2569 if( !nlperror && !cutoff && nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE )
    2570 {
    2571 /* get new fractional variables */
    2572 SCIP_CALL( getNLPFracVars(scip, heurdata, &nlpcands, &nlpcandssol, &nlpcandsfrac, &nnlpcands) );
    2573 }
    2574 SCIPdebugMsg(scip, " -> nlpsolstat=%d, objval=%g/%g, nfrac nlp=%d lp=%d\n", nlpsolstat, objval, searchbound, nnlpcands, nlpbranchcands);
    2575 }
    2576
    2577 /*lint --e{774}*/
    2578 SCIPdebugMsg(scip, "NLP nlpdiving ABORT due to ");
    2579 if( nlperror || (nlpsolstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE && nlpsolstat != SCIP_NLPSOLSTAT_UNKNOWN) )
    2580 {
    2581 SCIPdebugMsgPrint(scip, "NLP bad status - nlperror: %ud nlpsolstat: %d \n", nlperror, nlpsolstat);
    2582 SCIPstatistic( heurdata->nfailnlperror++ );
    2583 }
    2584 else if( SCIPisStopped(scip) || cutoff )
    2585 {
    2586 SCIPdebugMsgPrint(scip, "LIMIT hit - stop: %ud cutoff: %ud \n", SCIPisStopped(scip), cutoff);
    2587 SCIPstatistic( heurdata->nfailcutoff++ );
    2588 }
    2589 else if(! (divedepth < 10
    2590 || nnlpcands <= startnnlpcands - divedepth/2
    2591 || (divedepth < maxdivedepth && heurdata->nnlpiterations < maxnnlpiterations && objval < searchbound) ) )
    2592 {
    2593 SCIPdebugMsgPrint(scip, "TOO DEEP - divedepth: %4d cands halfed: %d ltmaxdepth: %d ltmaxiter: %d bound: %d\n", divedepth,
    2594 (nnlpcands > startnnlpcands - divedepth/2), (divedepth >= maxdivedepth), (heurdata->nnlpiterations >= maxnnlpiterations),
    2595 (objval >= searchbound));
    2596 SCIPstatistic( heurdata->nfaildepth++ );
    2597 }
    2598 else if( nnlpcands == 0 && !nlperror && !cutoff && nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE )
    2599 {
    2600 SCIPdebugMsgPrint(scip, "SUCCESS\n");
    2601 }
    2602 else
    2603 {
    2604 SCIPdebugMsgPrint(scip, "UNKNOWN, very mysterical reason\n"); /* see also special case var == NULL (bestcand == -1) after choose*Var above */
    2605 }
    2606
    2607 /* check if a solution has been found */
    2608 if( nnlpcands == 0 && !nlperror && !cutoff && nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE )
    2609 {
    2610 SCIP_Bool success;
    2611
    2612 /* create solution from diving NLP */
    2613 SCIPdebugMsg(scip, "nlpdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
    2614
    2615 /* try to add solution to SCIP
    2616 *
    2617 * Note that even if the NLP solver found a feasible solution it does not mean that is satisfy the integrality
    2618 * conditions for fixed variables. This happens because the NLP solver uses relative tolerances for the bound
    2619 * constraints but SCIP uses absolute tolerances for checking the integrality conditions.
    2620 */
    2621#ifdef SCIP_DEBUG
    2622 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, TRUE, TRUE, FALSE, TRUE, TRUE, &success) );
    2623#else
    2624 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, TRUE, TRUE, &success) );
    2625#endif
    2626
    2627 /* check, if solution was feasible and good enough */
    2628 if( success )
    2629 {
    2630 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
    2631 *result = SCIP_FOUNDSOL;
    2632 }
    2633 else
    2634 {
    2635 SCIPdebugMsg(scip, " -> solution was not accepted\n");
    2636 }
    2637 }
    2638
    2639 /* end diving */
    2641
    2642 /* free hash map and drop variable bound change events */
    2643 if( covercomputed )
    2644 {
    2645 assert(heurdata->eventhdlr != NULL);
    2646 assert(heurdata->nfixedcovervars >= 0); /* variables might have been globally fixed in propagation */
    2647 assert(varincover != NULL);
    2648 assert(covervars != NULL);
    2649
    2650 SCIPhashmapFree(&varincover);
    2651
    2652 /* drop bound change events of cover variables */
    2653 for( c = 0; c < ncovervars; c++ )
    2654 {
    2655 SCIP_CALL( SCIPdropVarEvent(scip, covervars[c], SCIP_EVENTTYPE_BOUNDCHANGED, heurdata->eventhdlr, (SCIP_EVENTDATA*)heurdata, -1) );
    2656 }
    2657 }
    2658 else
    2659 assert(varincover == NULL);
    2660
    2661 /* free NLP start solution */
    2662 if( nlpstartsol != NULL )
    2663 {
    2664 SCIP_CALL( SCIPfreeSol(scip, &nlpstartsol) );
    2665 }
    2666
    2667 /* free copied best solution */
    2668 if( heurdata->varselrule == 'g' )
    2669 {
    2670 assert(bestsol != NULL);
    2671 SCIP_CALL( SCIPfreeSol(scip, &bestsol) );
    2672 }
    2673 else
    2674 assert(bestsol == NULL);
    2675
    2676 /* free arrays of LP and NLP solution */
    2677 if( heurdata->varselrule == 'd' )
    2678 {
    2679 assert(pseudocandsnlpsol != NULL);
    2680 assert(pseudocandsnlpsol != NULL);
    2681 SCIPfreeBufferArray(scip, &pseudocandsnlpsol);
    2682 SCIPfreeBufferArray(scip, &pseudocandslpsol);
    2683 }
    2684 else
    2685 {
    2686 assert(pseudocandsnlpsol == NULL);
    2687 assert(pseudocandsnlpsol == NULL);
    2688 }
    2689
    2690 /* free array of cover variables */
    2691 if( heurdata->prefercover || heurdata->solvesubmip )
    2692 {
    2693 assert(covervars != NULL || !covercomputed);
    2694 if( covervars != NULL )
    2695 SCIPfreeBufferArray(scip, &covervars);
    2696 }
    2697 else
    2698 assert(covervars == NULL);
    2699
    2700 if( *result == SCIP_FOUNDSOL )
    2701 heurdata->nsuccess++;
    2702
    2703 SCIPdebugMsg(scip, "nlpdiving heuristic finished\n");
    2704
    2705 return SCIP_OKAY; /*lint !e438*/
    2706}
    2707
    2708
    2709/*
    2710 * heuristic specific interface methods
    2711 */
    2712
    2713/** creates the nlpdiving heuristic and includes it in SCIP */
    2715 SCIP* scip /**< SCIP data structure */
    2716 )
    2717{
    2718 SCIP_HEURDATA* heurdata;
    2719 SCIP_HEUR* heur = NULL;
    2720
    2721 /* create heuristic data */
    2722 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    2723 heurdata->inittiming = HEUR_TIMING;
    2724
    2725 /* include heuristic */
    2727 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecNlpdiving, heurdata) );
    2728
    2729 assert(heur != NULL);
    2730 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyNlpdiving) );
    2731 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeNlpdiving) );
    2732 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitNlpdiving) );
    2733 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitNlpdiving) );
    2734 SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolNlpdiving) );
    2735 SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolNlpdiving) );
    2736
    2737 /* get event handler for bound change events */
    2738 heurdata->eventhdlr = NULL;
    2739 /* create event handler for bound change events */
    2741 eventExecNlpdiving, NULL) );
    2742 if ( heurdata->eventhdlr == NULL )
    2743 {
    2744 SCIPerrorMessage("event handler for " HEUR_NAME " heuristic not found.\n");
    2745 return SCIP_PLUGINNOTFOUND;
    2746 }
    2747
    2748 /* nlpdiving heuristic parameters */
    2750 "heuristics/" HEUR_NAME "/minreldepth",
    2751 "minimal relative depth to start diving",
    2752 &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
    2754 "heuristics/" HEUR_NAME "/maxreldepth",
    2755 "maximal relative depth to start diving",
    2756 &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
    2758 "heuristics/" HEUR_NAME "/maxnlpiterabs",
    2759 "minimial absolute number of allowed NLP iterations",
    2760 &heurdata->maxnlpiterabs, FALSE, DEFAULT_MAXNLPITERABS, 0, INT_MAX, NULL, NULL) );
    2762 "heuristics/" HEUR_NAME "/maxnlpiterrel",
    2763 "additional allowed number of NLP iterations relative to successfully found solutions",
    2764 &heurdata->maxnlpiterrel, FALSE, DEFAULT_MAXNLPITERREL, 0, INT_MAX, NULL, NULL) );
    2766 "heuristics/" HEUR_NAME "/maxdiveubquot",
    2767 "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
    2768 &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
    2770 "heuristics/" HEUR_NAME "/maxdiveavgquot",
    2771 "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
    2772 &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    2774 "heuristics/" HEUR_NAME "/maxdiveubquotnosol",
    2775 "maximal UBQUOT when no solution was found yet (0.0: no limit)",
    2776 &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
    2778 "heuristics/" HEUR_NAME "/maxdiveavgquotnosol",
    2779 "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
    2780 &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    2782 "heuristics/" HEUR_NAME "/maxfeasnlps",
    2783 "maximal number of NLPs with feasible solution to solve during one dive",
    2784 &heurdata->maxfeasnlps, FALSE, DEFAULT_MAXFEASNLPS, 1, INT_MAX, NULL, NULL) );
    2786 "heuristics/" HEUR_NAME "/backtrack",
    2787 "use one level of backtracking if infeasibility is encountered?",
    2788 &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
    2790 "heuristics/" HEUR_NAME "/lp",
    2791 "should the LP relaxation be solved before the NLP relaxation?",
    2792 &heurdata->lp, TRUE, DEFAULT_LP, NULL, NULL) );
    2794 "heuristics/" HEUR_NAME "/preferlpfracs",
    2795 "prefer variables that are also fractional in LP solution?",
    2796 &heurdata->preferlpfracs, TRUE, DEFAULT_PREFERLPFRACS, NULL, NULL) );
    2798 "heuristics/" HEUR_NAME "/minsuccquot",
    2799 "heuristic will not run if less then this percentage of calls succeeded (0.0: no limit)",
    2800 &heurdata->minsuccquot, FALSE, DEFAULT_MINSUCCQUOT, 0.0, 1.0, NULL, NULL) );
    2802 "heuristics/" HEUR_NAME "/fixquot",
    2803 "percentage of fractional variables that should be fixed before the next NLP solve",
    2804 &heurdata->fixquot, FALSE, DEFAULT_FIXQUOT, 0.0, 1.0, NULL, NULL) );
    2806 "heuristics/" HEUR_NAME "/prefercover",
    2807 "should variables in a minimal cover be preferred?",
    2808 &heurdata->prefercover, FALSE, DEFAULT_PREFERCOVER, NULL, NULL) );
    2810 "heuristics/" HEUR_NAME "/solvesubmip",
    2811 "should a sub-MIP be solved if all cover variables are fixed?",
    2812 &heurdata->solvesubmip, FALSE, DEFAULT_SOLVESUBMIP, NULL, NULL) );
    2814 "heuristics/" HEUR_NAME "/nlpfastfail",
    2815 "should the NLP solver stop early if it converges slow?",
    2816 &heurdata->nlpfastfail, FALSE, DEFAULT_NLPFASTFAIL, NULL, NULL) );
    2818 "heuristics/" HEUR_NAME "/nlpstart",
    2819 "which point should be used as starting point for the NLP solver? ('n'one, last 'f'easible, from dive's'tart)",
    2820 &heurdata->nlpstart, TRUE, DEFAULT_NLPSTART, "fns", NULL, NULL) );
    2822 "heuristics/" HEUR_NAME "/varselrule",
    2823 "which variable selection should be used? ('f'ractionality, 'c'oefficient, 'p'seudocost, 'g'uided, 'd'ouble, 'v'eclen)",
    2824 &heurdata->varselrule, FALSE, DEFAULT_VARSELRULE, "fcpgdv", NULL, NULL) );
    2825
    2826 return SCIP_OKAY;
    2827}
    #define NULL
    Definition: def.h:257
    #define SCIP_PROBINGSCORE_PENALTYRATIO
    Definition: def.h:312
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:306
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #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 ABS(x)
    Definition: def.h:225
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:343
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_RETCODE SCIPcopyConsCompression(SCIP *sourcescip, SCIP *targetscip, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, const char *suffix, SCIP_VAR **fixedvars, SCIP_Real *fixedvals, int nfixedvars, SCIP_Bool global, SCIP_Bool enablepricing, SCIP_Bool threadsafe, SCIP_Bool passmessagehdlr, SCIP_Bool *valid)
    Definition: scip_copy.c:2962
    SCIP_RETCODE SCIPcheckCopyLimits(SCIP *sourcescip, SCIP_Bool *success)
    Definition: scip_copy.c:3250
    SCIP_RETCODE SCIPcopyLimits(SCIP *sourcescip, SCIP *targetscip)
    Definition: scip_copy.c:3293
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    SCIP_RETCODE SCIPfree(SCIP **scip)
    Definition: scip_general.c:402
    SCIP_RETCODE SCIPcreate(SCIP **scip)
    Definition: scip_general.c:370
    const char * SCIPgetProbName(SCIP *scip)
    Definition: scip_prob.c:1242
    int SCIPgetNContVars(SCIP *scip)
    Definition: scip_prob.c:2569
    SCIP_RETCODE SCIPsetObjlimit(SCIP *scip, SCIP_Real objlimit)
    Definition: scip_prob.c:1661
    SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
    Definition: scip_prob.c:2115
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    int SCIPgetNContImplVars(SCIP *scip)
    Definition: scip_prob.c:2522
    SCIP_Bool SCIPisObjIntegral(SCIP *scip)
    Definition: scip_prob.c:1801
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3284
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3179
    SCIP_Real SCIPgetLocalLowerbound(SCIP *scip)
    Definition: scip_prob.c:4178
    void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:225
    #define SCIPdebugMsgPrint
    Definition: scip_message.h:79
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPcomputeCoverUndercover(SCIP *scip, int *coversize, SCIP_VAR **cover, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Real objlimit, SCIP_Bool globalbounds, SCIP_Bool onlyconvexify, SCIP_Bool coverand, SCIP_Bool coverbd, SCIP_Bool coverind, SCIP_Bool covernl, char coveringobj, SCIP_Bool *success)
    SCIP_Bool SCIPisParamFixed(SCIP *scip, const char *name)
    Definition: scip_param.c:219
    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 SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
    Definition: scip_param.c:545
    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 SCIPsetIntParam(SCIP *scip, const char *name, int value)
    Definition: scip_param.c:487
    SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
    Definition: scip_param.c:904
    SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
    Definition: scip_param.c:307
    SCIP_RETCODE SCIPsetPresolving(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
    Definition: scip_param.c:956
    SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
    Definition: scip_param.c:661
    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 SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
    Definition: scip_param.c:429
    SCIP_RETCODE SCIPsetSeparating(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
    Definition: scip_param.c:985
    SCIP_RETCODE SCIPincludeHeurNlpdiving(SCIP *scip)
    SCIP_BRANCHRULE * SCIPfindBranchrule(SCIP *scip, const char *name)
    Definition: scip_branch.c:304
    int SCIPgetNLPBranchCands(SCIP *scip)
    Definition: scip_branch.c:436
    SCIP_RETCODE SCIPgetPseudoBranchCands(SCIP *scip, SCIP_VAR ***pseudocands, int *npseudocands, int *npriopseudocands)
    Definition: scip_branch.c:741
    SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: scip_event.c:111
    const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
    Definition: event.c:396
    SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
    Definition: event.c:1194
    SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
    Definition: scip_event.c:367
    SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
    Definition: scip_event.c:413
    SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
    Definition: event.c:1391
    SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
    Definition: event.c:1217
    SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
    Definition: event.c:1415
    SCIP_RETCODE SCIPsetHeurExitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXITSOL((*heurexitsol)))
    Definition: scip_heur.c:247
    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_HEURTIMING SCIPheurGetTimingmask(SCIP_HEUR *heur)
    Definition: heur.c:1497
    SCIP_Longint SCIPheurGetNSolsFound(SCIP_HEUR *heur)
    Definition: heur.c:1603
    SCIP_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXIT((*heurexit)))
    Definition: scip_heur.c:215
    SCIP_Longint SCIPheurGetNBestSolsFound(SCIP_HEUR *heur)
    Definition: heur.c:1613
    void SCIPheurSetTimingmask(SCIP_HEUR *heur, SCIP_HEURTIMING timingmask)
    Definition: heur.c:1507
    SCIP_Longint SCIPheurGetNCalls(SCIP_HEUR *heur)
    Definition: heur.c:1593
    SCIP_RETCODE SCIPsetHeurInitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINITSOL((*heurinitsol)))
    Definition: scip_heur.c:231
    SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
    Definition: scip_heur.c:199
    SCIP_Real SCIPheurGetTime(SCIP_HEUR *heur)
    Definition: heur.c:1655
    const char * SCIPheurGetName(SCIP_HEUR *heur)
    Definition: heur.c:1467
    void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
    Definition: heur.c:1378
    SCIP_Longint SCIPgetLastDivenode(SCIP *scip)
    Definition: scip_lp.c:2710
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    SCIP_Real SCIPgetLPObjval(SCIP *scip)
    Definition: scip_lp.c:253
    SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
    Definition: scip_lp.c:673
    SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
    Definition: scip_mem.c:126
    SCIP_Longint SCIPgetMemUsed(SCIP *scip)
    Definition: scip_mem.c:100
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    int SCIPgetNNlpis(SCIP *scip)
    Definition: scip_nlpi.c:205
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
    Definition: scip_nlp.c:574
    #define SCIPsolveNLP(...)
    Definition: scip_nlp.h:361
    SCIP_Real SCIPgetNLPObjval(SCIP *scip)
    Definition: scip_nlp.c:645
    SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
    Definition: scip_nlp.c:696
    SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_nlp.c:501
    SCIP_NLPTERMSTAT SCIPgetNLPTermstat(SCIP *scip)
    Definition: scip_nlp.c:596
    SCIP_RETCODE SCIPgetNLPStatistics(SCIP *scip, SCIP_NLPSTATISTICS *statistics)
    Definition: scip_nlp.c:621
    SCIP_NODESEL * SCIPfindNodesel(SCIP *scip, const char *name)
    Definition: scip_nodesel.c:242
    int SCIPgetProbingDepth(SCIP *scip)
    Definition: scip_probing.c:199
    SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_probing.c:346
    SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_probing.c:302
    SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
    Definition: scip_probing.c:581
    SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
    Definition: scip_probing.c:226
    SCIP_RETCODE SCIPstartProbing(SCIP *scip)
    Definition: scip_probing.c:120
    SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
    Definition: scip_probing.c:166
    SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
    Definition: scip_probing.c:825
    SCIP_RETCODE SCIPendProbing(SCIP *scip)
    Definition: scip_probing.c:261
    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 SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
    Definition: scip_sol.c:882
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1250
    SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:662
    int SCIPgetNSols(SCIP *scip)
    Definition: scip_sol.c:2887
    SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1504
    SCIP_Bool SCIPsolIsOriginal(SCIP_SOL *sol)
    Definition: sol.c:4155
    SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_sol.c:1844
    SCIP_RETCODE SCIPlinkNLPSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1351
    SCIP_RETCODE SCIProundSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *success)
    Definition: scip_sol.c:3128
    SCIP_RETCODE SCIPsetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_sol.c:1660
    SCIP_SOL ** SCIPgetSols(SCIP *scip)
    Definition: scip_sol.c:2936
    SCIP_RETCODE SCIPtrySol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
    Definition: scip_sol.c:4017
    SCIP_RETCODE SCIPtrySolFree(SCIP *scip, SCIP_SOL **sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
    Definition: scip_sol.c:4114
    SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1890
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1569
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
    Definition: scip_sol.c:2134
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2611
    SCIP_Longint SCIPgetNSolsFound(SCIP *scip)
    int SCIPgetMaxDepth(SCIP *scip)
    SCIP_Real SCIPgetUpperbound(SCIP *scip)
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_Real SCIPgetDualbound(SCIP *scip)
    SCIP_Real SCIPgetLowerbound(SCIP *scip)
    SCIP_Real SCIPgetAvgLowerbound(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Real SCIPgetSolvingTime(SCIP *scip)
    Definition: scip_timing.c:378
    SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
    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 SCIPisInfinity(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_Real SCIPfeastol(SCIP *scip)
    SCIP_Real SCIPfrac(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)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR *var)
    Definition: var.c:4478
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4380
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23530
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
    Definition: var.c:4467
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Real SCIPvarGetRootSol(SCIP_VAR *var)
    Definition: var.c:19144
    SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
    Definition: scip_var.c:11188
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_RETCODE SCIPupdateVarPseudocost(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta, SCIP_Real objdelta, SCIP_Real weight)
    Definition: scip_var.c:11122
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_Real SCIPvarGetNLPSol(SCIP_VAR *var)
    Definition: var.c:24723
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4322
    void SCIPenableVarHistory(SCIP *scip)
    Definition: scip_var.c:11083
    void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
    SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
    int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
    Definition: misc.c:10223
    #define DEFAULT_MAXNLPITERREL
    static SCIP_RETCODE chooseCoefVar(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR **nlpcands, SCIP_Real *nlpcandssol, SCIP_Real *nlpcandsfrac, int nnlpcands, SCIP_HASHMAP *varincover, SCIP_Bool covercomputed, int *bestcand, SCIP_Bool *bestcandmayround, SCIP_Bool *bestcandroundup)
    #define DEFAULT_MAXDIVEUBQUOT
    static SCIP_DECL_HEUREXITSOL(heurExitsolNlpdiving)
    static SCIP_RETCODE chooseGuidedVar(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR **nlpcands, SCIP_Real *nlpcandssol, SCIP_Real *nlpcandsfrac, int nnlpcands, SCIP_SOL *bestsol, SCIP_HASHMAP *varincover, SCIP_Bool covercomputed, int *bestcand, SCIP_Bool *bestcandmayround, SCIP_Bool *bestcandroundup)
    static SCIP_DECL_HEURINIT(heurInitNlpdiving)
    static void calcPscostQuot(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR *var, SCIP_Real primsol, SCIP_Real frac, int rounddir, SCIP_Real *pscostquot, SCIP_Bool *roundup, SCIP_Bool prefvar)
    static SCIP_DECL_HEURFREE(heurFreeNlpdiving)
    static SCIP_RETCODE chooseFracVar(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR **nlpcands, SCIP_Real *nlpcandssol, SCIP_Real *nlpcandsfrac, int nnlpcands, SCIP_HASHMAP *varincover, SCIP_Bool covercomputed, int *bestcand, SCIP_Bool *bestcandmayround, SCIP_Bool *bestcandroundup)
    static SCIP_RETCODE doSolveSubMIP(SCIP *scip, SCIP *subscip, SCIP_HEUR *heur, SCIP_VAR **covervars, int ncovervars, SCIP_Bool *success)
    #define MINNLPITER
    #define HEUR_TIMING
    static SCIP_RETCODE getNLPFracVars(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR ***nlpcands, SCIP_Real **nlpcandssol, SCIP_Real **nlpcandsfrac, int *nnlpcands)
    #define HEUR_FREQOFS
    #define HEUR_DESC
    #define DEFAULT_PREFERCOVER
    static SCIP_RETCODE chooseDoubleVar(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR **pseudocands, SCIP_Real *pseudocandsnlpsol, SCIP_Real *pseudocandslpsol, int npseudocands, SCIP_HASHMAP *varincover, SCIP_Bool covercomputed, int *bestcand, SCIP_Real *bestboundval, SCIP_Bool *bestcandmayround, SCIP_Bool *bestcandroundup)
    static SCIP_DECL_HEURCOPY(heurCopyNlpdiving)
    static SCIP_DECL_EVENTEXEC(eventExecNlpdiving)
    #define DEFAULT_MAXDIVEAVGQUOT
    #define DEFAULT_PREFERLPFRACS
    static SCIP_RETCODE chooseVeclenVar(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR **nlpcands, SCIP_Real *nlpcandssol, SCIP_Real *nlpcandsfrac, int nnlpcands, SCIP_HASHMAP *varincover, SCIP_Bool covercomputed, int *bestcand, SCIP_Bool *bestcandmayround, SCIP_Bool *bestcandroundup)
    #define DEFAULT_MAXNLPITERABS
    static SCIP_DECL_HEUREXEC(heurExecNlpdiving)
    #define DEFAULT_BACKTRACK
    #define DEFAULT_MAXDIVEUBQUOTNOSOL
    #define HEUR_DISPCHAR
    #define HEUR_MAXDEPTH
    #define HEUR_PRIORITY
    #define DEFAULT_MAXRELDEPTH
    static SCIP_RETCODE createNewSol(SCIP *scip, SCIP *subscip, SCIP_HEUR *heur, SCIP_HASHMAP *varmap, SCIP_SOL *subsol, SCIP_Bool *success)
    static SCIP_RETCODE choosePscostVar(SCIP *scip, SCIP_HEURDATA *heurdata, SCIP_VAR **nlpcands, SCIP_Real *nlpcandssol, SCIP_Real *nlpcandsfrac, int nnlpcands, SCIP_HASHMAP *varincover, SCIP_Bool covercomputed, int *bestcand, SCIP_Bool *bestcandmayround, SCIP_Bool *bestcandroundup)
    #define DEFAULT_MAXDIVEAVGQUOTNOSOL
    #define HEUR_NAME
    #define DEFAULT_LP
    #define DEFAULT_SOLVESUBMIP
    static SCIP_RETCODE solveSubMIP(SCIP *scip, SCIP_HEUR *heur, SCIP_VAR **covervars, int ncovervars, SCIP_Bool *success)
    #define DEFAULT_VARSELRULE
    #define DEFAULT_RANDSEED
    #define DEFAULT_FIXQUOT
    #define DEFAULT_NLPSTART
    #define DEFAULT_NLPFASTFAIL
    static SCIP_DECL_HEUREXIT(heurExitNlpdiving)
    #define DEFAULT_MAXFEASNLPS
    #define EVENTHDLR_DESC
    #define DEFAULT_MINSUCCQUOT
    #define HEUR_FREQ
    #define DEFAULT_MINRELDEPTH
    static SCIP_DECL_HEURINITSOL(heurInitsolNlpdiving)
    #define HEUR_USESSUBSCIP
    #define EVENTHDLR_NAME
    NLP diving heuristic that chooses fixings w.r.t. the fractionalities.
    NLP local search primal heuristic using sub-SCIPs.
    Undercover primal heuristic for MINLPs.
    memory allocation routines
    public methods for managing events
    public methods for primal heuristics
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPstatisticMessage
    Definition: pub_message.h:123
    #define SCIPstatistic(x)
    Definition: pub_message.h:120
    public data structures and miscellaneous methods
    public methods for primal CIP solutions
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for problem copies
    public methods for event handler plugins and event handlers
    general public methods
    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 message handling
    public methods for nonlinear relaxation
    public methods for NLPI solver interfaces
    public methods for node selector plugins
    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 random numbers
    public methods for solutions
    public solving methods
    public methods for querying solving statistics
    public methods for timing
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    #define SCIP_EVENTTYPE_BOUNDCHANGED
    Definition: type_event.h:127
    struct SCIP_EventData SCIP_EVENTDATA
    Definition: type_event.h:179
    #define SCIP_EVENTTYPE_UBTIGHTENED
    Definition: type_event.h:79
    #define SCIP_EVENTTYPE_LBRELAXED
    Definition: type_event.h:78
    #define SCIP_EVENTTYPE_LBCHANGED
    Definition: type_event.h:123
    uint64_t SCIP_EVENTTYPE
    Definition: type_event.h:156
    #define SCIP_EVENTTYPE_LBTIGHTENED
    Definition: type_event.h:77
    #define SCIP_EVENTTYPE_UBRELAXED
    Definition: type_event.h:80
    struct SCIP_HeurData SCIP_HEURDATA
    Definition: type_heur.h:77
    enum SCIP_LPSolStat SCIP_LPSOLSTAT
    Definition: type_lp.h:52
    @ SCIP_LPSOLSTAT_NOTSOLVED
    Definition: type_lp.h:43
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_LPSOLSTAT_INFEASIBLE
    Definition: type_lp.h:45
    @ SCIP_LPSOLSTAT_OBJLIMIT
    Definition: type_lp.h:47
    @ SCIP_VERBLEVEL_MINIMAL
    Definition: type_message.h:59
    @ SCIP_NLPPARAM_FASTFAIL_CONSERVATIVE
    Definition: type_nlpi.h:59
    @ SCIP_NLPPARAM_FASTFAIL_AGGRESSIVE
    Definition: type_nlpi.h:60
    enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
    Definition: type_nlpi.h:168
    @ SCIP_NLPTERMSTAT_NUMERICERROR
    Definition: type_nlpi.h:178
    @ SCIP_NLPTERMSTAT_LICENSEERROR
    Definition: type_nlpi.h:181
    @ SCIP_NLPSOLSTAT_LOCINFEASIBLE
    Definition: type_nlpi.h:163
    @ SCIP_NLPSOLSTAT_FEASIBLE
    Definition: type_nlpi.h:162
    @ SCIP_NLPSOLSTAT_UNKNOWN
    Definition: type_nlpi.h:166
    enum SCIP_NlpTermStat SCIP_NLPTERMSTAT
    Definition: type_nlpi.h:184
    @ SCIP_PARAMSETTING_OFF
    Definition: type_paramset.h:63
    @ SCIP_PARAMSETTING_FAST
    Definition: type_paramset.h:62
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_DELAYED
    Definition: type_result.h:43
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_FOUNDSOL
    Definition: type_result.h:56
    @ SCIP_INVALIDDATA
    Definition: type_retcode.h:52
    @ SCIP_PLUGINNOTFOUND
    Definition: type_retcode.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
    unsigned int SCIP_HEURTIMING
    Definition: type_timing.h:103
    #define SCIP_HEURTIMING_NONE
    Definition: type_timing.h:79
    @ SCIP_VARTYPE_CONTINUOUS
    Definition: type_var.h:71
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64
    @ SCIP_LOCKTYPE_MODEL
    Definition: type_var.h:141