Scippy

    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-2025 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#include <string.h>
    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(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
    1462 assert(event != NULL);
    1463
    1464 heurdata = (SCIP_HEURDATA*)eventdata;
    1465 assert(heurdata != NULL);
    1466 assert(0 <= heurdata->nfixedcovervars && heurdata->nfixedcovervars <= SCIPgetNVars(scip));
    1467
    1468 oldbound = SCIPeventGetOldbound(event);
    1469 newbound = SCIPeventGetNewbound(event);
    1470 var = SCIPeventGetVar(event);
    1471
    1472 eventtype = SCIPeventGetType(event);
    1473 otherbound = (eventtype & SCIP_EVENTTYPE_LBCHANGED) ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
    1474
    1475 switch( eventtype )
    1476 {
    1479 /* if cover variable is now fixed */
    1480 if( SCIPisFeasEQ(scip, newbound, otherbound) && !SCIPisFeasEQ(scip, oldbound, otherbound) )
    1481 {
    1482 assert(!SCIPisEQ(scip, oldbound, otherbound));
    1483 ++(heurdata->nfixedcovervars);
    1484 }
    1485 break;
    1488 /* if cover variable is now unfixed */
    1489 if( SCIPisFeasEQ(scip, oldbound, otherbound) && !SCIPisFeasEQ(scip, newbound, otherbound) )
    1490 {
    1491 assert(!SCIPisEQ(scip, newbound, otherbound));
    1492 --(heurdata->nfixedcovervars);
    1493 }
    1494 break;
    1495 default:
    1496 SCIPerrorMessage("invalid event type.\n");
    1497 return SCIP_INVALIDDATA;
    1498 }
    1499 assert(0 <= heurdata->nfixedcovervars && heurdata->nfixedcovervars <= SCIPgetNVars(scip));
    1500
    1501 /* SCIPdebugMsg(scip, "changed bound of cover variable <%s> from %f to %f (nfixedcovervars: %d).\n", SCIPvarGetName(var),
    1502 oldbound, newbound, heurdata->nfixedcovervars); */
    1503
    1504 return SCIP_OKAY;
    1505}
    1506
    1507
    1508/*
    1509 * Callback methods
    1510 */
    1511
    1512/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    1513static
    1514SCIP_DECL_HEURCOPY(heurCopyNlpdiving)
    1515{ /*lint --e{715}*/
    1516 assert(scip != NULL);
    1517 assert(heur != NULL);
    1518 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    1519
    1520 /* call inclusion method of primal heuristic */
    1522
    1523 return SCIP_OKAY;
    1524}
    1525
    1526/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    1527static
    1528SCIP_DECL_HEURFREE(heurFreeNlpdiving) /*lint --e{715}*/
    1529{ /*lint --e{715}*/
    1530 SCIP_HEURDATA* heurdata;
    1531
    1532 assert(heur != NULL);
    1533 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    1534 assert(scip != NULL);
    1535
    1536 /* free heuristic data */
    1537 heurdata = SCIPheurGetData(heur);
    1538 assert(heurdata != NULL);
    1539 SCIPfreeBlockMemory(scip, &heurdata);
    1540 SCIPheurSetData(heur, NULL);
    1541
    1542 return SCIP_OKAY;
    1543}
    1544
    1545
    1546/** initialization method of primal heuristic (called after problem was transformed) */
    1547static
    1548SCIP_DECL_HEURINIT(heurInitNlpdiving) /*lint --e{715}*/
    1549{ /*lint --e{715}*/
    1550 SCIP_HEURDATA* heurdata;
    1551
    1552 assert(heur != NULL);
    1553 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    1554
    1555 /* get heuristic data */
    1556 heurdata = SCIPheurGetData(heur);
    1557 assert(heurdata != NULL);
    1558
    1559 /* create working solution */
    1560 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
    1561
    1562 /* create random number generator */
    1563 SCIP_CALL( SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE) );
    1564
    1565 /* initialize data */
    1566 heurdata->nnlpiterations = 0;
    1567 heurdata->nsuccess = 0;
    1568 heurdata->nfixedcovervars = 0;
    1570 heurdata->nnlpsolves = 0;
    1571 heurdata->nfailcutoff = 0;
    1572 heurdata->nfaildepth = 0;
    1573 heurdata->nfailnlperror = 0;
    1574 );
    1575
    1576 return SCIP_OKAY;
    1577}
    1578
    1579
    1580/** deinitialization method of primal heuristic (called before transformed problem is freed) */
    1581static
    1582SCIP_DECL_HEUREXIT(heurExitNlpdiving) /*lint --e{715}*/
    1583{ /*lint --e{715}*/
    1584 SCIP_HEURDATA* heurdata;
    1585
    1586 assert(heur != NULL);
    1587 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    1588
    1589 /* get heuristic data */
    1590 heurdata = SCIPheurGetData(heur);
    1591 assert(heurdata != NULL);
    1592
    1593 /* free random number generator */
    1594 SCIPfreeRandom(scip, &heurdata->randnumgen);
    1595
    1596 /* free working solution */
    1597 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
    1598
    1600 if( strstr(SCIPgetProbName(scip), "_covering") == NULL && SCIPheurGetNCalls(heur) > 0 )
    1601 {
    1602 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",
    1604 heurdata->nnlpiterations, heurdata->nnlpsolves, heurdata->nnlpiterations/MAX(1.0,(SCIP_Real)heurdata->nnlpsolves),
    1605 (100*heurdata->nsuccess) / (int)SCIPheurGetNCalls(heur), (100*heurdata->nfailcutoff) / (int)SCIPheurGetNCalls(heur), (100*heurdata->nfaildepth) / (int)SCIPheurGetNCalls(heur), (100*heurdata->nfailnlperror) / (int)SCIPheurGetNCalls(heur)
    1606 );
    1607 }
    1608 );
    1609
    1610 return SCIP_OKAY;
    1611}
    1612
    1613
    1614/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
    1615static
    1616SCIP_DECL_HEURINITSOL(heurInitsolNlpdiving)
    1617{ /*lint --e{715}*/
    1618 SCIP_HEURDATA* heurdata;
    1619
    1620 assert(heur != NULL);
    1621
    1622 /* get heuristic data */
    1623 heurdata = SCIPheurGetData(heur);
    1624 assert(heurdata != NULL);
    1625
    1626 /* store nlpdiving timing */
    1627 heurdata->inittiming = SCIPheurGetTimingmask(heur);
    1628
    1629 /* disable nlpdiving heuristic */
    1632
    1633 return SCIP_OKAY;
    1634}
    1635
    1636
    1637/** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
    1638static
    1639SCIP_DECL_HEUREXITSOL(heurExitsolNlpdiving)
    1640{ /*lint --e{715}*/
    1641 SCIP_HEURDATA* heurdata;
    1642
    1643 assert(heur != NULL);
    1644
    1645 /* get heuristic data */
    1646 heurdata = SCIPheurGetData(heur);
    1647 assert(heurdata != NULL);
    1648
    1649 /* reset nlpdiving timing */
    1650 SCIPheurSetTimingmask(heur, heurdata->inittiming);
    1651
    1652 return SCIP_OKAY;
    1653}
    1654
    1655
    1656/** execution method of primal heuristic */
    1657static
    1658SCIP_DECL_HEUREXEC(heurExecNlpdiving)
    1659{ /*lint --e{715}*/
    1660 SCIP_HEURDATA* heurdata;
    1661 SCIP_NLPSOLSTAT nlpsolstat;
    1662 SCIP_LPSOLSTAT lpsolstat;
    1663 SCIP_SOL* nlpstartsol;
    1664 SCIP_SOL* bestsol;
    1665 SCIP_VAR** nlpcands;
    1666 SCIP_VAR** covervars;
    1667 SCIP_Real* nlpcandssol;
    1668 SCIP_Real* nlpcandsfrac;
    1669 SCIP_Real* pseudocandslpsol;
    1670 SCIP_Real* pseudocandsnlpsol;
    1671 SCIP_HASHMAP* varincover;
    1672 SCIP_Real searchubbound;
    1673 SCIP_Real searchavgbound;
    1674 SCIP_Real searchbound;
    1675 SCIP_Real objval;
    1676 SCIP_Real oldobjval;
    1677 SCIP_Real fixquot;
    1678 SCIP_Real bestboundval;
    1679 SCIP_Bool bestcandmayround;
    1680 SCIP_Bool bestcandroundup;
    1681 SCIP_Bool nlperror;
    1682 SCIP_Bool lperror;
    1683 SCIP_Bool cutoff;
    1684 SCIP_Bool backtracked;
    1685 SCIP_Bool solvenlp;
    1686 SCIP_Bool covercomputed;
    1687 SCIP_Bool solvesubmip;
    1688 SCIP_Longint ncalls;
    1689 SCIP_Longint nsolsfound;
    1690 SCIP_VAR* backtrackvar; /* (first) variable to fix differently in backtracking */
    1691 SCIP_Real backtrackvarval; /* (fractional) value of backtrack variable */
    1692 SCIP_Bool backtrackroundup; /* whether variable should be rounded up in backtracking */
    1693 int backtrackdepth; /* depth where to go when backtracking */
    1694 int avgnnlpiterations;
    1695 int maxnnlpiterations;
    1696 int npseudocands;
    1697 int nlpbranchcands;
    1698 int ncovervars;
    1699 int nnlpcands;
    1700 int startnnlpcands;
    1701 int depth;
    1702 int maxdepth;
    1703 int maxdivedepth;
    1704 int divedepth;
    1705 int lastnlpsolvedepth;
    1706 int nfeasnlps;
    1707 int bestcand;
    1708 int c;
    1709
    1710 assert(scip != NULL);
    1711 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    1712 assert(result != NULL);
    1713 assert(SCIPisNLPConstructed(scip));
    1714 assert(SCIPgetNNlpis(scip) >= 1);
    1715
    1716 *result = SCIP_DIDNOTRUN;
    1717
    1718 /* do not call heuristic of node was already detected to be infeasible */
    1719 if( nodeinfeasible )
    1720 return SCIP_OKAY;
    1721
    1722 /* only call heuristic if the current node will not be cutoff, e.g., due to a (integer and NLP-)feasible LP solution */
    1724 return SCIP_OKAY;
    1725
    1726 /* get heuristic's data */
    1727 heurdata = SCIPheurGetData(heur);
    1728 assert(heurdata != NULL);
    1729
    1730 /* do not call heuristic if it barely succeded */
    1731 if( (SCIPheurGetNSolsFound(heur) + 1.0) / (SCIP_Real)(SCIPheurGetNCalls(heur) + 1.0) < heurdata->minsuccquot )
    1732 return SCIP_OKAY;
    1733
    1734 *result = SCIP_DELAYED;
    1735
    1736 /* don't dive two times at the same node */
    1738 return SCIP_OKAY;
    1739
    1740 *result = SCIP_DIDNOTRUN;
    1741
    1742 /* only try to dive if we are in the correct part of the tree, given by minreldepth and maxreldepth */
    1743 depth = SCIPgetDepth(scip);
    1744 maxdepth = SCIPgetMaxDepth(scip);
    1745 maxdepth = MAX(maxdepth, 30);
    1746 if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
    1747 return SCIP_OKAY;
    1748
    1749 /* calculate the maximal number of NLP iterations until heuristic is aborted
    1750 * maximal number is maxnlpiterabs plus a success-depending multiplier of maxnlpiterrel
    1751 */
    1752 ncalls = SCIPheurGetNCalls(heur);
    1753 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
    1754 maxnnlpiterations = heurdata->maxnlpiterabs;
    1755 maxnnlpiterations += (int)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxnlpiterrel);
    1756
    1757 /* don't try to dive if we took too many NLP iterations during diving */
    1758 if( heurdata->nnlpiterations >= maxnnlpiterations )
    1759 return SCIP_OKAY;
    1760
    1761 /* allow at least a bit more than the so far average number of NLP iterations per dive */
    1762 avgnnlpiterations = (int)(heurdata->nnlpiterations / MAX(ncalls, 1.0));
    1763 maxnnlpiterations = (int)MAX((SCIP_Real) maxnnlpiterations, (SCIP_Real) heurdata->nnlpiterations + 1.2*avgnnlpiterations);
    1764
    1765 /* don't try to dive if there are no unfixed discrete variables */
    1766 SCIP_CALL( SCIPgetPseudoBranchCands(scip, NULL, &npseudocands, NULL) );
    1767 if( npseudocands == 0 )
    1768 return SCIP_OKAY;
    1769
    1770 *result = SCIP_DIDNOTFIND;
    1771
    1772 /* set starting point to lp solution */
    1774
    1775 /* solve NLP relaxation if not solved already */
    1776 nlpsolstat = SCIPgetNLPSolstat(scip);
    1777 if( nlpsolstat > SCIP_NLPSOLSTAT_FEASIBLE )
    1778 {
    1779 SCIP_NLPSTATISTICS nlpstatistics;
    1780
    1782 .iterlimit = maxnnlpiterations - heurdata->nnlpiterations,
    1783 .fastfail = heurdata->nlpfastfail ? SCIP_NLPPARAM_FASTFAIL_AGGRESSIVE : SCIP_NLPPARAM_FASTFAIL_CONSERVATIVE) ); /*lint !e666*/
    1784 SCIPstatistic( ++heurdata->nnlpsolves );
    1785
    1786 /* update iteration count */
    1788 {
    1789 SCIP_CALL( SCIPgetNLPStatistics(scip, &nlpstatistics) );
    1790 heurdata->nnlpiterations += nlpstatistics.niterations;
    1791 }
    1792
    1793 nlpsolstat = SCIPgetNLPSolstat(scip);
    1794
    1795 /* give up, if no feasible solution found */
    1796 if( nlpsolstat >= SCIP_NLPSOLSTAT_LOCINFEASIBLE )
    1797 {
    1798 SCIPdebugMsg(scip, "initial NLP infeasible or not solvable --> stop\n");
    1799
    1802 heurdata->nfailcutoff++;
    1803 else
    1804 heurdata->nfailnlperror++;
    1805 )
    1806
    1807 return SCIP_OKAY;
    1808 }
    1809 }
    1810
    1811 /* get NLP solution */
    1812 SCIP_CALL( SCIPlinkNLPSol(scip, heurdata->sol) );
    1813
    1814 /* get fractional variables that should be integral */
    1815 SCIP_CALL( getNLPFracVars(scip, heurdata, &nlpcands, &nlpcandssol, &nlpcandsfrac, &nnlpcands) );
    1816 assert(nnlpcands <= npseudocands);
    1817
    1818 /* get LP candidates if LP solution is optimal */
    1819 lpsolstat = SCIPgetLPSolstat(scip);
    1820 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    1821 nlpbranchcands = SCIPgetNLPBranchCands(scip);
    1822 else
    1823 nlpbranchcands = 0;
    1824
    1825 /* don't try to dive, if there are no fractional variables */
    1826 if( nnlpcands == 0 )
    1827 {
    1828 SCIP_Bool success;
    1829
    1830 /* check, if solution was feasible and good enough
    1831 *
    1832 * Note that even if the NLP solver found a feasible solution it does not mean that is satisfy the integrality
    1833 * conditions for fixed variables. This happens because the NLP solver uses relative tolerances for the bound
    1834 * constraints but SCIP uses absolute tolerances for checking the integrality conditions.
    1835 */
    1836#ifdef SCIP_DEBUG
    1837 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, TRUE, TRUE, FALSE, TRUE, TRUE, &success) );
    1838#else
    1839 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, TRUE, TRUE, &success) );
    1840#endif
    1841 if( success )
    1842 {
    1843 SCIPdebugMsg(scip, " -> solution of first NLP was integral, feasible, and good enough\n");
    1844 *result = SCIP_FOUNDSOL;
    1845 }
    1846
    1847 return SCIP_OKAY;
    1848 }
    1849
    1850 /* for guided diving: don't dive, if no feasible solutions exist */
    1851 if( heurdata->varselrule == 'g' && SCIPgetNSols(scip) == 0 )
    1852 return SCIP_OKAY;
    1853
    1854 /* for guided diving: get best solution that should guide the search; if this solution lives in the original variable space,
    1855 * we cannot use it since it might violate the global bounds of the current problem
    1856 */
    1857 if( heurdata->varselrule == 'g' && SCIPsolIsOriginal(SCIPgetBestSol(scip)) )
    1858 return SCIP_OKAY;
    1859
    1860 nlpstartsol = NULL;
    1861 assert(nlpcandsfrac != NULL);
    1862 assert(nlpcands != NULL);
    1863 assert(nlpcandssol != NULL);
    1864
    1865 /* save solution of first NLP, if we may use it later */
    1866 if( heurdata->nlpstart != 'n' )
    1867 {
    1868 SCIP_CALL( SCIPcreateNLPSol(scip, &nlpstartsol, heur) );
    1869 SCIP_CALL( SCIPunlinkSol(scip, nlpstartsol) );
    1870 }
    1871
    1872 /* calculate the objective search bound */
    1873 if( SCIPgetNSolsFound(scip) == 0 )
    1874 {
    1875 if( heurdata->maxdiveubquotnosol > 0.0 )
    1876 searchubbound = SCIPgetLowerbound(scip)
    1877 + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
    1878 else
    1879 searchubbound = SCIPinfinity(scip);
    1880 if( heurdata->maxdiveavgquotnosol > 0.0 )
    1881 searchavgbound = SCIPgetLowerbound(scip)
    1882 + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
    1883 else
    1884 searchavgbound = SCIPinfinity(scip);
    1885 }
    1886 else
    1887 {
    1888 if( heurdata->maxdiveubquot > 0.0 )
    1889 searchubbound = SCIPgetLowerbound(scip)
    1890 + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
    1891 else
    1892 searchubbound = SCIPinfinity(scip);
    1893 if( heurdata->maxdiveavgquot > 0.0 )
    1894 searchavgbound = SCIPgetLowerbound(scip)
    1895 + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
    1896 else
    1897 searchavgbound = SCIPinfinity(scip);
    1898 }
    1899 searchbound = MIN(searchubbound, searchavgbound);
    1900 if( SCIPisObjIntegral(scip) )
    1901 searchbound = SCIPceil(scip, searchbound);
    1902
    1903 /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
    1905 assert(maxdivedepth >= 0);
    1906 maxdivedepth = MIN(maxdivedepth, maxdepth);
    1907 maxdivedepth *= 10;
    1908
    1909 /* initialize local variables */
    1910 backtrackdepth = -1;
    1911 backtrackvar = NULL;
    1912 backtrackvarval = 0.0;
    1913 backtrackroundup = FALSE;
    1914 bestsol = NULL;
    1915 pseudocandsnlpsol = NULL;
    1916 pseudocandslpsol = NULL;
    1917 covervars = NULL;
    1918 covercomputed = FALSE;
    1919 varincover = NULL;
    1920
    1921 /* compute cover, if required */
    1922 if( heurdata->prefercover || heurdata->solvesubmip )
    1923 {
    1924 SCIP_Real timelimit;
    1925 SCIP_Real memorylimit;
    1926
    1927 /* get limits */
    1928 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
    1929 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
    1930 if( !SCIPisInfinity(scip, timelimit) )
    1931 timelimit -= SCIPgetSolvingTime(scip);
    1932
    1933 /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
    1934 if( !SCIPisInfinity(scip, memorylimit) )
    1935 {
    1936 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
    1937 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
    1938 }
    1939
    1940 /* compute cover; use local bounds; only cover "and" and nonlinear constraints (no bounddisjunction or indicator),
    1941 * including convex constraints */
    1942 ncovervars = -1;
    1944 if( memorylimit > 2.0*SCIPgetMemExternEstim(scip)/1048576.0 && timelimit > 0.05 )
    1945 {
    1946 SCIP_CALL( SCIPcomputeCoverUndercover(scip, &ncovervars, covervars, timelimit, memorylimit, SCIPinfinity(scip),
    1947 FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 'u', &covercomputed) );
    1948 }
    1949
    1950 if( covercomputed )
    1951 {
    1952 /* a cover can be empty, if the cover computation reveals that all nonlinear constraints are linear w.r.t. current variable fixations */
    1953 assert(ncovervars >= 0);
    1954
    1955 /* create hash map */
    1956 SCIP_CALL( SCIPhashmapCreate(&varincover, SCIPblkmem(scip), ncovervars) );
    1957
    1958 /* process variables in the cover */
    1959 for( c = 0; c < ncovervars; c++ )
    1960 {
    1961 /* insert variable into hash map */
    1962 if( SCIPvarGetType(covervars[c]) != SCIP_VARTYPE_CONTINUOUS )
    1963 {
    1964 assert(!SCIPhashmapExists(varincover, covervars[c]));
    1965 SCIP_CALL( SCIPhashmapInsertInt(varincover, covervars[c], c+1) );
    1966 }
    1967
    1968 /* catch bound change events of cover variables */
    1969 assert(heurdata->eventhdlr != NULL);
    1970 SCIP_CALL( SCIPcatchVarEvent(scip, covervars[c], SCIP_EVENTTYPE_BOUNDCHANGED, heurdata->eventhdlr,
    1971 (SCIP_EVENTDATA*) heurdata, NULL) );
    1972 assert(!SCIPisFeasEQ(scip, SCIPvarGetLbLocal(covervars[c]), SCIPvarGetUbLocal(covervars[c])));
    1973 }
    1974 }
    1975 }
    1976 else
    1977 {
    1978 covervars = NULL;
    1979 ncovervars = 0;
    1980 }
    1981
    1982 /* start diving */
    1984
    1985 /* enables collection of variable statistics during probing */
    1987
    1988 /* get NLP objective value*/
    1989 objval = SCIPgetNLPObjval(scip);
    1990
    1991 SCIPdebugMsg(scip, "(node %" SCIP_LONGINT_FORMAT ") executing nlpdiving heuristic: depth=%d, %d fractionals, dualbound=%g, searchbound=%g\n",
    1993
    1994 /* store a copy of the best solution, if guided diving should be used */
    1995 if( heurdata->varselrule == 'g' )
    1996 {
    1997 assert(SCIPgetNSols(scip) > 0);
    1999
    2001 }
    2002
    2003 /* if double diving should be used, create arrays to hold to entire LP and NLP solution */
    2004 if( heurdata->varselrule == 'd' )
    2005 {
    2006 SCIP_CALL( SCIPallocBufferArray(scip, &pseudocandslpsol, npseudocands) );
    2007 SCIP_CALL( SCIPallocBufferArray(scip, &pseudocandsnlpsol, npseudocands) );
    2008 }
    2009
    2010 /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
    2011 * - if possible, we dive at least with the depth 10
    2012 * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
    2013 */
    2014 nlperror = FALSE;
    2015 lperror = FALSE;
    2016 cutoff = FALSE;
    2017 divedepth = 0;
    2018 lastnlpsolvedepth = 0;
    2019 backtracked = FALSE; /* whether we are in backtracking */
    2020 fixquot = heurdata->fixquot;
    2021 nfeasnlps = 1;
    2022 startnnlpcands = nnlpcands;
    2023 solvesubmip = heurdata->solvesubmip;
    2024
    2025 while( !nlperror && !cutoff && (nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_UNKNOWN) && nnlpcands > 0
    2026 && (nfeasnlps < heurdata->maxfeasnlps
    2027 || nnlpcands <= startnnlpcands - divedepth/2
    2028 || (nfeasnlps < maxdivedepth && heurdata->nnlpiterations < maxnnlpiterations && objval < searchbound))
    2029 && !SCIPisStopped(scip) )
    2030 {
    2031 SCIP_VAR* var;
    2032 SCIP_Bool updatepscost;
    2033
    2034 /* open a new probing node if this will not exceed the maximal tree depth, otherwise stop here */
    2036 {
    2038 divedepth++;
    2039 }
    2040 else
    2041 break;
    2042
    2043 bestcand = -1;
    2044 bestcandmayround = TRUE;
    2045 bestcandroundup = FALSE;
    2046 bestboundval = SCIP_INVALID;
    2047 updatepscost = TRUE;
    2048 var = NULL;
    2049
    2050 /* find best candidate variable */
    2051 switch( heurdata->varselrule )
    2052 {
    2053 case 'c':
    2054 SCIP_CALL( chooseCoefVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
    2055 &bestcand, &bestcandmayround, &bestcandroundup) );
    2056 if( bestcand >= 0 )
    2057 {
    2058 var = nlpcands[bestcand];
    2059 bestboundval = nlpcandssol[bestcand];
    2060 }
    2061 break;
    2062 case 'v':
    2063 SCIP_CALL( chooseVeclenVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
    2064 &bestcand, &bestcandmayround, &bestcandroundup) );
    2065 if( bestcand >= 0 )
    2066 {
    2067 var = nlpcands[bestcand];
    2068 bestboundval = nlpcandssol[bestcand];
    2069 }
    2070 break;
    2071 case 'p':
    2072 SCIP_CALL( choosePscostVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
    2073 &bestcand, &bestcandmayround, &bestcandroundup) );
    2074 if( bestcand >= 0 )
    2075 {
    2076 var = nlpcands[bestcand];
    2077 bestboundval = nlpcandssol[bestcand];
    2078 }
    2079 break;
    2080 case 'g':
    2081 SCIP_CALL( chooseGuidedVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, bestsol, varincover, covercomputed,
    2082 &bestcand, &bestcandmayround, &bestcandroundup) );
    2083 if( bestcand >= 0 )
    2084 {
    2085 var = nlpcands[bestcand];
    2086 bestboundval = nlpcandssol[bestcand];
    2087 }
    2088 break;
    2089 case 'd':
    2090 /* double diving only works if we have both relaxations at hand, otherwise we fall back to fractional diving */
    2091 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    2092 {
    2093 SCIP_VAR** pseudocands;
    2094
    2095 SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &npseudocands, NULL) );
    2096 assert(backtrackdepth > 0 || nnlpcands <= npseudocands);
    2097 assert(SCIPgetNLPBranchCands(scip) <= npseudocands);
    2098 SCIP_CALL( SCIPgetSolVals(scip, NULL, npseudocands, pseudocands, pseudocandslpsol) );
    2099 SCIP_CALL( SCIPgetSolVals(scip, heurdata->sol, npseudocands, pseudocands, pseudocandsnlpsol) );
    2100 SCIP_CALL( chooseDoubleVar(scip, heurdata, pseudocands, pseudocandsnlpsol, pseudocandslpsol, npseudocands,
    2101 varincover, covercomputed, &bestcand, &bestboundval, &bestcandmayround, &bestcandroundup) );
    2102 if( bestcand >= 0 )
    2103 var = pseudocands[bestcand];
    2104 break;
    2105 }
    2106 else
    2107 updatepscost = FALSE;
    2108 /*lint -fallthrough*/
    2109 case 'f':
    2110 SCIP_CALL( chooseFracVar(scip, heurdata, nlpcands, nlpcandssol, nlpcandsfrac, nnlpcands, varincover, covercomputed,
    2111 &bestcand, &bestcandmayround, &bestcandroundup) );
    2112 if( bestcand >= 0 )
    2113 {
    2114 var = nlpcands[bestcand];
    2115 bestboundval = nlpcandssol[bestcand];
    2116 }
    2117 break;
    2118 default:
    2119 SCIPerrorMessage("invalid variable selection rule\n");
    2120 return SCIP_INVALIDDATA;
    2121 }
    2122
    2123 /* if all candidates are roundable, try to round the solution
    2124 * if var == NULL (i.e., bestcand == -1), then all solution candidates are outside bounds
    2125 * this should only happen if they are slightly outside bounds (i.e., still within feastol, relative tolerance),
    2126 * but far enough out to be considered as fractional (within feastol, but using absolute tolerance)
    2127 * in this case, we also try our luck with rounding
    2128 */
    2129 if( (var == NULL || bestcandmayround) && backtrackdepth == -1 )
    2130 {
    2131 SCIP_Bool success;
    2132
    2133 /* create solution from diving NLP and try to round it */
    2134 SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
    2135
    2136 if( success )
    2137 {
    2138 SCIPdebugMsg(scip, "nlpdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
    2139
    2140 /* try to add solution to SCIP */
    2141#ifdef SCIP_DEBUG
    2142 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, TRUE, TRUE, FALSE, FALSE, TRUE, &success) );
    2143#else
    2144 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, TRUE, &success) );
    2145#endif
    2146
    2147 /* check, if solution was feasible and good enough */
    2148 if( success )
    2149 {
    2150 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
    2151 *result = SCIP_FOUNDSOL;
    2152 }
    2153 }
    2154 }
    2155
    2156 /* if all variables have been found to be essentially integral (even though there is some numerical doubt, see comment above), then stop */
    2157 if( var == NULL )
    2158 break;
    2159
    2160 do
    2161 {
    2162 SCIP_Real frac;
    2163 frac = SCIP_INVALID;
    2164
    2165 if( backtracked && backtrackdepth > 0 )
    2166 {
    2167 assert(backtrackvar != NULL);
    2168
    2169 /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
    2170 * occured or variable was fixed by propagation while backtracking => Abort diving!
    2171 */
    2172 if( SCIPvarGetLbLocal(backtrackvar) >= SCIPvarGetUbLocal(backtrackvar) - 0.5 )
    2173 {
    2174 SCIPdebugMsg(scip, "Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
    2175 SCIPvarGetName(backtrackvar), SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar), backtrackvarval);
    2176 cutoff = TRUE;
    2177 break;
    2178 }
    2179 if( SCIPisFeasLT(scip, backtrackvarval, SCIPvarGetLbLocal(backtrackvar)) || SCIPisFeasGT(scip, backtrackvarval, SCIPvarGetUbLocal(backtrackvar)) )
    2180 {
    2181 SCIPdebugMsg(scip, "selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
    2182 SCIPvarGetName(backtrackvar), SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar), backtrackvarval);
    2183 assert(backtracked);
    2184 break;
    2185 }
    2186
    2187 /* round backtrack variable up or down */
    2188 if( backtrackroundup )
    2189 {
    2190 SCIPdebugMsg(scip, " dive %d/%d, NLP iter %d/%d: var <%s>, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
    2191 divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
    2192 SCIPvarGetName(backtrackvar), backtrackvarval, SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar),
    2193 SCIPfeasCeil(scip, backtrackvarval), SCIPvarGetUbLocal(backtrackvar));
    2194 SCIP_CALL( SCIPchgVarLbProbing(scip, backtrackvar, SCIPfeasCeil(scip, backtrackvarval)) );
    2195 }
    2196 else
    2197 {
    2198 SCIPdebugMsg(scip, " dive %d/%d, NLP iter %d/%d: var <%s>, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
    2199 divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
    2200 SCIPvarGetName(backtrackvar), backtrackvarval, SCIPvarGetLbLocal(backtrackvar), SCIPvarGetUbLocal(backtrackvar),
    2201 SCIPvarGetLbLocal(backtrackvar), SCIPfeasFloor(scip, backtrackvarval));
    2202 SCIP_CALL( SCIPchgVarUbProbing(scip, backtrackvar, SCIPfeasFloor(scip, backtrackvarval)) );
    2203 }
    2204
    2205 /* forget about backtrack variable */
    2206 backtrackdepth = -1;
    2207
    2208 /* for pseudo cost computation */
    2209 bestcandroundup = backtrackroundup;
    2210 frac = SCIPfrac(scip, backtrackvarval);
    2211 var = backtrackvar;
    2212 }
    2213 else
    2214 {
    2215 assert(var != NULL);
    2216
    2217 /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
    2218 * occured or variable was fixed by propagation while backtracking => Abort diving!
    2219 */
    2220 if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
    2221 {
    2222 SCIPdebugMsg(scip, "Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
    2223 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestboundval);
    2224 cutoff = TRUE;
    2225 break;
    2226 }
    2227 if( SCIPisFeasLT(scip, bestboundval, SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, bestboundval, SCIPvarGetUbLocal(var)) )
    2228 {
    2229 SCIPdebugMsg(scip, "selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
    2230 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestboundval);
    2231 assert(backtracked);
    2232 break;
    2233 }
    2234
    2235 /* apply rounding of best candidate */
    2236 if( bestcandroundup == !backtracked )
    2237 {
    2238 /* round variable up */
    2239 SCIPdebugMsg(scip, " dive %d/%d, NLP iter %d/%d: var <%s>, round=%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
    2240 divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
    2241 SCIPvarGetName(var), bestcandmayround,
    2242 bestboundval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
    2243 SCIPfeasCeil(scip, bestboundval), SCIPvarGetUbLocal(var));
    2244 SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, bestboundval)) );
    2245
    2246 /* 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 */
    2247 if( backtrackdepth == -1 || (divedepth - lastnlpsolvedepth == (int)(MIN(fixquot * nnlpcands, nlpbranchcands)/2.0)) )
    2248 {
    2249 backtrackdepth = divedepth;
    2250 backtrackvar = var;
    2251 backtrackvarval = bestboundval;
    2252 backtrackroundup = FALSE;
    2253 }
    2254 }
    2255 else
    2256 {
    2257 /* round variable down */
    2258 SCIPdebugMsg(scip, " dive %d/%d, NLP iter %d/%d: var <%s>, round=%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
    2259 divedepth, maxdivedepth, heurdata->nnlpiterations, maxnnlpiterations,
    2260 SCIPvarGetName(var), bestcandmayround,
    2261 bestboundval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
    2262 SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, bestboundval));
    2263 SCIP_CALL( SCIPchgVarUbProbing(scip, var, SCIPfeasFloor(scip, bestboundval)) );
    2264
    2265 /* 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 */
    2266 if( backtrackdepth == -1 || (divedepth - lastnlpsolvedepth == (int)(MIN(fixquot * nnlpcands, nlpbranchcands)/2.0)) )
    2267 {
    2268 backtrackdepth = divedepth;
    2269 backtrackvar = var;
    2270 backtrackvarval = bestboundval;
    2271 backtrackroundup = TRUE;
    2272 }
    2273 }
    2274
    2275 /* for pseudo-cost computation */
    2276 if( updatepscost && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
    2277 {
    2278 if( heurdata->varselrule == 'd' )
    2279 {
    2280 assert(pseudocandsnlpsol != NULL);
    2281 assert(0 <= bestcand && bestcand < npseudocands);
    2282 frac = SCIPfrac(scip, pseudocandsnlpsol[bestcand]);
    2283 }
    2284 else
    2285 frac = nlpcandsfrac[bestcand];
    2286 }
    2287 }
    2288
    2289 /* apply domain propagation */
    2290 SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
    2291 if( cutoff )
    2292 {
    2293 SCIPdebugMsg(scip, " *** cutoff detected in propagation at level %d\n", SCIPgetProbingDepth(scip));
    2294 }
    2295
    2296 /* if all variables in the cover are fixed or there is no fractional variable in the cover,
    2297 * then solve a sub-MIP
    2298 */
    2299 if( !cutoff && solvesubmip && covercomputed &&
    2300 (heurdata->nfixedcovervars == ncovervars ||
    2301 (heurdata->nfixedcovervars >= (ncovervars+1)/2 && !SCIPhashmapExists(varincover, var))) )
    2302 {
    2303 int probingdepth;
    2304
    2305 solvesubmip = FALSE;
    2306 probingdepth = SCIPgetProbingDepth(scip);
    2307 assert(probingdepth >= 1);
    2308 assert(covervars != NULL);
    2309
    2310 if( heurdata->nfixedcovervars != ncovervars )
    2311 {
    2312 /* fix all remaining cover variables */
    2313 for( c = 0; c < ncovervars && !cutoff ; c++ )
    2314 {
    2315 SCIP_Real lb;
    2316 SCIP_Real ub;
    2317 lb = SCIPvarGetLbLocal(covervars[c]);
    2318 ub = SCIPvarGetUbLocal(covervars[c]);
    2319 if( !SCIPisFeasEQ(scip, lb, ub) )
    2320 {
    2321 SCIP_Real nlpsolval;
    2322
    2323 /* adopt lpsolval w.r.t. intermediate bound changes by propagation */
    2324 nlpsolval = SCIPvarGetNLPSol(covervars[c]);
    2325 nlpsolval = MIN(nlpsolval,ub);
    2326 nlpsolval = MAX(nlpsolval,lb);
    2327 assert(SCIPvarGetType(covervars[c]) == SCIP_VARTYPE_CONTINUOUS || SCIPisFeasIntegral(scip, nlpsolval));
    2328
    2329 /* open a new probing node if this will not exceed the maximal tree depth,
    2330 * otherwise fix all the remaining variables at the same probing node
    2331 * @todo do we need a new probing node for each fixing? if one of these fixings leads to a cutoff
    2332 * we backtrack to the last probing node before we started to fix the covervars (and we do
    2333 * not solve the probing LP). thus, it would be less work load in SCIPendProbing
    2334 * and SCIPbacktrackProbing.
    2335 */
    2337 {
    2339 }
    2340
    2341 /* fix and propagate */
    2342 assert(SCIPisLbBetter(scip, nlpsolval, lb, ub) || SCIPisUbBetter(scip, nlpsolval, lb, ub));
    2343
    2344 if( SCIPisLbBetter(scip, nlpsolval, lb, ub) )
    2345 {
    2346 SCIP_CALL( SCIPchgVarLbProbing(scip, covervars[c], nlpsolval) );
    2347 /* if covervar was continuous implied integral and fractional, then nlpsolval may be below
    2348 * lower bound now, so adjust to new bound
    2349 */
    2350 nlpsolval = MAX(nlpsolval, SCIPvarGetLbLocal(covervars[c])); /*lint !e666*/
    2351 }
    2352 if( SCIPisUbBetter(scip, nlpsolval, lb, ub) )
    2353 {
    2354 SCIP_CALL( SCIPchgVarUbProbing(scip, covervars[c], nlpsolval) );
    2355 }
    2356
    2357 SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
    2358 }
    2359 }
    2360 }
    2361
    2362 /* solve sub-MIP or return to standard diving */
    2363 if( cutoff )
    2364 {
    2365 SCIP_CALL( SCIPbacktrackProbing(scip, probingdepth) );
    2366 }
    2367 else
    2368 {
    2369 SCIP_Bool success;
    2370 success = FALSE;
    2371
    2372 SCIP_CALL( solveSubMIP(scip, heur, covervars, ncovervars, &success) );
    2373 if( success )
    2374 *result = SCIP_FOUNDSOL;
    2375 backtracked = TRUE; /* to avoid backtracking */
    2376 nnlpcands = 0; /* to force termination */
    2377 cutoff = TRUE;
    2378 }
    2379 }
    2380
    2381 /* resolve the diving LP */
    2382 if( !cutoff && !lperror && (heurdata->lp || heurdata->varselrule == 'd')
    2384 {
    2385 SCIP_CALL( SCIPsolveProbingLP(scip, 100, &lperror, &cutoff) );
    2386
    2387 /* get LP solution status, objective value, and fractional variables, that should be integral */
    2388 lpsolstat = SCIPgetLPSolstat(scip);
    2389 assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
    2391
    2392 if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    2393 {
    2394 nlpbranchcands = SCIPgetNLPBranchCands(scip);
    2395
    2396 /* get new objective value */
    2397 oldobjval = objval;
    2398 objval = SCIPgetLPObjval(scip);
    2399
    2400 /* update pseudo cost values */
    2401 if( updatepscost && SCIPisGT(scip, objval, oldobjval) )
    2402 {
    2403 assert(frac != SCIP_INVALID); /*lint !e777*/
    2404 if( bestcandroundup )
    2405 {
    2406 SCIP_CALL( SCIPupdateVarPseudocost(scip, var, 1.0-frac, objval - oldobjval, 1.0) );
    2407 }
    2408 else
    2409 {
    2410 SCIP_CALL( SCIPupdateVarPseudocost(scip, var, 0.0-frac, objval - oldobjval, 1.0) );
    2411 }
    2412 }
    2413 }
    2414 else
    2415 {
    2416 nlpbranchcands = 0;
    2417 }
    2418
    2419 if( cutoff )
    2420 {
    2421 SCIPdebugMsg(scip, " *** cutoff detected in LP solving at level %d, lpsolstat = %d\n", SCIPgetProbingDepth(scip), lpsolstat);
    2422 }
    2423 }
    2424 else
    2425 lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
    2426
    2427 /* check whether we want to solve the NLP, which is the case if
    2428 * - we are in backtracking, or
    2429 * - we have (actively) fixed/rounded fixquot*nnlpcands variables
    2430 * - all fractional variables were rounded/fixed (due to fixing and domain propagation)
    2431 */
    2432 solvenlp = backtracked;
    2433 if( !solvenlp && !cutoff )
    2434 {
    2435 solvenlp = (lastnlpsolvedepth < divedepth - fixquot * nnlpcands);
    2436 if( !solvenlp )
    2437 {
    2438 /* check if fractional NLP variables are left (some may have been fixed by propagation) */
    2439 for( c = 0; c < nnlpcands; ++c )
    2440 {
    2441 var = nlpcands[c];
    2442 if( SCIPisLT(scip, nlpcandssol[c], SCIPvarGetLbLocal(var)) || SCIPisGT(scip, nlpcandssol[c], SCIPvarGetUbLocal(var)) )
    2443 continue;
    2444 else
    2445 break;
    2446 }
    2447 if( c == nnlpcands )
    2448 solvenlp = TRUE;
    2449 }
    2450 }
    2451
    2452 nlpsolstat = SCIP_NLPSOLSTAT_UNKNOWN;
    2453
    2454 /* resolve the diving NLP */
    2455 if( !cutoff && solvenlp )
    2456 {
    2457 SCIP_NLPTERMSTAT termstat;
    2458 SCIP_NLPSTATISTICS nlpstatistics;
    2459
    2460 /* set start solution, if we are in backtracking (previous NLP solve was infeasible) */
    2461 if( heurdata->nlpstart != 'n' && backtracked )
    2462 {
    2463 assert(nlpstartsol != NULL);
    2464
    2465 SCIPdebugMsg(scip, "setting NLP initial guess\n");
    2466
    2467 SCIP_CALL( SCIPsetNLPInitialGuessSol(scip, nlpstartsol) );
    2468 }
    2469
    2470 /* solve NLP; allow at least MINNLPITER many iterations */
    2472 .iterlimit = MAX(maxnnlpiterations - heurdata->nnlpiterations, MINNLPITER)) ); /*lint !e666*/
    2473 SCIPstatistic( ++heurdata->nnlpsolves );
    2474
    2475 termstat = SCIPgetNLPTermstat(scip);
    2476 if( termstat >= SCIP_NLPTERMSTAT_NUMERICERROR )
    2477 {
    2478 if( termstat >= SCIP_NLPTERMSTAT_LICENSEERROR )
    2479 {
    2481 "Error while solving NLP in nlpdiving heuristic; NLP solve terminated with code <%d>\n", termstat);
    2482 }
    2483 nlperror = TRUE;
    2484 break;
    2485 }
    2486
    2487 /* update iteration count */
    2488 SCIP_CALL( SCIPgetNLPStatistics(scip, &nlpstatistics) );
    2489 heurdata->nnlpiterations += nlpstatistics.niterations;
    2490
    2491 /* get NLP solution status, objective value, and fractional variables, that should be integral */
    2492 nlpsolstat = SCIPgetNLPSolstat(scip);
    2493 cutoff = (nlpsolstat > SCIP_NLPSOLSTAT_FEASIBLE);
    2494
    2495 if( cutoff )
    2496 {
    2497 SCIPdebugMsg(scip, " *** cutoff detected in NLP solving at level %d, nlpsolstat: %d\n", SCIPgetProbingDepth(scip), nlpsolstat);
    2498 }
    2499 else
    2500 {
    2501 SCIP_CALL( SCIPlinkNLPSol(scip, heurdata->sol) );
    2502
    2503 /* remember that we have solve NLP on this depth successfully */
    2504 lastnlpsolvedepth = divedepth;
    2505 /* forget previous backtrack variable, we will never go back to a depth before the current one */
    2506 backtrackdepth = -1;
    2507 /* store NLP solution for warmstarting, if nlpstart is 'f' */
    2508 if( heurdata->nlpstart == 'f' )
    2509 {
    2510 assert(nlpstartsol != NULL);
    2511
    2512 /* copy NLP solution values into nlpstartsol, is there a better way to do this???? */
    2513 SCIP_CALL( SCIPlinkNLPSol(scip, nlpstartsol) );
    2514 SCIP_CALL( SCIPunlinkSol(scip, nlpstartsol) );
    2515 }
    2516 /* increase counter on number of NLP solves with feasible solution */
    2517 ++nfeasnlps;
    2518 }
    2519 }
    2520
    2521 /* perform backtracking if a cutoff was detected */
    2522 if( cutoff && !backtracked && heurdata->backtrack )
    2523 {
    2524 if( backtrackdepth == -1 )
    2525 {
    2526 /* backtrack one step */
    2527 SCIPdebugMsg(scip, " *** cutoff detected at level %d - backtracking one step\n", SCIPgetProbingDepth(scip));
    2529
    2530 /* after backtracking there has to be at least one open node without exceeding the maximal tree depth */
    2532
    2534 }
    2535 else
    2536 {
    2537 /* if we have a stored a depth for backtracking, go there */
    2538 SCIPdebugMsg(scip, " *** cutoff detected at level %d - backtracking to depth %d\n", SCIPgetProbingDepth(scip), backtrackdepth);
    2539 SCIP_CALL( SCIPbacktrackProbing(scip, backtrackdepth-1) );
    2540
    2541 /* after backtracking there has to be at least one open node without exceeding the maximal tree depth */
    2543
    2545 divedepth = backtrackdepth;
    2546
    2547 /* do not update pseudocosts if backtracking by more than one level */
    2548 updatepscost = FALSE;
    2549
    2550 /* in case, we are feasible after backtracking, fix less variables at once in continuing diving
    2551 * @todo should we remember the fixquot in heurdata for the next run?
    2552 */
    2553 fixquot *= 0.5;
    2554 }
    2555 /* remember that we are backtracking now */
    2556 backtracked = TRUE;
    2557 }
    2558 else
    2559 backtracked = FALSE;
    2560 }
    2561 while( backtracked );
    2562
    2563 if( !nlperror && !cutoff && nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE )
    2564 {
    2565 /* get new fractional variables */
    2566 SCIP_CALL( getNLPFracVars(scip, heurdata, &nlpcands, &nlpcandssol, &nlpcandsfrac, &nnlpcands) );
    2567 }
    2568 SCIPdebugMsg(scip, " -> nlpsolstat=%d, objval=%g/%g, nfrac nlp=%d lp=%d\n", nlpsolstat, objval, searchbound, nnlpcands, nlpbranchcands);
    2569 }
    2570
    2571 /*lint --e{774}*/
    2572 SCIPdebugMsg(scip, "NLP nlpdiving ABORT due to ");
    2573 if( nlperror || (nlpsolstat > SCIP_NLPSOLSTAT_LOCINFEASIBLE && nlpsolstat != SCIP_NLPSOLSTAT_UNKNOWN) )
    2574 {
    2575 SCIPdebugMsgPrint(scip, "NLP bad status - nlperror: %ud nlpsolstat: %d \n", nlperror, nlpsolstat);
    2576 SCIPstatistic( heurdata->nfailnlperror++ );
    2577 }
    2578 else if( SCIPisStopped(scip) || cutoff )
    2579 {
    2580 SCIPdebugMsgPrint(scip, "LIMIT hit - stop: %ud cutoff: %ud \n", SCIPisStopped(scip), cutoff);
    2581 SCIPstatistic( heurdata->nfailcutoff++ );
    2582 }
    2583 else if(! (divedepth < 10
    2584 || nnlpcands <= startnnlpcands - divedepth/2
    2585 || (divedepth < maxdivedepth && heurdata->nnlpiterations < maxnnlpiterations && objval < searchbound) ) )
    2586 {
    2587 SCIPdebugMsgPrint(scip, "TOO DEEP - divedepth: %4d cands halfed: %d ltmaxdepth: %d ltmaxiter: %d bound: %d\n", divedepth,
    2588 (nnlpcands > startnnlpcands - divedepth/2), (divedepth >= maxdivedepth), (heurdata->nnlpiterations >= maxnnlpiterations),
    2589 (objval >= searchbound));
    2590 SCIPstatistic( heurdata->nfaildepth++ );
    2591 }
    2592 else if( nnlpcands == 0 && !nlperror && !cutoff && nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE )
    2593 {
    2594 SCIPdebugMsgPrint(scip, "SUCCESS\n");
    2595 }
    2596 else
    2597 {
    2598 SCIPdebugMsgPrint(scip, "UNKNOWN, very mysterical reason\n"); /* see also special case var == NULL (bestcand == -1) after choose*Var above */
    2599 }
    2600
    2601 /* check if a solution has been found */
    2602 if( nnlpcands == 0 && !nlperror && !cutoff && nlpsolstat <= SCIP_NLPSOLSTAT_FEASIBLE )
    2603 {
    2604 SCIP_Bool success;
    2605
    2606 /* create solution from diving NLP */
    2607 SCIPdebugMsg(scip, "nlpdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));
    2608
    2609 /* try to add solution to SCIP
    2610 *
    2611 * Note that even if the NLP solver found a feasible solution it does not mean that is satisfy the integrality
    2612 * conditions for fixed variables. This happens because the NLP solver uses relative tolerances for the bound
    2613 * constraints but SCIP uses absolute tolerances for checking the integrality conditions.
    2614 */
    2615#ifdef SCIP_DEBUG
    2616 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, TRUE, TRUE, FALSE, TRUE, TRUE, &success) );
    2617#else
    2618 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, TRUE, TRUE, &success) );
    2619#endif
    2620
    2621 /* check, if solution was feasible and good enough */
    2622 if( success )
    2623 {
    2624 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
    2625 *result = SCIP_FOUNDSOL;
    2626 }
    2627 else
    2628 {
    2629 SCIPdebugMsg(scip, " -> solution was not accepted\n");
    2630 }
    2631 }
    2632
    2633 /* end diving */
    2635
    2636 /* free hash map and drop variable bound change events */
    2637 if( covercomputed )
    2638 {
    2639 assert(heurdata->eventhdlr != NULL);
    2640 assert(heurdata->nfixedcovervars >= 0); /* variables might have been globally fixed in propagation */
    2641 assert(varincover != NULL);
    2642 assert(covervars != NULL);
    2643
    2644 SCIPhashmapFree(&varincover);
    2645
    2646 /* drop bound change events of cover variables */
    2647 for( c = 0; c < ncovervars; c++ )
    2648 {
    2649 SCIP_CALL( SCIPdropVarEvent(scip, covervars[c], SCIP_EVENTTYPE_BOUNDCHANGED, heurdata->eventhdlr, (SCIP_EVENTDATA*)heurdata, -1) );
    2650 }
    2651 }
    2652 else
    2653 assert(varincover == NULL);
    2654
    2655 /* free NLP start solution */
    2656 if( nlpstartsol != NULL )
    2657 {
    2658 SCIP_CALL( SCIPfreeSol(scip, &nlpstartsol) );
    2659 }
    2660
    2661 /* free copied best solution */
    2662 if( heurdata->varselrule == 'g' )
    2663 {
    2664 assert(bestsol != NULL);
    2665 SCIP_CALL( SCIPfreeSol(scip, &bestsol) );
    2666 }
    2667 else
    2668 assert(bestsol == NULL);
    2669
    2670 /* free arrays of LP and NLP solution */
    2671 if( heurdata->varselrule == 'd' )
    2672 {
    2673 assert(pseudocandsnlpsol != NULL);
    2674 assert(pseudocandsnlpsol != NULL);
    2675 SCIPfreeBufferArray(scip, &pseudocandsnlpsol);
    2676 SCIPfreeBufferArray(scip, &pseudocandslpsol);
    2677 }
    2678 else
    2679 {
    2680 assert(pseudocandsnlpsol == NULL);
    2681 assert(pseudocandsnlpsol == NULL);
    2682 }
    2683
    2684 /* free array of cover variables */
    2685 if( heurdata->prefercover || heurdata->solvesubmip )
    2686 {
    2687 assert(covervars != NULL || !covercomputed);
    2688 if( covervars != NULL )
    2689 SCIPfreeBufferArray(scip, &covervars);
    2690 }
    2691 else
    2692 assert(covervars == NULL);
    2693
    2694 if( *result == SCIP_FOUNDSOL )
    2695 heurdata->nsuccess++;
    2696
    2697 SCIPdebugMsg(scip, "nlpdiving heuristic finished\n");
    2698
    2699 return SCIP_OKAY; /*lint !e438*/
    2700}
    2701
    2702
    2703/*
    2704 * heuristic specific interface methods
    2705 */
    2706
    2707/** creates the nlpdiving heuristic and includes it in SCIP */
    2709 SCIP* scip /**< SCIP data structure */
    2710 )
    2711{
    2712 SCIP_HEURDATA* heurdata;
    2713 SCIP_HEUR* heur = NULL;
    2714
    2715 /* create heuristic data */
    2716 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    2717 heurdata->inittiming = HEUR_TIMING;
    2718
    2719 /* include heuristic */
    2721 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecNlpdiving, heurdata) );
    2722
    2723 assert(heur != NULL);
    2724 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyNlpdiving) );
    2725 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeNlpdiving) );
    2726 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitNlpdiving) );
    2727 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitNlpdiving) );
    2728 SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolNlpdiving) );
    2729 SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolNlpdiving) );
    2730
    2731 /* get event handler for bound change events */
    2732 heurdata->eventhdlr = NULL;
    2733 /* create event handler for bound change events */
    2735 eventExecNlpdiving, NULL) );
    2736 if ( heurdata->eventhdlr == NULL )
    2737 {
    2738 SCIPerrorMessage("event handler for " HEUR_NAME " heuristic not found.\n");
    2739 return SCIP_PLUGINNOTFOUND;
    2740 }
    2741
    2742 /* nlpdiving heuristic parameters */
    2744 "heuristics/" HEUR_NAME "/minreldepth",
    2745 "minimal relative depth to start diving",
    2746 &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
    2748 "heuristics/" HEUR_NAME "/maxreldepth",
    2749 "maximal relative depth to start diving",
    2750 &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
    2752 "heuristics/" HEUR_NAME "/maxnlpiterabs",
    2753 "minimial absolute number of allowed NLP iterations",
    2754 &heurdata->maxnlpiterabs, FALSE, DEFAULT_MAXNLPITERABS, 0, INT_MAX, NULL, NULL) );
    2756 "heuristics/" HEUR_NAME "/maxnlpiterrel",
    2757 "additional allowed number of NLP iterations relative to successfully found solutions",
    2758 &heurdata->maxnlpiterrel, FALSE, DEFAULT_MAXNLPITERREL, 0, INT_MAX, NULL, NULL) );
    2760 "heuristics/" HEUR_NAME "/maxdiveubquot",
    2761 "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
    2762 &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
    2764 "heuristics/" HEUR_NAME "/maxdiveavgquot",
    2765 "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
    2766 &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    2768 "heuristics/" HEUR_NAME "/maxdiveubquotnosol",
    2769 "maximal UBQUOT when no solution was found yet (0.0: no limit)",
    2770 &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
    2772 "heuristics/" HEUR_NAME "/maxdiveavgquotnosol",
    2773 "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
    2774 &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    2776 "heuristics/" HEUR_NAME "/maxfeasnlps",
    2777 "maximal number of NLPs with feasible solution to solve during one dive",
    2778 &heurdata->maxfeasnlps, FALSE, DEFAULT_MAXFEASNLPS, 1, INT_MAX, NULL, NULL) );
    2780 "heuristics/" HEUR_NAME "/backtrack",
    2781 "use one level of backtracking if infeasibility is encountered?",
    2782 &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
    2784 "heuristics/" HEUR_NAME "/lp",
    2785 "should the LP relaxation be solved before the NLP relaxation?",
    2786 &heurdata->lp, TRUE, DEFAULT_LP, NULL, NULL) );
    2788 "heuristics/" HEUR_NAME "/preferlpfracs",
    2789 "prefer variables that are also fractional in LP solution?",
    2790 &heurdata->preferlpfracs, TRUE, DEFAULT_PREFERLPFRACS, NULL, NULL) );
    2792 "heuristics/" HEUR_NAME "/minsuccquot",
    2793 "heuristic will not run if less then this percentage of calls succeeded (0.0: no limit)",
    2794 &heurdata->minsuccquot, FALSE, DEFAULT_MINSUCCQUOT, 0.0, 1.0, NULL, NULL) );
    2796 "heuristics/" HEUR_NAME "/fixquot",
    2797 "percentage of fractional variables that should be fixed before the next NLP solve",
    2798 &heurdata->fixquot, FALSE, DEFAULT_FIXQUOT, 0.0, 1.0, NULL, NULL) );
    2800 "heuristics/" HEUR_NAME "/prefercover",
    2801 "should variables in a minimal cover be preferred?",
    2802 &heurdata->prefercover, FALSE, DEFAULT_PREFERCOVER, NULL, NULL) );
    2804 "heuristics/" HEUR_NAME "/solvesubmip",
    2805 "should a sub-MIP be solved if all cover variables are fixed?",
    2806 &heurdata->solvesubmip, FALSE, DEFAULT_SOLVESUBMIP, NULL, NULL) );
    2808 "heuristics/" HEUR_NAME "/nlpfastfail",
    2809 "should the NLP solver stop early if it converges slow?",
    2810 &heurdata->nlpfastfail, FALSE, DEFAULT_NLPFASTFAIL, NULL, NULL) );
    2812 "heuristics/" HEUR_NAME "/nlpstart",
    2813 "which point should be used as starting point for the NLP solver? ('n'one, last 'f'easible, from dive's'tart)",
    2814 &heurdata->nlpstart, TRUE, DEFAULT_NLPSTART, "fns", NULL, NULL) );
    2816 "heuristics/" HEUR_NAME "/varselrule",
    2817 "which variable selection should be used? ('f'ractionality, 'c'oefficient, 'p'seudocost, 'g'uided, 'd'ouble, 'v'eclen)",
    2818 &heurdata->varselrule, FALSE, DEFAULT_VARSELRULE, "fcpgdv", NULL, NULL) );
    2819
    2820 return SCIP_OKAY;
    2821}
    #define NULL
    Definition: def.h:248
    #define SCIP_PROBINGSCORE_PENALTYRATIO
    Definition: def.h:303
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:297
    #define SCIP_REAL_MAX
    Definition: def.h:158
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define ABS(x)
    Definition: def.h:216
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:334
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIP_CALL(x)
    Definition: def.h:355
    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:2961
    SCIP_RETCODE SCIPcheckCopyLimits(SCIP *sourcescip, SCIP_Bool *success)
    Definition: scip_copy.c:3249
    SCIP_RETCODE SCIPcopyLimits(SCIP *sourcescip, SCIP *targetscip)
    Definition: scip_copy.c:3292
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:759
    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:2981
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:516
    SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
    Definition: scip_sol.c:884
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1252
    SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:664
    int SCIPgetNSols(SCIP *scip)
    Definition: scip_sol.c:2882
    SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1506
    SCIP_Bool SCIPsolIsOriginal(SCIP_SOL *sol)
    Definition: sol.c:4140
    SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_sol.c:1846
    SCIP_RETCODE SCIPlinkNLPSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1353
    SCIP_RETCODE SCIProundSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *success)
    Definition: scip_sol.c:3123
    SCIP_RETCODE SCIPsetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_sol.c:1662
    SCIP_SOL ** SCIPgetSols(SCIP *scip)
    Definition: scip_sol.c:2931
    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:4012
    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:4109
    SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1892
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1571
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
    Definition: scip_sol.c:2132
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2635
    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:4484
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23478
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4386
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23498
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
    Definition: var.c:4473
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23453
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24142
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_Real SCIPvarGetRootSol(SCIP_VAR *var)
    Definition: var.c:19115
    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:24234
    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:24120
    SCIP_Real SCIPvarGetNLPSol(SCIP_VAR *var)
    Definition: var.c:24691
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4328
    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
    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