Scippy

SCIP

Solving Constraint Integer Programs

heur_intdiving.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_intdiving.c
26 * @ingroup DEFPLUGINS_HEUR
27 * @brief LP diving heuristic that fixes variables with integral LP value
28 * @author Tobias Achterberg
29 */
30
31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32
34#include "scip/heur_intdiving.h"
35#include "scip/pub_heur.h"
36#include "scip/pub_lp.h"
37#include "scip/pub_message.h"
38#include "scip/pub_var.h"
39#include "scip/scip_branch.h"
40#include "scip/scip_general.h"
41#include "scip/scip_heur.h"
42#include "scip/scip_lp.h"
43#include "scip/scip_mem.h"
44#include "scip/scip_message.h"
45#include "scip/scip_numerics.h"
46#include "scip/scip_param.h"
47#include "scip/scip_prob.h"
48#include "scip/scip_probing.h"
49#include "scip/scip_sol.h"
51#include "scip/scip_tree.h"
52#include "scip/scip_var.h"
53#include <string.h>
54
55#define HEUR_NAME "intdiving"
56#define HEUR_DESC "LP diving heuristic that fixes binary variables with large LP value to one"
57#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_DIVING
58#define HEUR_PRIORITY -1003500
59#define HEUR_FREQ -1
60#define HEUR_FREQOFS 9
61#define HEUR_MAXDEPTH -1
62#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPPLUNGE
63#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
64
65
66/*
67 * Default parameter settings
68 */
69
70#define DEFAULT_MINRELDEPTH 0.0 /**< minimal relative depth to start diving */
71#define DEFAULT_MAXRELDEPTH 1.0 /**< maximal relative depth to start diving */
72#define DEFAULT_MAXLPITERQUOT 0.05 /**< maximal fraction of diving LP iterations compared to node LP iterations */
73#define DEFAULT_MAXLPITEROFS 1000 /**< additional number of allowed LP iterations */
74#define DEFAULT_MAXDIVEUBQUOT 0.8 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
75 * where diving is performed (0.0: no limit) */
76#define DEFAULT_MAXDIVEAVGQUOT 0.0 /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
77 * where diving is performed (0.0: no limit) */
78#define DEFAULT_MAXDIVEUBQUOTNOSOL 0.1 /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
79#define DEFAULT_MAXDIVEAVGQUOTNOSOL 0.0 /**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
80#define DEFAULT_BACKTRACK TRUE /**< use one level of backtracking if infeasibility is encountered? */
81
82#define MINLPITER 10000 /**< minimal number of LP iterations allowed in each LP solving call */
83
84
85/* locally defined heuristic data */
86struct SCIP_HeurData
87{
88 SCIP_SOL* sol; /**< working solution */
89 SCIP_Real minreldepth; /**< minimal relative depth to start diving */
90 SCIP_Real maxreldepth; /**< maximal relative depth to start diving */
91 SCIP_Real maxlpiterquot; /**< maximal fraction of diving LP iterations compared to node LP iterations */
92 int maxlpiterofs; /**< additional number of allowed LP iterations */
93 SCIP_Real maxdiveubquot; /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
94 * where diving is performed (0.0: no limit) */
95 SCIP_Real maxdiveavgquot; /**< maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound)
96 * where diving is performed (0.0: no limit) */
97 SCIP_Real maxdiveubquotnosol; /**< maximal UBQUOT when no solution was found yet (0.0: no limit) */
98 SCIP_Real maxdiveavgquotnosol;/**< maximal AVGQUOT when no solution was found yet (0.0: no limit) */
99 SCIP_Bool backtrack; /**< use one level of backtracking if infeasibility is encountered? */
100 SCIP_Longint nlpiterations; /**< LP iterations used in this heuristic */
101 int nsuccess; /**< number of runs that produced at least one feasible solution */
102};
103
104
105/*
106 * local methods
107 */
108
109
110/*
111 * Callback methods
112 */
113
114/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
115static
116SCIP_DECL_HEURCOPY(heurCopyIntdiving)
117{ /*lint --e{715}*/
118 assert(scip != NULL);
119 assert(heur != NULL);
120 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
121
122 /* call inclusion method of primal heuristic */
124
125 return SCIP_OKAY;
126}
127
128/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
129static
130SCIP_DECL_HEURFREE(heurFreeIntdiving) /*lint --e{715}*/
131{ /*lint --e{715}*/
132 SCIP_HEURDATA* heurdata;
133
134 assert(heur != NULL);
135 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
136 assert(scip != NULL);
137
138 /* free heuristic data */
139 heurdata = SCIPheurGetData(heur);
140 assert(heurdata != NULL);
141 SCIPfreeBlockMemory(scip, &heurdata);
142 SCIPheurSetData(heur, NULL);
143
144 return SCIP_OKAY;
145}
146
147
148/** initialization method of primal heuristic (called after problem was transformed) */
149static
150SCIP_DECL_HEURINIT(heurInitIntdiving) /*lint --e{715}*/
151{ /*lint --e{715}*/
152 SCIP_HEURDATA* heurdata;
153
154 assert(heur != NULL);
155 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
156
157 /* get heuristic data */
158 heurdata = SCIPheurGetData(heur);
159 assert(heurdata != NULL);
160
161 /* create working solution */
162 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
163
164 /* initialize data */
165 heurdata->nlpiterations = 0;
166 heurdata->nsuccess = 0;
167
168 return SCIP_OKAY;
169}
170
171
172/** deinitialization method of primal heuristic (called before transformed problem is freed) */
173static
174SCIP_DECL_HEUREXIT(heurExitIntdiving) /*lint --e{715}*/
175{ /*lint --e{715}*/
176 SCIP_HEURDATA* heurdata;
177
178 assert(heur != NULL);
179 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
180
181 /* get heuristic data */
182 heurdata = SCIPheurGetData(heur);
183 assert(heurdata != NULL);
184
185 /* free working solution */
186 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
187
188 return SCIP_OKAY;
189}
190
191
192/** execution method of primal heuristic */
193static
194SCIP_DECL_HEUREXEC(heurExecIntdiving) /*lint --e{715}*/
195{ /*lint --e{715}*/
196 SCIP_HEURDATA* heurdata;
197 SCIP_LPSOLSTAT lpsolstat;
198 SCIP_VAR** pseudocands;
199 SCIP_VAR** fixcands;
200 SCIP_Real* fixcandscores;
201 SCIP_Real searchubbound;
202 SCIP_Real searchavgbound;
203 SCIP_Real searchbound;
204 SCIP_Real objval;
205 SCIP_Bool lperror;
206 SCIP_Bool cutoff;
207 SCIP_Bool backtracked;
208 SCIP_Longint ncalls;
209 SCIP_Longint nsolsfound;
210 SCIP_Longint nlpiterations;
211 SCIP_Longint maxnlpiterations;
212 int nfixcands;
213 int nbinfixcands;
214 int depth;
215 int maxdepth;
216 int maxdivedepth;
217 int divedepth;
218 int nextcand;
219 int c;
220
221 assert(heur != NULL);
222 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
223 assert(scip != NULL);
224 assert(result != NULL);
225 assert(SCIPhasCurrentNodeLP(scip));
226
227 *result = SCIP_DELAYED;
228
229 /* do not call heuristic of node was already detected to be infeasible */
230 if( nodeinfeasible )
231 return SCIP_OKAY;
232
233 /* only call heuristic, if an optimal LP solution is at hand */
235 return SCIP_OKAY;
236
237 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
239 return SCIP_OKAY;
240
241 /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
242 if( !SCIPisLPSolBasic(scip) )
243 return SCIP_OKAY;
244
245 /* don't dive two times at the same node */
247 return SCIP_OKAY;
248
249 *result = SCIP_DIDNOTRUN;
250
251 /* get heuristic's data */
252 heurdata = SCIPheurGetData(heur);
253 assert(heurdata != NULL);
254
255 /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
256 depth = SCIPgetDepth(scip);
257 maxdepth = SCIPgetMaxDepth(scip);
258 maxdepth = MAX(maxdepth, 100);
259 if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
260 return SCIP_OKAY;
261
262 /* calculate the maximal number of LP iterations until heuristic is aborted */
263 nlpiterations = SCIPgetNNodeLPIterations(scip);
264 ncalls = SCIPheurGetNCalls(heur);
265 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
266 maxnlpiterations = (SCIP_Longint)(((nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
267 maxnlpiterations += heurdata->maxlpiterofs;
268
269 /* don't try to dive, if we took too many LP iterations during diving */
270 if( heurdata->nlpiterations >= maxnlpiterations )
271 return SCIP_OKAY;
272
273 /* allow at least a certain number of LP iterations in this dive */
274 maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);
275
276 /* get unfixed integer variables */
277 SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &nfixcands, NULL) );
278
279 /* don't try to dive, if there are no fractional variables */
280 if( nfixcands == 0 )
281 return SCIP_OKAY;
282
283 /* calculate the objective search bound */
284 if( SCIPgetNSolsFound(scip) == 0 )
285 {
286 if( heurdata->maxdiveubquotnosol > 0.0 )
287 searchubbound = SCIPgetLowerbound(scip)
288 + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
289 else
290 searchubbound = SCIPinfinity(scip);
291 if( heurdata->maxdiveavgquotnosol > 0.0 )
292 searchavgbound = SCIPgetLowerbound(scip)
293 + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
294 else
295 searchavgbound = SCIPinfinity(scip);
296 }
297 else
298 {
299 if( heurdata->maxdiveubquot > 0.0 )
300 searchubbound = SCIPgetLowerbound(scip)
301 + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
302 else
303 searchubbound = SCIPinfinity(scip);
304 if( heurdata->maxdiveavgquot > 0.0 )
305 searchavgbound = SCIPgetLowerbound(scip)
306 + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
307 else
308 searchavgbound = SCIPinfinity(scip);
309 }
310 searchbound = MIN(searchubbound, searchavgbound);
312 searchbound = SCIPceil(scip, searchbound);
313
314 /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
316 assert(maxdivedepth >= 0);
317 maxdivedepth = MIN(maxdivedepth, maxdepth);
318 maxdivedepth *= 10;
319
320 *result = SCIP_DIDNOTFIND;
321
322 /* start diving */
324
325 /* enables collection of variable statistics during probing */
327
328 SCIPdebugMsg(scip, "(node %" SCIP_LONGINT_FORMAT ") executing intdiving heuristic: depth=%d, %d non-fixed, dualbound=%g, searchbound=%g\n",
330
331 /* copy the pseudo candidates into own array, because we want to reorder them */
332 SCIP_CALL( SCIPduplicateBufferArray(scip, &fixcands, pseudocands, nfixcands) );
333
334 /* sort non-fixed variables by non-increasing inference score, but prefer binaries over integers in any case */
335 SCIP_CALL( SCIPallocBufferArray(scip, &fixcandscores, nfixcands) );
336 nbinfixcands = 0;
337 for( c = 0; c < nfixcands; ++c )
338 {
339 SCIP_VAR* var;
340 SCIP_Real score;
341 int colveclen;
342 int left;
343 int right;
344 int i;
345
346 assert(c >= nbinfixcands);
347 var = fixcands[c];
348 assert(SCIPvarIsIntegral(var));
350 if( SCIPvarIsBinary(var) )
351 {
352 score = 500.0 * SCIPvarGetNCliques(var, TRUE) + 100.0 * SCIPvarGetNImpls(var, TRUE)
353 + SCIPgetVarAvgInferenceScore(scip, var) + (SCIP_Real)colveclen/100.0;
354
355 /* shift the non-binary variables one slot to the right */
356 for( i = c; i > nbinfixcands; --i )
357 {
358 fixcands[i] = fixcands[i-1];
359 fixcandscores[i] = fixcandscores[i-1];
360 }
361 /* put the new candidate into the first nbinfixcands slot */
362 left = 0;
363 right = nbinfixcands;
364 nbinfixcands++;
365 }
366 else
367 {
368 score = 5.0 * (SCIPvarGetNCliques(var, FALSE) + SCIPvarGetNCliques(var, TRUE))
370 + (SCIP_Real)colveclen/10000.0;
371
372 /* put the new candidate in the slots after the binary candidates */
373 left = nbinfixcands;
374 right = c;
375 }
376 for( i = right; i > left && score > fixcandscores[i-1]; --i )
377 {
378 fixcands[i] = fixcands[i-1];
379 fixcandscores[i] = fixcandscores[i-1];
380 }
381 fixcands[i] = var;
382 fixcandscores[i] = score;
383 SCIPdebugMsg(scip, " <%s>: ncliques=%d/%d, nimpls=%d/%d, inferencescore=%g, colveclen=%d -> score=%g\n",
386 colveclen, score);
387 }
388 SCIPfreeBufferArray(scip, &fixcandscores);
389
390 /* get LP objective value */
391 lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
392 objval = SCIPgetLPObjval(scip);
393
394 /* dive as long we are in the given objective, depth and iteration limits, but if possible, we dive at least with
395 * the depth 10
396 */
397 lperror = FALSE;
398 cutoff = FALSE;
399 divedepth = 0;
400 nextcand = 0;
401 while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL
402 && (divedepth < 10
403 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound))
404 && !SCIPisStopped(scip) )
405 {
406 SCIP_VAR* var;
407 SCIP_Real bestsolval;
408 SCIP_Real bestfixval;
409 int bestcand;
410 SCIP_Longint nnewlpiterations;
411 SCIP_Longint nnewdomreds;
412
413 /* open a new probing node if this will not exceed the maximal tree depth, otherwise stop here */
415 {
417 divedepth++;
418 }
419 else
420 break;
421
422 nnewlpiterations = 0;
423 nnewdomreds = 0;
424
425 /* fix binary variable that is closest to 1 in the LP solution to 1;
426 * if all binary variables are fixed, fix integer variable with least fractionality in LP solution
427 */
428 bestcand = -1;
429 bestsolval = -1.0;
430 bestfixval = 1.0;
431
432 /* look in the binary variables for fixing candidates */
433 for( c = nextcand; c < nbinfixcands; ++c )
434 {
435 SCIP_Real solval;
436
437 var = fixcands[c];
438
439 /* ignore already fixed variables */
440 if( var == NULL )
441 continue;
442 if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 )
443 {
444 fixcands[c] = NULL;
445 continue;
446 }
447
448 /* get the LP solution value */
449 solval = SCIPvarGetLPSol(var);
450
451 if( solval > bestsolval )
452 {
453 bestcand = c;
454 bestfixval = 1.0;
455 bestsolval = solval;
456 if( SCIPisGE(scip, bestsolval, 1.0) )
457 {
458 /* we found an unfixed binary variable with LP solution value of 1.0 - there cannot be a better candidate */
459 break;
460 }
461 else if( SCIPisLE(scip, bestsolval, 0.0) )
462 {
463 /* the variable is currently at 0.0 - this is the only situation where we want to fix it to 0.0 */
464 bestfixval = 0.0;
465 }
466 }
467 }
468
469 /* if all binary variables are fixed, look in the integer variables for a fixing candidate */
470 if( bestcand == -1 )
471 {
472 SCIP_Real bestfrac;
473
474 bestfrac = SCIP_INVALID;
475 for( c = MAX(nextcand, nbinfixcands); c < nfixcands; ++c )
476 {
477 SCIP_Real solval;
478 SCIP_Real frac;
479
480 var = fixcands[c];
481
482 /* ignore already fixed variables */
483 if( var == NULL )
484 continue;
485 if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
486 {
487 fixcands[c] = NULL;
488 continue;
489 }
490
491 /* get the LP solution value */
492 solval = SCIPvarGetLPSol(var);
493 frac = SCIPfrac(scip, solval);
494
495 /* ignore integer variables that are currently integral */
496 if( SCIPisFeasFracIntegral(scip, frac) )
497 continue;
498
499 if( frac < bestfrac )
500 {
501 bestcand = c;
502 bestsolval = solval;
503 bestfrac = frac;
504 bestfixval = SCIPfloor(scip, bestsolval + 0.5);
505 if( SCIPisZero(scip, bestfrac) )
506 {
507 /* we found an unfixed integer variable with integral LP solution value */
508 break;
509 }
510 }
511 }
512 }
513 assert(-1 <= bestcand && bestcand < nfixcands);
514
515 /* if there is no unfixed candidate left, we are done */
516 if( bestcand == -1 )
517 break;
518
519 var = fixcands[bestcand];
520 assert(var != NULL);
521 assert(SCIPvarIsIntegral(var));
522 assert(SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) > 0.5);
523 assert(SCIPisGE(scip, bestfixval, SCIPvarGetLbLocal(var)));
524 assert(SCIPisLE(scip, bestfixval, SCIPvarGetUbLocal(var)));
525
526 backtracked = FALSE;
527 do
528 {
529 /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
530 * occured or variable was fixed by propagation while backtracking => Abort diving!
531 */
532 if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
533 {
534 SCIPdebugMsg(scip, "Selected variable <%s> already fixed to [%g,%g], diving aborted \n",
536 cutoff = TRUE;
537 break;
538 }
539 if( SCIPisFeasLT(scip, bestfixval, SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, bestfixval, SCIPvarGetUbLocal(var)) )
540 {
541 SCIPdebugMsg(scip, "selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
542 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval);
543 assert(backtracked);
544 break;
545 }
546
547 /* apply fixing of best candidate */
548 SCIPdebugMsg(scip, " dive %d/%d, LP iter %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ", %d unfixed: var <%s>, sol=%g, oldbounds=[%g,%g], fixed to %g\n",
549 divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPgetNPseudoBranchCands(scip),
550 SCIPvarGetName(var), bestsolval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval);
551 SCIP_CALL( SCIPfixVarProbing(scip, var, bestfixval) );
552
553 /* apply domain propagation */
554 SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, &nnewdomreds) );
555 if( !cutoff )
556 {
557 /* if the best candidate was just fixed to its LP value and no domain reduction was found, the LP solution
558 * stays valid, and the LP does not need to be resolved
559 */
560 if( nnewdomreds > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) )
561 {
562 /* resolve the diving LP */
563 /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
564 * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
565 */
566#ifdef NDEBUG
567 SCIP_RETCODE retstat;
568 nlpiterations = SCIPgetNLPIterations(scip);
569 retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff);
570 if( retstat != SCIP_OKAY )
571 {
572 SCIPwarningMessage(scip, "Error while solving LP in Intdiving heuristic; LP solve terminated with code <%d>\n",retstat);
573 }
574#else
575 nlpiterations = SCIPgetNLPIterations(scip);
576 SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) );
577#endif
578
579 if( lperror )
580 break;
581
582 /* update iteration count */
583 nnewlpiterations = SCIPgetNLPIterations(scip) - nlpiterations;
584 heurdata->nlpiterations += nnewlpiterations;
585
586 /* get LP solution status */
587 lpsolstat = SCIPgetLPSolstat(scip);
588 assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
590 }
591 }
592
593 /* perform backtracking if a cutoff was detected */
594 if( cutoff && !backtracked && heurdata->backtrack )
595 {
596 SCIPdebugMsg(scip, " *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
598
599 /* after backtracking there has to be at least one open node without exceeding the maximal tree depth */
601
603
604 bestfixval = SCIPvarIsBinary(var)
605 ? 1.0 - bestfixval
606 : (SCIPisGT(scip, bestsolval, bestfixval) && SCIPisFeasLE(scip, bestfixval + 1, SCIPvarGetUbLocal(var)) ? bestfixval + 1 : bestfixval - 1);
607
608 backtracked = TRUE;
609 }
610 else
611 backtracked = FALSE;
612 }
613 while( backtracked );
614
615 if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
616 {
617 SCIP_Bool success;
618
619 /* get new objective value */
620 objval = SCIPgetLPObjval(scip);
621
622 if( nnewlpiterations > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) )
623 {
624 /* we must start again with the first candidate, since the LP solution changed */
625 nextcand = 0;
626
627 /* create solution from diving LP and try to round it */
628 SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
629 SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
630 if( success )
631 {
632 SCIPdebugMsg(scip, "intdiving found roundable primal solution: obj=%g\n",
633 SCIPgetSolOrigObj(scip, heurdata->sol));
634
635 /* try to add solution to SCIP */
636 SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, FALSE, &success) );
637
638 /* check, if solution was feasible and good enough */
639 if( success )
640 {
641 SCIPdebugMsg(scip, " -> solution was feasible and good enough\n");
642 *result = SCIP_FOUNDSOL;
643 }
644 }
645 }
646 else
647 nextcand = bestcand+1; /* continue with the next candidate in the following loop */
648 }
649 SCIPdebugMsg(scip, " -> lpsolstat=%d, objval=%g/%g\n", lpsolstat, objval, searchbound);
650 }
651
652 /* free temporary memory */
653 SCIPfreeBufferArray(scip, &fixcands);
654
655 /* end diving */
657
658 if( *result == SCIP_FOUNDSOL )
659 heurdata->nsuccess++;
660
661 SCIPdebugMsg(scip, "intdiving heuristic finished\n");
662
663 return SCIP_OKAY; /*lint !e438*/
664}
665
666
667/*
668 * heuristic specific interface methods
669 */
670
671/** creates the intdiving heuristic and includes it in SCIP */
673 SCIP* scip /**< SCIP data structure */
674 )
675{
676 SCIP_HEURDATA* heurdata;
677 SCIP_HEUR* heur;
678
679 /* create Intdiving primal heuristic data */
680 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
681
682 /* include primal heuristic */
685 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecIntdiving, heurdata) );
686
687 assert(heur != NULL);
688
689 /* primal heuristic is safe to use in exact solving mode */
690 SCIPheurMarkExact(heur);
691
692 /* set non-NULL pointers to callback methods */
693 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyIntdiving) );
694 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeIntdiving) );
695 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitIntdiving) );
696 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitIntdiving) );
697
698 /* intdiving heuristic parameters */
700 "heuristics/intdiving/minreldepth",
701 "minimal relative depth to start diving",
702 &heurdata->minreldepth, TRUE, DEFAULT_MINRELDEPTH, 0.0, 1.0, NULL, NULL) );
704 "heuristics/intdiving/maxreldepth",
705 "maximal relative depth to start diving",
706 &heurdata->maxreldepth, TRUE, DEFAULT_MAXRELDEPTH, 0.0, 1.0, NULL, NULL) );
708 "heuristics/intdiving/maxlpiterquot",
709 "maximal fraction of diving LP iterations compared to node LP iterations",
710 &heurdata->maxlpiterquot, FALSE, DEFAULT_MAXLPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
712 "heuristics/intdiving/maxlpiterofs",
713 "additional number of allowed LP iterations",
714 &heurdata->maxlpiterofs, FALSE, DEFAULT_MAXLPITEROFS, 0, INT_MAX, NULL, NULL) );
716 "heuristics/intdiving/maxdiveubquot",
717 "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where diving is performed (0.0: no limit)",
718 &heurdata->maxdiveubquot, TRUE, DEFAULT_MAXDIVEUBQUOT, 0.0, 1.0, NULL, NULL) );
720 "heuristics/intdiving/maxdiveavgquot",
721 "maximal quotient (curlowerbound - lowerbound)/(avglowerbound - lowerbound) where diving is performed (0.0: no limit)",
722 &heurdata->maxdiveavgquot, TRUE, DEFAULT_MAXDIVEAVGQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
724 "heuristics/intdiving/maxdiveubquotnosol",
725 "maximal UBQUOT when no solution was found yet (0.0: no limit)",
726 &heurdata->maxdiveubquotnosol, TRUE, DEFAULT_MAXDIVEUBQUOTNOSOL, 0.0, 1.0, NULL, NULL) );
728 "heuristics/intdiving/maxdiveavgquotnosol",
729 "maximal AVGQUOT when no solution was found yet (0.0: no limit)",
730 &heurdata->maxdiveavgquotnosol, TRUE, DEFAULT_MAXDIVEAVGQUOTNOSOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
732 "heuristics/intdiving/backtrack",
733 "use one level of backtracking if infeasibility is encountered?",
734 &heurdata->backtrack, FALSE, DEFAULT_BACKTRACK, NULL, NULL) );
735
736 return SCIP_OKAY;
737}
#define NULL
Definition: def.h:248
#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 TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2569
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
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
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 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 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 SCIPincludeHeurIntdiving(SCIP *scip)
SCIP_RETCODE SCIPgetPseudoBranchCands(SCIP *scip, SCIP_VAR ***pseudocands, int *npseudocands, int *npriopseudocands)
Definition: scip_branch.c:741
int SCIPgetNPseudoBranchCands(SCIP *scip)
Definition: scip_branch.c:766
int SCIPcolGetNNonz(SCIP_COL *col)
Definition: lp.c:17520
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
Definition: scip_heur.c:167
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:1368
SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, SCIP_HEURTIMING timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
Definition: scip_heur.c:122
SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
Definition: scip_heur.c:183
SCIP_RETCODE SCIPsetHeurExit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXIT((*heurexit)))
Definition: scip_heur.c:215
SCIP_Longint SCIPheurGetNBestSolsFound(SCIP_HEUR *heur)
Definition: heur.c:1613
SCIP_Longint SCIPheurGetNCalls(SCIP_HEUR *heur)
Definition: heur.c:1593
void SCIPheurMarkExact(SCIP_HEUR *heur)
Definition: heur.c:1457
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
Definition: scip_heur.c:199
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1467
void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
Definition: heur.c:1378
SCIP_Longint SCIPgetLastDivenode(SCIP *scip)
Definition: scip_lp.c:2710
SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition: scip_lp.c:87
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
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
int SCIPgetProbingDepth(SCIP *scip)
Definition: scip_probing.c:199
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 SCIPfixVarProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval)
Definition: scip_probing.c:419
SCIP_RETCODE SCIPendProbing(SCIP *scip)
Definition: scip_probing.c:261
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:516
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
SCIP_RETCODE SCIProundSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *success)
Definition: scip_sol.c:3123
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 SCIPlinkLPSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1295
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1892
SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
Definition: scip_sol.c:2132
SCIP_Longint SCIPgetNSolsFound(SCIP *scip)
int SCIPgetMaxDepth(SCIP *scip)
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_Real SCIPgetDualbound(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Real SCIPgetAvgLowerbound(SCIP *scip)
SCIP_Longint SCIPgetNNodeLPIterations(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasFracIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
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_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:23683
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_Real SCIPgetVarAvgInferenceScore(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:11945
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24568
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:23386
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition: var.c:24664
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24642
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
void SCIPenableVarHistory(SCIP *scip)
Definition: scip_var.c:11083
#define DEFAULT_MAXDIVEUBQUOT
static SCIP_DECL_HEURFREE(heurFreeIntdiving)
#define HEUR_TIMING
#define DEFAULT_MAXLPITERQUOT
#define HEUR_FREQOFS
#define HEUR_DESC
static SCIP_DECL_HEURCOPY(heurCopyIntdiving)
#define MINLPITER
#define DEFAULT_MAXDIVEAVGQUOT
#define DEFAULT_BACKTRACK
static SCIP_DECL_HEUREXEC(heurExecIntdiving)
#define DEFAULT_MAXDIVEUBQUOTNOSOL
#define HEUR_DISPCHAR
#define HEUR_MAXDEPTH
#define HEUR_PRIORITY
#define DEFAULT_MAXRELDEPTH
#define DEFAULT_MAXLPITEROFS
#define DEFAULT_MAXDIVEAVGQUOTNOSOL
#define HEUR_NAME
static SCIP_DECL_HEURINIT(heurInitIntdiving)
#define HEUR_FREQ
#define DEFAULT_MINRELDEPTH
static SCIP_DECL_HEUREXIT(heurExitIntdiving)
#define HEUR_USESSUBSCIP
LP diving heuristic that fixes variables with integral LP value.
memory allocation routines
public methods for primal heuristics
public methods for LP management
public methods for message output
public methods for problem variables
public methods for branching rule plugins and branching
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 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 solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:77
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:52
@ 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_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_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_VARSTATUS_COLUMN
Definition: type_var.h:53