Scippy

SCIP

Solving Constraint Integer Programs

heur_rounding.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_rounding.c
26 * @ingroup DEFPLUGINS_HEUR
27 * @brief LP rounding heuristic that tries to recover from intermediate infeasibilities
28 * @author Tobias Achterberg
29 */
30
31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32
34#include "scip/heur_rounding.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_heur.h"
41#include "scip/scip_lp.h"
42#include "scip/scip_mem.h"
43#include "scip/scip_message.h"
44#include "scip/scip_numerics.h"
45#include "scip/scip_param.h"
46#include "scip/scip_sol.h"
48#include <string.h>
49
50#define HEUR_NAME "rounding"
51#define HEUR_DESC "LP rounding heuristic with infeasibility recovering"
52#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_ROUNDING
53#define HEUR_PRIORITY -1000
54#define HEUR_FREQ 1
55#define HEUR_FREQOFS 0
56#define HEUR_MAXDEPTH -1
57#define HEUR_TIMING SCIP_HEURTIMING_DURINGLPLOOP
58#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
59
60#define DEFAULT_SUCCESSFACTOR 100 /**< number of calls per found solution that are considered as standard success,
61 * a higher factor causes the heuristic to be called more often
62 */
63#define DEFAULT_ONCEPERNODE FALSE /**< should the heuristic only be called once per node? */
64
65/* locally defined heuristic data */
66struct SCIP_HeurData
67{
68 SCIP_SOL* sol; /**< working solution */
69 SCIP_Longint lastlp; /**< last LP number where the heuristic was applied */
70 int successfactor; /**< number of calls per found solution that are considered as standard success,
71 * a higher factor causes the heuristic to be called more often
72 */
73 SCIP_Bool oncepernode; /**< should the heuristic only be called once per node? */
74};
75
76
77/*
78 * local methods
79 */
80
81/** update row violation arrays after a row's activity value changed */
82static
84 SCIP* scip, /**< SCIP data structure */
85 SCIP_ROW* row, /**< LP row */
86 SCIP_ROW** violrows, /**< array with currently violated rows */
87 int* violrowpos, /**< position of LP rows in violrows array */
88 int* nviolrows, /**< pointer to the number of currently violated rows */
89 SCIP_Real oldactivity, /**< old activity value of LP row */
90 SCIP_Real newactivity /**< new activity value of LP row */
91 )
92{
93 SCIP_Real lhs;
94 SCIP_Real rhs;
95 SCIP_Bool oldviol;
96 SCIP_Bool newviol;
97
98 assert(violrows != NULL);
99 assert(violrowpos != NULL);
100 assert(nviolrows != NULL);
101
102 lhs = SCIProwGetLhs(row);
103 rhs = SCIProwGetRhs(row);
104 oldviol = (SCIPisFeasLT(scip, oldactivity, lhs) || SCIPisFeasGT(scip, oldactivity, rhs));
105 newviol = (SCIPisFeasLT(scip, newactivity, lhs) || SCIPisFeasGT(scip, newactivity, rhs));
106 if( oldviol != newviol )
107 {
108 int rowpos;
109 int violpos;
110
111 rowpos = SCIProwGetLPPos(row);
112 assert(rowpos >= 0);
113
114 if( oldviol )
115 {
116 /* the row violation was repaired: remove row from violrows array, decrease violation count */
117 violpos = violrowpos[rowpos];
118 assert(0 <= violpos && violpos < *nviolrows);
119 assert(violrows[violpos] == row);
120 violrowpos[rowpos] = -1;
121 if( violpos != *nviolrows-1 )
122 {
123 violrows[violpos] = violrows[*nviolrows-1];
124 violrowpos[SCIProwGetLPPos(violrows[violpos])] = violpos;
125 }
126 (*nviolrows)--;
127 }
128 else
129 {
130 /* the row is now violated: add row to violrows array, increase violation count */
131 assert(violrowpos[rowpos] == -1);
132 violrows[*nviolrows] = row;
133 violrowpos[rowpos] = *nviolrows;
134 (*nviolrows)++;
135 }
136 }
137}
138
139/** update row activities after a variable's solution value changed */
140static
142 SCIP* scip, /**< SCIP data structure */
143 SCIP_Real* activities, /**< LP row activities */
144 SCIP_ROW** violrows, /**< array with currently violated rows */
145 int* violrowpos, /**< position of LP rows in violrows array */
146 int* nviolrows, /**< pointer to the number of currently violated rows */
147 int nlprows, /**< number of rows in current LP */
148 SCIP_VAR* var, /**< variable that has been changed */
149 SCIP_Real oldsolval, /**< old solution value of variable */
150 SCIP_Real newsolval /**< new solution value of variable */
151 )
152{
153 SCIP_COL* col;
154 SCIP_ROW** colrows;
155 SCIP_Real* colvals;
156 SCIP_Real delta;
157 int ncolrows;
158 int r;
159
160 assert(activities != NULL);
161 assert(nviolrows != NULL);
162 assert(0 <= *nviolrows && *nviolrows <= nlprows);
163
164 delta = newsolval - oldsolval;
165 col = SCIPvarGetCol(var);
166 colrows = SCIPcolGetRows(col);
167 colvals = SCIPcolGetVals(col);
168 ncolrows = SCIPcolGetNLPNonz(col);
169 assert(ncolrows == 0 || (colrows != NULL && colvals != NULL));
170
171 for( r = 0; r < ncolrows; ++r )
172 {
173 SCIP_ROW* row;
174 int rowpos;
175
176 row = colrows[r];
177 rowpos = SCIProwGetLPPos(row);
178 assert(-1 <= rowpos && rowpos < nlprows);
179
180 if( rowpos >= 0 && !SCIProwIsLocal(row) )
181 {
182 SCIP_Real oldactivity;
183 SCIP_Real newactivity;
184
185 assert(SCIProwIsInLP(row));
186
187 /* update row activity */
188 oldactivity = activities[rowpos];
189 if( !SCIPisInfinity(scip, -oldactivity) && !SCIPisInfinity(scip, oldactivity) )
190 {
191 newactivity = oldactivity + delta * colvals[r];
192 if( SCIPisInfinity(scip, newactivity) )
193 newactivity = SCIPinfinity(scip);
194 else if( SCIPisInfinity(scip, -newactivity) )
195 newactivity = -SCIPinfinity(scip);
196 activities[rowpos] = newactivity;
197
198 /* update row violation arrays */
199 updateViolations(scip, row, violrows, violrowpos, nviolrows, oldactivity, newactivity);
200 }
201 }
202 }
203
204 return SCIP_OKAY;
205}
206
207/** returns a variable, that pushes activity of the row in the given direction with minimal negative impact on other rows;
208 * if variables have equal impact, chooses the one with best objective value improvement in corresponding direction;
209 * rounding in a direction is forbidden, if this forces the objective value over the upper bound
210 */
211static
213 SCIP* scip, /**< SCIP data structure */
214 SCIP_SOL* sol, /**< primal solution */
215 SCIP_Real minobj, /**< minimal objective value possible after rounding remaining fractional vars */
216 SCIP_ROW* row, /**< LP row */
217 int direction, /**< should the activity be increased (+1) or decreased (-1)? */
218 SCIP_VAR** roundvar, /**< pointer to store the rounding variable, returns NULL if impossible */
219 SCIP_Real* oldsolval, /**< pointer to store old (fractional) solution value of rounding variable */
220 SCIP_Real* newsolval /**< pointer to store new (rounded) solution value of rounding variable */
221 )
222{
223 SCIP_COL* col;
224 SCIP_VAR* var;
225 SCIP_Real val;
226 SCIP_COL** rowcols;
227 SCIP_Real* rowvals;
228 SCIP_Real solval;
229 SCIP_Real roundval;
230 SCIP_Real obj;
231 SCIP_Real deltaobj;
232 SCIP_Real bestdeltaobj;
233 int nrowcols;
234 int nlocks;
235 int minnlocks;
236 int c;
237
238 assert(direction == +1 || direction == -1);
239 assert(roundvar != NULL);
240 assert(oldsolval != NULL);
241 assert(newsolval != NULL);
242
243 /* get row entries */
244 rowcols = SCIProwGetCols(row);
245 rowvals = SCIProwGetVals(row);
246 nrowcols = SCIProwGetNLPNonz(row);
247
248 /* select rounding variable */
249 minnlocks = INT_MAX;
250 bestdeltaobj = SCIPinfinity(scip);
251 *roundvar = NULL;
252 for( c = 0; c < nrowcols; ++c )
253 {
254 col = rowcols[c];
255 var = SCIPcolGetVar(col);
256
258 {
259 solval = SCIPgetSolVal(scip, sol, var);
260
261 if( !SCIPisFeasIntegral(scip, solval) )
262 {
263 val = rowvals[c];
264 obj = SCIPvarGetObj(var);
265
266 if( direction * val < 0.0 )
267 {
268 /* rounding down */
270 if( nlocks <= minnlocks )
271 {
272 roundval = SCIPfeasFloor(scip, solval);
273 deltaobj = obj * (roundval - solval);
274 if( (nlocks < minnlocks || deltaobj < bestdeltaobj) && minobj - obj < SCIPgetCutoffbound(scip) )
275 {
276 minnlocks = nlocks;
277 bestdeltaobj = deltaobj;
278 *roundvar = var;
279 *oldsolval = solval;
280 *newsolval = roundval;
281 }
282 }
283 }
284 else
285 {
286 /* rounding up */
287 assert(direction * val > 0.0);
289 if( nlocks <= minnlocks )
290 {
291 roundval = SCIPfeasCeil(scip, solval);
292 deltaobj = obj * (roundval - solval);
293 if( (nlocks < minnlocks || deltaobj < bestdeltaobj) && minobj + obj < SCIPgetCutoffbound(scip) )
294 {
295 minnlocks = nlocks;
296 bestdeltaobj = deltaobj;
297 *roundvar = var;
298 *oldsolval = solval;
299 *newsolval = roundval;
300 }
301 }
302 }
303 }
304 }
305 }
306
307 return SCIP_OKAY;
308}
309
310/** returns a variable, that increases the activity of the row */
311static
313 SCIP* scip, /**< SCIP data structure */
314 SCIP_SOL* sol, /**< primal solution */
315 SCIP_Real minobj, /**< minimal objective value possible after rounding remaining fractional vars */
316 SCIP_ROW* row, /**< LP row */
317 SCIP_VAR** roundvar, /**< pointer to store the rounding variable, returns NULL if impossible */
318 SCIP_Real* oldsolval, /**< old (fractional) solution value of rounding variable */
319 SCIP_Real* newsolval /**< new (rounded) solution value of rounding variable */
320 )
321{
322 return selectRounding(scip, sol, minobj, row, +1, roundvar, oldsolval, newsolval);
323}
324
325/** returns a variable, that decreases the activity of the row */
326static
328 SCIP* scip, /**< SCIP data structure */
329 SCIP_SOL* sol, /**< primal solution */
330 SCIP_Real minobj, /**< minimal objective value possible after rounding remaining fractional vars */
331 SCIP_ROW* row, /**< LP row */
332 SCIP_VAR** roundvar, /**< pointer to store the rounding variable, returns NULL if impossible */
333 SCIP_Real* oldsolval, /**< old (fractional) solution value of rounding variable */
334 SCIP_Real* newsolval /**< new (rounded) solution value of rounding variable */
335 )
336{
337 return selectRounding(scip, sol, minobj, row, -1, roundvar, oldsolval, newsolval);
338}
339
340/** returns a fractional variable, that has most impact on rows in opposite direction, i.e. that is most crucial to
341 * fix in the other direction;
342 * if variables have equal impact, chooses the one with best objective value improvement in corresponding direction;
343 * rounding in a direction is forbidden, if this forces the objective value over the upper bound
344 */
345static
347 SCIP* scip, /**< SCIP data structure */
348 SCIP_SOL* sol, /**< primal solution */
349 SCIP_Real minobj, /**< minimal objective value possible after rounding remaining fractional vars */
350 SCIP_VAR** lpcands, /**< fractional variables in LP */
351 int nlpcands, /**< number of fractional variables in LP */
352 SCIP_VAR** roundvar, /**< pointer to store the rounding variable, returns NULL if impossible */
353 SCIP_Real* oldsolval, /**< old (fractional) solution value of rounding variable */
354 SCIP_Real* newsolval /**< new (rounded) solution value of rounding variable */
355 )
356{
357 SCIP_VAR* var;
358 SCIP_Real solval;
359 SCIP_Real roundval;
360 SCIP_Real obj;
361 SCIP_Real deltaobj;
362 SCIP_Real bestdeltaobj;
363 int maxnlocks;
364 int nlocks;
365 int v;
366
367 assert(roundvar != NULL);
368 assert(oldsolval != NULL);
369 assert(newsolval != NULL);
370
371 /* select rounding variable */
372 maxnlocks = -1;
373 bestdeltaobj = SCIPinfinity(scip);
374 *roundvar = NULL;
375 for( v = 0; v < nlpcands; ++v )
376 {
377 var = lpcands[v];
379
380 solval = SCIPgetSolVal(scip, sol, var);
381 if( !SCIPisFeasIntegral(scip, solval) )
382 {
383 obj = SCIPvarGetObj(var);
384
385 /* rounding down */
387 if( nlocks >= maxnlocks )
388 {
389 roundval = SCIPfeasFloor(scip, solval);
390 deltaobj = obj * (roundval - solval);
391 if( (nlocks > maxnlocks || deltaobj < bestdeltaobj) && minobj - obj < SCIPgetCutoffbound(scip) )
392 {
393 maxnlocks = nlocks;
394 bestdeltaobj = deltaobj;
395 *roundvar = var;
396 *oldsolval = solval;
397 *newsolval = roundval;
398 }
399 }
400
401 /* rounding up */
403 if( nlocks >= maxnlocks )
404 {
405 roundval = SCIPfeasCeil(scip, solval);
406 deltaobj = obj * (roundval - solval);
407 if( (nlocks > maxnlocks || deltaobj < bestdeltaobj) && minobj + obj < SCIPgetCutoffbound(scip) )
408 {
409 maxnlocks = nlocks;
410 bestdeltaobj = deltaobj;
411 *roundvar = var;
412 *oldsolval = solval;
413 *newsolval = roundval;
414 }
415 }
416 }
417 }
418
419 return SCIP_OKAY;
420}
421
422
423/*
424 * Callback methods
425 */
426
427/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
428static
429SCIP_DECL_HEURCOPY(heurCopyRounding)
430{ /*lint --e{715}*/
431 assert(scip != NULL);
432 assert(heur != NULL);
433 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
434
435 /* call inclusion method of primal heuristic */
437
438 return SCIP_OKAY;
439}
440
441/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
442static
443SCIP_DECL_HEURFREE(heurFreeRounding) /*lint --e{715}*/
444{ /*lint --e{715}*/
445 SCIP_HEURDATA* heurdata;
446
447 assert(heur != NULL);
448 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
449 assert(scip != NULL);
450
451 /* free heuristic data */
452 heurdata = SCIPheurGetData(heur);
453 assert(heurdata != NULL);
454 SCIPfreeBlockMemory(scip, &heurdata);
455 SCIPheurSetData(heur, NULL);
456
457 return SCIP_OKAY;
458}
459
460/** initialization method of primal heuristic (called after problem was transformed) */
461static
462SCIP_DECL_HEURINIT(heurInitRounding) /*lint --e{715}*/
463{ /*lint --e{715}*/
464 SCIP_HEURDATA* heurdata;
465
466 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
467
468 heurdata = SCIPheurGetData(heur);
469 assert(heurdata != NULL);
470
471 /* create heuristic data */
472 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
473 heurdata->lastlp = -1;
474
475 return SCIP_OKAY;
476}
477
478/** deinitialization method of primal heuristic (called before transformed problem is freed) */
479static
480SCIP_DECL_HEUREXIT(heurExitRounding) /*lint --e{715}*/
481{ /*lint --e{715}*/
482 SCIP_HEURDATA* heurdata;
483
484 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
485
486 /* free heuristic data */
487 heurdata = SCIPheurGetData(heur);
488 assert(heurdata != NULL);
489 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
490
491 return SCIP_OKAY;
492}
493
494/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
495static
496SCIP_DECL_HEURINITSOL(heurInitsolRounding)
497{
498 SCIP_HEURDATA* heurdata;
499
500 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
501
502 heurdata = SCIPheurGetData(heur);
503 assert(heurdata != NULL);
504 heurdata->lastlp = -1;
505
506 /* change the heuristic's timingmask, if nit should be called only once per node */
507 if( heurdata->oncepernode )
509
510 return SCIP_OKAY;
511}
512
513/** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
514static
515SCIP_DECL_HEUREXITSOL(heurExitsolRounding)
516{
517 /* reset the timing mask to its default value */
519
520 return SCIP_OKAY;
521}
522
523
524/** execution method of primal heuristic */
525static
526SCIP_DECL_HEUREXEC(heurExecRounding) /*lint --e{715}*/
527{ /*lint --e{715}*/
528 SCIP_HEURDATA* heurdata;
529 SCIP_SOL* sol;
530 SCIP_VAR** lpcands;
531 SCIP_Real* lpcandssol;
532 SCIP_ROW** lprows;
533 SCIP_Real* activities;
534 SCIP_ROW** violrows;
535 int* violrowpos;
536 SCIP_Real obj;
537 SCIP_Real bestroundval;
538 SCIP_Real minobj;
539 int nfrac;
540 int nlpcands;
541 int nlprows;
542 int nviolrows;
543 int c;
544 int r;
545 SCIP_Longint nlps;
546 SCIP_Longint ncalls;
547 SCIP_Longint nsolsfound;
549
550 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
551 assert(scip != NULL);
552 assert(result != NULL);
553 assert(SCIPhasCurrentNodeLP(scip));
554
555 *result = SCIP_DIDNOTRUN;
556
557 /* only call heuristic, if an optimal LP solution is at hand */
559 return SCIP_OKAY;
560
561 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
563 return SCIP_OKAY;
564
565 /* get heuristic data */
566 heurdata = SCIPheurGetData(heur);
567 assert(heurdata != NULL);
568
569 /* don't call heuristic, if we have already processed the current LP solution */
570 nlps = SCIPgetNLPs(scip);
571 if( nlps == heurdata->lastlp )
572 return SCIP_OKAY;
573 heurdata->lastlp = nlps;
574
575 /* don't call heuristic, if it was not successful enough in the past */
576 ncalls = SCIPheurGetNCalls(heur);
577 nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + SCIPheurGetNSolsFound(heur);
579 if( nnodes % ((ncalls/heurdata->successfactor)/(nsolsfound+1)+1) != 0 )
580 return SCIP_OKAY;
581
582 /* get fractional variables, that should be integral */
583 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, NULL) );
584
585 /* only call heuristic, if LP solution is fractional */
586 if( nlpcands == 0 )
587 return SCIP_OKAY;
588
589 *result = SCIP_DIDNOTFIND;
590
591 /* get LP rows */
592 SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) );
593
594 SCIPdebugMsg(scip, "executing rounding heuristic: %d LP rows, %d LP candidates\n", nlprows, nlpcands);
595
596 /* get memory for activities, violated rows, and row violation positions */
597 nfrac = nlpcands;
598 SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) );
599 SCIP_CALL( SCIPallocBufferArray(scip, &violrows, nlprows) );
600 SCIP_CALL( SCIPallocBufferArray(scip, &violrowpos, nlprows) );
601
602 /* get the activities for all globally valid rows;
603 * the rows should be feasible, but due to numerical inaccuracies in the LP solver, they can be violated
604 */
605 nviolrows = 0;
606 for( r = 0; r < nlprows; ++r )
607 {
608 SCIP_ROW* row;
609
610 row = lprows[r];
611 assert(SCIProwGetLPPos(row) == r);
612
613 if( !SCIProwIsLocal(row) )
614 {
615 activities[r] = SCIPgetRowActivity(scip, row);
616 if( SCIPisFeasLT(scip, activities[r], SCIProwGetLhs(row))
617 || SCIPisFeasGT(scip, activities[r], SCIProwGetRhs(row)) )
618 {
619 violrows[nviolrows] = row;
620 violrowpos[r] = nviolrows;
621 nviolrows++;
622 }
623 else
624 violrowpos[r] = -1;
625 }
626 }
627
628 /* get the working solution from heuristic's local data */
629 sol = heurdata->sol;
630 assert(sol != NULL);
631
632 /* copy the current LP solution to the working solution */
634
635 /* calculate the minimal objective value possible after rounding fractional variables */
636 minobj = SCIPgetSolTransObj(scip, sol);
637 assert(minobj < SCIPgetCutoffbound(scip));
638 for( c = 0; c < nlpcands; ++c )
639 {
640 obj = SCIPvarGetObj(lpcands[c]);
641 bestroundval = obj > 0.0 ? SCIPfeasFloor(scip, lpcandssol[c]) : SCIPfeasCeil(scip, lpcandssol[c]);
642 minobj += obj * (bestroundval - lpcandssol[c]);
643 }
644
645 /* try to round remaining variables in order to become/stay feasible */
646 while( nfrac > 0 )
647 {
648 SCIP_VAR* roundvar;
649 SCIP_Real oldsolval;
650 SCIP_Real newsolval;
651
652 SCIPdebugMsg(scip, "rounding heuristic: nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
653 nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));
654
655 /* minobj < SCIPgetCutoffbound(scip) should be true, otherwise the rounding variable selection
656 * should have returned NULL. Due to possible cancellation we use SCIPisLE. */
657 assert( SCIPisLE(scip, minobj, SCIPgetCutoffbound(scip)) );
658
659 /* choose next variable to process:
660 * - if a violated row exists, round a variable decreasing the violation, that has least impact on other rows
661 * - otherwise, round a variable, that has strongest devastating impact on rows in opposite direction
662 */
663 if( nviolrows > 0 )
664 {
665 SCIP_ROW* row;
666 int rowpos;
667
668 row = violrows[nviolrows-1];
669 rowpos = SCIProwGetLPPos(row);
670 assert(0 <= rowpos && rowpos < nlprows);
671 assert(violrowpos[rowpos] == nviolrows-1);
672
673 SCIPdebugMsg(scip, "rounding heuristic: try to fix violated row <%s>: %g <= %g <= %g\n",
674 SCIProwGetName(row), SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row));
675 if( SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) )
676 {
677 /* lhs is violated: select a variable rounding, that increases the activity */
678 SCIP_CALL( selectIncreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) );
679 }
680 else
681 {
682 assert(SCIPisFeasGT(scip, activities[rowpos], SCIProwGetRhs(row)));
683 /* rhs is violated: select a variable rounding, that decreases the activity */
684 SCIP_CALL( selectDecreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) );
685 }
686 }
687 else
688 {
689 SCIPdebugMsg(scip, "rounding heuristic: search rounding variable and try to stay feasible\n");
690 SCIP_CALL( selectEssentialRounding(scip, sol, minobj, lpcands, nlpcands, &roundvar, &oldsolval, &newsolval) );
691 }
692
693 /* check, whether rounding was possible */
694 if( roundvar == NULL )
695 {
696 SCIPdebugMsg(scip, "rounding heuristic: -> didn't find a rounding variable\n");
697 break;
698 }
699
700 SCIPdebugMsg(scip, "rounding heuristic: -> round var <%s>, oldval=%g, newval=%g, obj=%g\n",
701 SCIPvarGetName(roundvar), oldsolval, newsolval, SCIPvarGetObj(roundvar));
702
703 /* update row activities of globally valid rows */
704 SCIP_CALL( updateActivities(scip, activities, violrows, violrowpos, &nviolrows, nlprows,
705 roundvar, oldsolval, newsolval) );
706
707 /* store new solution value and decrease fractionality counter */
708 SCIP_CALL( SCIPsetSolVal(scip, sol, roundvar, newsolval) );
709 nfrac--;
710
711 /* update minimal objective value possible after rounding remaining variables */
712 obj = SCIPvarGetObj(roundvar);
713 if( obj > 0.0 && newsolval > oldsolval )
714 minobj += obj;
715 else if( obj < 0.0 && newsolval < oldsolval )
716 minobj -= obj;
717
718 SCIPdebugMsg(scip, "rounding heuristic: -> nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
719 nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));
720 }
721
722 /* check, if the new solution is feasible */
723 if( nfrac == 0 && nviolrows == 0 )
724 {
725 SCIP_Bool stored;
726
727 /* check solution for feasibility, and add it to solution store if possible
728 * neither integrality nor feasibility of LP rows has to be checked, because this is already
729 * done in the rounding heuristic itself; however, be better check feasibility of LP rows,
730 * because of numerical problems with activity updating
731 */
732 SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, FALSE, TRUE, &stored) );
733
734 if( stored )
735 {
736#ifdef SCIP_DEBUG
737 SCIPdebugMsg(scip, "found feasible rounded solution:\n");
739#endif
740 *result = SCIP_FOUNDSOL;
741 }
742 }
743
744 /* free memory buffers */
745 SCIPfreeBufferArray(scip, &violrowpos);
746 SCIPfreeBufferArray(scip, &violrows);
747 SCIPfreeBufferArray(scip, &activities);
748
749 return SCIP_OKAY;
750}
751
752
753/*
754 * heuristic specific interface methods
755 */
756
757/** creates the rounding heuristic with infeasibility recovering and includes it in SCIP */
759 SCIP* scip /**< SCIP data structure */
760 )
761{
762 SCIP_HEURDATA* heurdata;
763 SCIP_HEUR* heur;
764
765 /* create Rounding primal heuristic data */
766 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
767
768 /* include primal heuristic */
771 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecRounding, heurdata) );
772
773 assert(heur != NULL);
774
775 /* primal heuristic is safe to use in exact solving mode */
776 SCIPheurMarkExact(heur);
777
778 /* set non-NULL pointers to callback methods */
779 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyRounding) );
780 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeRounding) );
781 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitRounding) );
782 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitRounding) );
783 SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolRounding) );
784 SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolRounding) );
785
786 /* add rounding primal heuristic parameters */
787 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/successfactor",
788 "number of calls per found solution that are considered as standard success, a higher factor causes the heuristic to be called more often",
789 &heurdata->successfactor, TRUE, DEFAULT_SUCCESSFACTOR, -1, INT_MAX, NULL, NULL) );
790
791 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/oncepernode",
792 "should the heuristic only be called once per node?",
793 &heurdata->oncepernode, TRUE, DEFAULT_ONCEPERNODE, NULL, NULL) );
794
795 return SCIP_OKAY;
796}
SCIP_Real * r
Definition: circlepacking.c:59
#define NULL
Definition: def.h:248
#define SCIP_Longint
Definition: def.h:141
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define SCIP_CALL(x)
Definition: def.h:355
#define nnodes
Definition: gastrans.c:74
#define SCIPdebugMsg
Definition: scip_message.h:78
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 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 SCIPincludeHeurRounding(SCIP *scip)
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:402
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17425
SCIP_Real * SCIPcolGetVals(SCIP_COL *col)
Definition: lp.c:17555
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:17545
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition: lp.c:17534
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_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
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_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition: scip_lp.c:87
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:576
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:253
#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
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17686
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17632
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17696
int SCIProwGetNLPNonz(SCIP_ROW *row)
Definition: lp.c:17621
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17895
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17795
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17745
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2068
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17917
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17642
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 SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:2349
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_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 SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:2005
SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
Definition: scip_sol.c:2132
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_Longint SCIPgetNLPs(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
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_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:23683
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4386
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4328
static SCIP_RETCODE selectEssentialRounding(SCIP *scip, SCIP_SOL *sol, SCIP_Real minobj, SCIP_VAR **lpcands, int nlpcands, SCIP_VAR **roundvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
#define DEFAULT_SUCCESSFACTOR
Definition: heur_rounding.c:60
static SCIP_DECL_HEURCOPY(heurCopyRounding)
#define HEUR_TIMING
Definition: heur_rounding.c:57
static SCIP_RETCODE updateActivities(SCIP *scip, SCIP_Real *activities, SCIP_ROW **violrows, int *violrowpos, int *nviolrows, int nlprows, SCIP_VAR *var, SCIP_Real oldsolval, SCIP_Real newsolval)
static void updateViolations(SCIP *scip, SCIP_ROW *row, SCIP_ROW **violrows, int *violrowpos, int *nviolrows, SCIP_Real oldactivity, SCIP_Real newactivity)
Definition: heur_rounding.c:83
#define HEUR_FREQOFS
Definition: heur_rounding.c:55
#define HEUR_DESC
Definition: heur_rounding.c:51
#define DEFAULT_ONCEPERNODE
Definition: heur_rounding.c:63
#define HEUR_DISPCHAR
Definition: heur_rounding.c:52
#define HEUR_MAXDEPTH
Definition: heur_rounding.c:56
#define HEUR_PRIORITY
Definition: heur_rounding.c:53
static SCIP_RETCODE selectIncreaseRounding(SCIP *scip, SCIP_SOL *sol, SCIP_Real minobj, SCIP_ROW *row, SCIP_VAR **roundvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
#define HEUR_NAME
Definition: heur_rounding.c:50
static SCIP_DECL_HEUREXEC(heurExecRounding)
static SCIP_DECL_HEUREXIT(heurExitRounding)
static SCIP_RETCODE selectDecreaseRounding(SCIP *scip, SCIP_SOL *sol, SCIP_Real minobj, SCIP_ROW *row, SCIP_VAR **roundvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
static SCIP_DECL_HEUREXITSOL(heurExitsolRounding)
static SCIP_DECL_HEURINITSOL(heurInitsolRounding)
static SCIP_DECL_HEURFREE(heurFreeRounding)
static SCIP_RETCODE selectRounding(SCIP *scip, SCIP_SOL *sol, SCIP_Real minobj, SCIP_ROW *row, int direction, SCIP_VAR **roundvar, SCIP_Real *oldsolval, SCIP_Real *newsolval)
static SCIP_DECL_HEURINIT(heurInitRounding)
#define HEUR_FREQ
Definition: heur_rounding.c:54
#define HEUR_USESSUBSCIP
Definition: heur_rounding.c:58
LP rounding heuristic that tries to recover from intermediate infeasibilities.
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
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 solutions
public methods for querying solving statistics
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:77
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ 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
#define SCIP_HEURTIMING_AFTERLPNODE
Definition: type_timing.h:83
@ SCIP_VARTYPE_CONTINUOUS
Definition: type_var.h:71
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:141