Scippy

SCIP

Solving Constraint Integer Programs

heur_zirounding.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_zirounding.c
26 * @ingroup DEFPLUGINS_HEUR
27 * @brief zirounding primal heuristic
28 * @author Gregor Hendel
29 */
30
31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32
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 "zirounding"
51#define HEUR_DESC "LP rounding heuristic as suggested by C. Wallace taking row slacks and bounds into account"
52#define HEUR_DISPCHAR SCIP_HEURDISPCHAR_ROUNDING
53#define HEUR_PRIORITY -500
54#define HEUR_FREQ 1
55#define HEUR_FREQOFS 0
56#define HEUR_MAXDEPTH -1
57#define HEUR_TIMING SCIP_HEURTIMING_AFTERLPNODE
58#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
59
60#define DEFAULT_MAXROUNDINGLOOPS 2 /**< delimits the number of main loops, can be set to -1 for no limit */
61#define DEFAULT_STOPZIROUND TRUE /**< deactivation check is enabled by default */
62#define DEFAULT_STOPPERCENTAGE 0.02 /**< the tolerance percentage after which zirounding will not be executed anymore */
63#define DEFAULT_MINSTOPNCALLS 1000 /**< number of heuristic calls before deactivation check */
64
65#define MINSHIFT 1e-4 /**< minimum shift value for every single step */
66
67/*
68 * Data structures
69 */
70
71/** primal heuristic data */
72struct SCIP_HeurData
73{
74 SCIP_SOL* sol; /**< working solution */
75 SCIP_Longint lastlp; /**< the number of the last LP for which ZIRounding was called */
76 int maxroundingloops; /**< limits rounding loops in execution */
77 SCIP_Bool stopziround; /**< sets deactivation check */
78 SCIP_Real stoppercentage; /**< threshold for deactivation check */
79 int minstopncalls; /**< number of heuristic calls before deactivation check */
80};
81
83{
86};
87typedef enum Direction DIRECTION;
88
89/*
90 * Local methods
91 */
92
93/** returns the fractionality of a value x, which is calculated as zivalue(x) = min(x-floor(x), ceil(x)-x) */
94static
96 SCIP* scip, /**< pointer to current SCIP data structure */
97 SCIP_Real val /**< the value for which the fractionality should be computed */
98 )
99{
100 SCIP_Real upgap; /* the gap between val and ceil(val) */
101 SCIP_Real downgap; /* the gap between val and floor(val) */
102
103 assert(scip != NULL);
104
105 upgap = SCIPfeasCeil(scip, val) - val;
106 downgap = val - SCIPfeasFloor(scip, val);
107
108 return MIN(upgap, downgap);
109}
110
111/** determines shifting bounds for variable */
112static
114 SCIP* scip, /**< pointer to current SCIP data structure */
115 SCIP_VAR* var, /**< the variable for which lb and ub have to be calculated */
116 SCIP_Real currentvalue, /**< the current value of var in the working solution */
117 SCIP_Real* upperbound, /**< pointer to store the calculated upper bound on the variable shift */
118 SCIP_Real* lowerbound, /**< pointer to store the calculated lower bound on the variable shift */
119 SCIP_Real* upslacks, /**< array that contains the slacks between row activities and the right hand sides of the rows */
120 SCIP_Real* downslacks, /**< array that contains lhs slacks */
121 int nslacks, /**< current number of slacks */
122 SCIP_Bool* numericalerror /**< flag to determine whether a numerical error occurred */
123 )
124{
125 SCIP_COL* col;
126 SCIP_ROW** colrows;
127 SCIP_Real* colvals;
128 int ncolvals;
129 int i;
130
131 assert(scip != NULL);
132 assert(var != NULL);
133 assert(upslacks != NULL);
134 assert(downslacks != NULL);
135 assert(upperbound != NULL);
136 assert(lowerbound != NULL);
137
138 /* get the column associated to the variable, the nonzero rows and the nonzero coefficients */
139 col = SCIPvarGetCol(var);
140 colrows = SCIPcolGetRows(col);
141 colvals = SCIPcolGetVals(col);
142 ncolvals = SCIPcolGetNLPNonz(col);
143
144 /* only proceed, when variable has nonzero coefficients */
145 if( ncolvals == 0 )
146 return;
147
148 assert(colvals != NULL);
149 assert(colrows != NULL);
150
151 /* initialize the bounds on the shift to be the gap of the current solution value to the bounds of the variable */
153 *upperbound = SCIPinfinity(scip);
154 else
155 *upperbound = SCIPvarGetUbGlobal(var) - currentvalue;
156
158 *lowerbound = SCIPinfinity(scip);
159 else
160 *lowerbound = currentvalue - SCIPvarGetLbGlobal(var);
161
162 /* go through every nonzero row coefficient corresponding to var to determine bounds for shifting
163 * in such a way that shifting maintains feasibility in every LP row.
164 * a lower or upper bound as it is calculated in zirounding always has to be >= 0.0.
165 * if one of these values is significantly < 0.0, this will cause the abort of execution of the heuristic so that
166 * infeasible solutions are avoided
167 */
168 for( i = 0; i < ncolvals && MAX(*lowerbound, *upperbound) >= MINSHIFT; ++i )
169 {
170 SCIP_ROW* row;
171 int rowpos;
172
173 row = colrows[i];
174 rowpos = SCIProwGetLPPos(row);
175
176 /* the row might currently not be in the LP, ignore it! */
177 if( rowpos == -1 )
178 continue;
179
180 assert(0 <= rowpos && rowpos < nslacks);
181
182 /* all bounds and slacks as they are calculated in zirounding always have to be greater equal zero.
183 * It might however be due to numerical issues, e.g. with scaling, that they are not. Better abort in this case.
184 */
185 if( SCIPisFeasLT(scip, *lowerbound, 0.0) || SCIPisFeasLT(scip, *upperbound, 0.0)
186 || SCIPisFeasLT(scip, upslacks[rowpos], 0.0) || SCIPisFeasLT(scip, downslacks[rowpos] , 0.0) )
187 {
188 *numericalerror = TRUE;
189 return;
190 }
191
192 SCIPdebugMsg(scip, "colval: %15.8g, downslack: %15.8g, upslack: %5.2g, lb: %5.2g, ub: %5.2g\n", colvals[i], downslacks[rowpos], upslacks[rowpos],
193 *lowerbound, *upperbound);
194
195 /* if coefficient > 0, rounding up might violate up slack and rounding down might violate down slack
196 * thus search for the minimum so that no constraint is violated; vice versa for coefficient < 0
197 */
198 if( colvals[i] > 0 )
199 {
200 if( !SCIPisInfinity(scip, upslacks[rowpos]) )
201 {
202 SCIP_Real upslack;
203 upslack = MAX(upslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
204 *upperbound = MIN(*upperbound, upslack/colvals[i]);
205 }
206
207 if( !SCIPisInfinity(scip, downslacks[rowpos]) )
208 {
209 SCIP_Real downslack;
210 downslack = MAX(downslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
211 *lowerbound = MIN(*lowerbound, downslack/colvals[i]);
212 }
213 }
214 else
215 {
216 assert(colvals[i] != 0.0);
217
218 if( !SCIPisInfinity(scip, upslacks[rowpos]) )
219 {
220 SCIP_Real upslack;
221 upslack = MAX(upslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
222 *lowerbound = MIN(*lowerbound, -upslack/colvals[i]);
223 }
224
225 if( !SCIPisInfinity(scip, downslacks[rowpos]) )
226 {
227 SCIP_Real downslack;
228 downslack = MAX(downslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */
229 *upperbound = MIN(*upperbound, -downslack/colvals[i]);
230 }
231 }
232 }
233}
234
235/** when a variable is shifted, the activities and slacks of all rows it appears in have to be updated */
236static
238 SCIP* scip, /**< pointer to current SCIP data structure */
239 SCIP_SOL* sol, /**< working solution */
240 SCIP_VAR* var, /**< pointer to variable to be modified */
241 SCIP_Real shiftvalue, /**< the value by which the variable is shifted */
242 SCIP_Real* upslacks, /**< upslacks of all rows the variable appears in */
243 SCIP_Real* downslacks, /**< downslacks of all rows the variable appears in */
244 SCIP_Real* activities, /**< activities of the LP rows */
245 SCIP_VAR** slackvars, /**< the slack variables for equality rows */
246 SCIP_Real* slackcoeffs, /**< the slack variable coefficients */
247 int nslacks /**< size of the arrays */
248 )
249{
250 SCIP_COL* col; /* the corresponding column of variable var */
251 SCIP_ROW** rows; /* pointer to the nonzero coefficient rows for variable var */
252 int nrows; /* the number of nonzeros */
253 SCIP_Real* colvals; /* array to store the nonzero coefficients */
254 int i;
255
256 assert(scip != NULL);
257 assert(sol != NULL);
258 assert(var != NULL);
259 assert(upslacks != NULL);
260 assert(downslacks != NULL);
261 assert(activities != NULL);
262 assert(nslacks >= 0);
263
264 col = SCIPvarGetCol(var);
265 assert(col != NULL);
266
267 rows = SCIPcolGetRows(col);
268 nrows = SCIPcolGetNLPNonz(col);
269 colvals = SCIPcolGetVals(col);
270 assert(nrows == 0 || (rows != NULL && colvals != NULL));
271
272 /* go through all rows the shifted variable appears in */
273 for( i = 0; i < nrows; ++i )
274 {
275 int rowpos;
276
277 rowpos = SCIProwGetLPPos(rows[i]);
278 assert(-1 <= rowpos && rowpos < nslacks);
279
280 /* if the row is in the LP, update its activity, up and down slack */
281 if( rowpos >= 0 )
282 {
283 SCIP_Real val;
284 SCIP_Real lhs;
285 SCIP_Real rhs;
286 SCIP_ROW* row;
287
288 val = colvals[i] * shiftvalue;
289 row = rows[i];
290 lhs = SCIProwGetLhs(row);
291 rhs = SCIProwGetRhs(row);
292
293 /* if the row is an equation, we update its slack variable instead of its activities */
294 if( SCIPisFeasEQ(scip, lhs, rhs) )
295 {
296 SCIP_Real slackvarshiftval;
297 SCIP_Real slackvarsolval;
298
299 assert(slackvars[rowpos] != NULL);
300 assert(!SCIPisZero(scip, slackcoeffs[rowpos]));
301
302 slackvarsolval = SCIPgetSolVal(scip, sol, slackvars[rowpos]);
303 slackvarshiftval = -val / slackcoeffs[rowpos];
304
305 assert(SCIPisFeasGE(scip, slackvarsolval + slackvarshiftval, SCIPvarGetLbGlobal(slackvars[rowpos])));
306 assert(SCIPisFeasLE(scip, slackvarsolval + slackvarshiftval, SCIPvarGetUbGlobal(slackvars[rowpos])));
307
308 SCIP_CALL( SCIPsetSolVal(scip, sol, slackvars[rowpos], slackvarsolval + slackvarshiftval) );
309 }
310 else if( !SCIPisInfinity(scip, REALABS(activities[rowpos])) )
311 activities[rowpos] += val;
312
313 /* the slacks of the row now can be updated independently of its type */
314 if( !SCIPisInfinity(scip, upslacks[rowpos]) )
315 upslacks[rowpos] -= val;
316 if( !SCIPisInfinity(scip, -downslacks[rowpos]) )
317 downslacks[rowpos] += val;
318
319 assert(SCIPisInfinity(scip, -lhs) || SCIPisFeasGE(scip, activities[rowpos], lhs));
320 assert(SCIPisInfinity(scip, rhs) || SCIPisFeasLE(scip, activities[rowpos], rhs));
321 }
322 }
323 return SCIP_OKAY;
324}
325
326/** finds a continuous slack variable for an equation row, NULL if none exists */
327static
329 SCIP* scip, /**< pointer to current SCIP data structure */
330 SCIP_ROW* row, /**< the row for which a slack variable is searched */
331 SCIP_VAR** varpointer, /**< pointer to store the slack variable */
332 SCIP_Real* coeffpointer /**< pointer to store the coefficient of the slack variable */
333 )
334{
335 int v;
336 SCIP_COL** rowcols;
337 SCIP_Real* rowvals;
338 int nrowvals;
339
340 assert(row != NULL);
341 assert(varpointer != NULL);
342 assert(coeffpointer != NULL);
343
344 rowcols = SCIProwGetCols(row);
345 rowvals = SCIProwGetVals(row);
346 nrowvals = SCIProwGetNNonz(row);
347
348 assert(nrowvals == 0 || rowvals != NULL);
349 assert(nrowvals == 0 || rowcols != NULL);
350
351 /* iterate over the row variables. Stop after the first unfixed continuous variable was found. */
352 for( v = nrowvals - 1; v >= 0; --v )
353 {
354 SCIP_VAR* colvar;
355
356 assert(rowcols[v] != NULL);
357 if( SCIPcolGetLPPos(rowcols[v]) == -1 )
358 continue;
359
360 colvar = SCIPcolGetVar(rowcols[v]);
361
362 if( !SCIPvarIsIntegral(colvar)
364 && SCIPcolGetNLPNonz(rowcols[v]) == 1 )
365 {
366 SCIPdebugMsg(scip, " slack variable for row %s found: %s\n", SCIProwGetName(row), SCIPvarGetName(colvar));
367
368 *coeffpointer = rowvals[v];
369 *varpointer = colvar;
370
371 return;
372 }
373 }
374
375 *varpointer = NULL;
376 *coeffpointer = 0.0;
377
378 SCIPdebugMsg(scip, "No slack variable for row %s found. \n", SCIProwGetName(row));
379}
380
381/*
382 * Callback methods of primal heuristic
383 */
384
385/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
386static
387SCIP_DECL_HEURCOPY(heurCopyZirounding)
388{ /*lint --e{715}*/
389 assert(scip != NULL);
390 assert(heur != NULL);
391 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
392
393 /* call inclusion method of primal heuristic */
395
396 return SCIP_OKAY;
397}
398
399/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
400static
401SCIP_DECL_HEURFREE(heurFreeZirounding)
402{ /*lint --e{715}*/
403 SCIP_HEURDATA* heurdata;
404
405 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
406
407 heurdata = SCIPheurGetData(heur);
408 assert(heurdata != NULL);
409
410 /* free heuristic data */
411 SCIPfreeBlockMemory(scip, &heurdata);
412 SCIPheurSetData(heur, NULL);
413
414 return SCIP_OKAY;
415}
416
417/** initialization method of primal heuristic (called after problem was transformed) */
418static
419SCIP_DECL_HEURINIT(heurInitZirounding)
420{ /*lint --e{715}*/
421 SCIP_HEURDATA* heurdata;
422
423 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
424
425 heurdata = SCIPheurGetData(heur);
426 assert(heurdata != NULL);
427
428 /* create working solution */
429 SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
430
431 return SCIP_OKAY;
432}
433
434/** deinitialization method of primal heuristic (called before transformed problem is freed) */
435static
436SCIP_DECL_HEUREXIT(heurExitZirounding) /*lint --e{715}*/
437{ /*lint --e{715}*/
438 SCIP_HEURDATA* heurdata;
439
440 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
441
442 heurdata = SCIPheurGetData(heur);
443 assert(heurdata != NULL);
444
445 /* free working solution */
446 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
447
448 return SCIP_OKAY;
449}
450
451/** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
452static
453SCIP_DECL_HEURINITSOL(heurInitsolZirounding)
454{ /*lint --e{715}*/
455 SCIP_HEURDATA* heurdata;
456
457 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
458
459 heurdata = SCIPheurGetData(heur);
460 assert(heurdata != NULL);
461
462 heurdata->lastlp = -1;
463
464 return SCIP_OKAY;
465}
466
467
468/** execution method of primal heuristic */
469static
470SCIP_DECL_HEUREXEC(heurExecZirounding)
471{ /*lint --e{715}*/
472 SCIP_HEURDATA* heurdata;
473 SCIP_SOL* sol;
474 SCIP_VAR** lpcands;
475 SCIP_VAR** zilpcands;
476
477 SCIP_VAR** slackvars;
478 SCIP_Real* upslacks;
479 SCIP_Real* downslacks;
480 SCIP_Real* activities;
481 SCIP_Real* slackvarcoeffs;
482 SCIP_Bool* rowneedsslackvar;
483
484 SCIP_ROW** rows;
485 SCIP_Real* lpcandssol;
486 SCIP_Real* solarray;
487
488 SCIP_Longint nlps;
489 int currentlpcands;
490 int nlpcands;
491 int nimplfracs;
492 int i;
493 int c;
494 int nslacks;
495 int nroundings;
496
497 SCIP_Bool improvementfound;
498 SCIP_Bool numericalerror;
499
500 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
501 assert(result != NULL);
502 assert(SCIPhasCurrentNodeLP(scip));
503
504 *result = SCIP_DIDNOTRUN;
505
506 /* do not call heuristic of node was already detected to be infeasible */
507 if( nodeinfeasible )
508 return SCIP_OKAY;
509
510 /* only call heuristic if an optimal LP-solution is at hand */
512 return SCIP_OKAY;
513
514 /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
516 return SCIP_OKAY;
517
518 /* get heuristic data */
519 heurdata = SCIPheurGetData(heur);
520 assert(heurdata != NULL);
521
522 /* Do not call heuristic if deactivation check is enabled and percentage of found solutions in relation
523 * to number of calls falls below heurdata->stoppercentage */
524 if( heurdata->stopziround && SCIPheurGetNCalls(heur) >= heurdata->minstopncalls
525 && SCIPheurGetNSolsFound(heur)/(SCIP_Real)SCIPheurGetNCalls(heur) < heurdata->stoppercentage )
526 return SCIP_OKAY;
527
528 /* assure that heuristic has not already been called after the last LP had been solved */
529 nlps = SCIPgetNLPs(scip);
530 if( nlps == heurdata->lastlp )
531 return SCIP_OKAY;
532
533 heurdata->lastlp = nlps;
534
535 /* @todo: check whether rounding continuous implied integral variables is necessary */
536 /* get fractional variables */
537 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, &nimplfracs) );
538 nlpcands = nlpcands + nimplfracs;
539
540 /* make sure that there is at least one fractional variable that should be integral */
541 if( nlpcands == 0 )
542 return SCIP_OKAY;
543
544 assert(nlpcands > 0);
545 assert(lpcands != NULL);
546 assert(lpcandssol != NULL);
547
548 /* get LP rows data */
549 rows = SCIPgetLPRows(scip);
550 nslacks = SCIPgetNLPRows(scip);
551
552 /* cannot do anything if LP is empty */
553 if( nslacks == 0 )
554 return SCIP_OKAY;
555
556 assert(rows != NULL);
557 assert(nslacks > 0);
558
559 /* get the working solution from heuristic's local data */
560 sol = heurdata->sol;
561 assert(sol != NULL);
562
563 *result = SCIP_DIDNOTFIND;
564
565 solarray = NULL;
566 zilpcands = NULL;
567
568 /* copy the current LP solution to the working solution and allocate memory for local data */
570 SCIP_CALL( SCIPallocBufferArray(scip, &solarray, nlpcands) );
571 SCIP_CALL( SCIPallocBufferArray(scip, &zilpcands, nlpcands) );
572
573 /* copy necessary data to local arrays */
574 BMScopyMemoryArray(solarray, lpcandssol, nlpcands);
575 BMScopyMemoryArray(zilpcands, lpcands, nlpcands);
576
577 /* allocate buffer data arrays */
578 SCIP_CALL( SCIPallocBufferArray(scip, &slackvars, nslacks) );
579 SCIP_CALL( SCIPallocBufferArray(scip, &upslacks, nslacks) );
580 SCIP_CALL( SCIPallocBufferArray(scip, &downslacks, nslacks) );
581 SCIP_CALL( SCIPallocBufferArray(scip, &slackvarcoeffs, nslacks) );
582 SCIP_CALL( SCIPallocBufferArray(scip, &rowneedsslackvar, nslacks) );
583 SCIP_CALL( SCIPallocBufferArray(scip, &activities, nslacks) );
584
585 BMSclearMemoryArray(slackvars, nslacks);
586 BMSclearMemoryArray(slackvarcoeffs, nslacks);
587 BMSclearMemoryArray(rowneedsslackvar, nslacks);
588
589 numericalerror = FALSE;
590 nroundings = 0;
591
592 /* loop over fractional variables and involved LP rows to find all rows which require a slack variable */
593 for( c = 0; c < nlpcands; ++c )
594 {
595 SCIP_VAR* cand;
596 SCIP_ROW** candrows;
597 int r;
598 int ncandrows;
599
600 cand = zilpcands[c];
601 assert(cand != NULL);
602 assert(SCIPcolGetLPPos(SCIPvarGetCol(cand)) >= 0);
603
604 candrows = SCIPcolGetRows(SCIPvarGetCol(cand));
605 ncandrows = SCIPcolGetNLPNonz(SCIPvarGetCol(cand));
606
607 assert(candrows == NULL || ncandrows > 0);
608
609 for( r = 0; r < ncandrows; ++r )
610 {
611 int rowpos;
612
613 assert(candrows != NULL); /* to please flexelint */
614 assert(candrows[r] != NULL);
615 rowpos = SCIProwGetLPPos(candrows[r]);
616
617 if( rowpos >= 0 && SCIPisFeasEQ(scip, SCIProwGetLhs(candrows[r]), SCIProwGetRhs(candrows[r])) )
618 {
619 rowneedsslackvar[rowpos] = TRUE;
620 SCIPdebugMsg(scip, " Row %s needs slack variable for variable %s\n", SCIProwGetName(candrows[r]), SCIPvarGetName(cand));
621 }
622 }
623 }
624
625 /* calculate row slacks for every every row that belongs to the current LP and ensure, that the current solution
626 * has no violated constraint -- if any constraint is violated, i.e. a slack is significantly smaller than zero,
627 * this will cause the termination of the heuristic because Zirounding does not provide feasibility recovering
628 */
629 for( i = 0; i < nslacks; ++i )
630 {
631 SCIP_ROW* row;
632 SCIP_Real lhs;
633 SCIP_Real rhs;
634
635 row = rows[i];
636
637 assert(row != NULL);
638
639 lhs = SCIProwGetLhs(row);
640 rhs = SCIProwGetRhs(row);
641
642 /* get row activity */
643 activities[i] = SCIPgetRowActivity(scip, row);
644 assert(SCIPisFeasLE(scip, lhs, activities[i]) && SCIPisFeasLE(scip, activities[i], rhs));
645
646 /* in special case if LHS or RHS is (-)infinity slacks have to be initialized as infinity */
647 if( SCIPisInfinity(scip, -lhs) )
648 downslacks[i] = SCIPinfinity(scip);
649 else
650 downslacks[i] = activities[i] - lhs;
651
652 if( SCIPisInfinity(scip, rhs) )
653 upslacks[i] = SCIPinfinity(scip);
654 else
655 upslacks[i] = rhs - activities[i];
656
657 SCIPdebugMsg(scip, "lhs:%5.2f <= act:%5.2g <= rhs:%5.2g --> down: %5.2g, up:%5.2g\n", lhs, activities[i], rhs, downslacks[i], upslacks[i]);
658
659 /* row is an equation. Try to find a slack variable in the row, i.e.,
660 * a continuous variable which occurs only in this row. If no such variable exists,
661 * there is no hope for an IP-feasible solution in this round
662 */
663 if( SCIPisFeasEQ(scip, lhs, rhs) && rowneedsslackvar[i] )
664 {
665 /* @todo: This is only necessary for rows containing fractional variables. */
666 rowFindSlackVar(scip, row, &(slackvars[i]), &(slackvarcoeffs[i]));
667
668 if( slackvars[i] == NULL )
669 {
670 SCIPdebugMsg(scip, "No slack variable found for equation %s, terminating ZI Round heuristic\n", SCIProwGetName(row));
671 goto TERMINATE;
672 }
673 else
674 {
675 SCIP_Real ubslackvar;
676 SCIP_Real lbslackvar;
677 SCIP_Real solvalslackvar;
678 SCIP_Real coeffslackvar;
679 SCIP_Real ubgap;
680 SCIP_Real lbgap;
681
682 assert(!SCIPvarIsIntegral(slackvars[i]));
683 solvalslackvar = SCIPgetSolVal(scip, sol, slackvars[i]);
684 ubslackvar = SCIPvarGetUbGlobal(slackvars[i]);
685 lbslackvar = SCIPvarGetLbGlobal(slackvars[i]);
686
687 coeffslackvar = slackvarcoeffs[i];
688 assert(!SCIPisZero(scip, coeffslackvar));
689
690 ubgap = MAX(0.0, ubslackvar - solvalslackvar);
691 lbgap = MAX(0.0, solvalslackvar - lbslackvar);
692
693 if( SCIPisPositive(scip, coeffslackvar) )
694 {
695 if( !SCIPisInfinity(scip, lbslackvar) )
696 upslacks[i] += coeffslackvar * lbgap;
697 else
698 upslacks[i] = SCIPinfinity(scip);
699 if( !SCIPisInfinity(scip, ubslackvar) )
700 downslacks[i] += coeffslackvar * ubgap;
701 else
702 downslacks[i] = SCIPinfinity(scip);
703 }
704 else
705 {
706 if( !SCIPisInfinity(scip, ubslackvar) )
707 upslacks[i] -= coeffslackvar * ubgap;
708 else
709 upslacks[i] = SCIPinfinity(scip);
710 if( !SCIPisInfinity(scip, lbslackvar) )
711 downslacks[i] -= coeffslackvar * lbgap;
712 else
713 downslacks[i] = SCIPinfinity(scip);
714 }
715 SCIPdebugMsg(scip, " Slack variable for row %s at pos %d: %g <= %s = %g <= %g; Coeff %g, upslack = %g, downslack = %g \n",
716 SCIProwGetName(row), SCIProwGetLPPos(row), lbslackvar, SCIPvarGetName(slackvars[i]), solvalslackvar, ubslackvar, coeffslackvar,
717 upslacks[i], downslacks[i]);
718 }
719 }
720 /* due to numerical inaccuracies, the rows might be feasible, even if the slacks are
721 * significantly smaller than zero -> terminate
722 */
723 if( SCIPisFeasLT(scip, upslacks[i], 0.0) || SCIPisFeasLT(scip, downslacks[i], 0.0) )
724 goto TERMINATE;
725 }
726
727 assert(nslacks == 0 || (upslacks != NULL && downslacks != NULL && activities != NULL));
728
729 /* initialize number of remaining variables and flag to enter the main loop */
730 currentlpcands = nlpcands;
731 improvementfound = TRUE;
732
733 /* iterate over variables as long as there are fractional variables left */
734 while( currentlpcands > 0 && improvementfound && (heurdata->maxroundingloops == -1 || nroundings < heurdata->maxroundingloops) )
735 { /*lint --e{850}*/
736 improvementfound = FALSE;
737 nroundings++;
738 SCIPdebugMsg(scip, "zirounding enters while loop for %d time with %d candidates left. \n", nroundings, currentlpcands);
739
740 /* check for every remaining fractional variable if a shifting decreases ZI-value of the variable */
741 for( c = 0; c < currentlpcands; ++c )
742 {
743 SCIP_VAR* var;
744 SCIP_Real oldsolval;
745 SCIP_Real upperbound;
746 SCIP_Real lowerbound;
747 SCIP_Real up;
748 SCIP_Real down;
749 SCIP_Real ziup;
750 SCIP_Real zidown;
751 SCIP_Real zicurrent;
752 SCIP_Real shiftval;
753
754 DIRECTION direction;
755
756 /* get values from local data */
757 oldsolval = solarray[c];
758 var = zilpcands[c];
759
760 assert(!SCIPisFeasIntegral(scip, oldsolval));
762
763 /* calculate bounds for variable and make sure that there are no numerical inconsistencies */
764 upperbound = SCIPinfinity(scip);
765 lowerbound = SCIPinfinity(scip);
766 calculateBounds(scip, var, oldsolval, &upperbound, &lowerbound, upslacks, downslacks, nslacks, &numericalerror);
767
768 if( numericalerror )
769 goto TERMINATE;
770
771 /* continue if only marginal shifts are possible */
772 if( MAX(upperbound, lowerbound) < MINSHIFT )
773 {
774 /* stop immediately if a variable has not been rounded during the last round */
775 if( nroundings == heurdata->maxroundingloops )
776 break;
777 else
778 continue;
779 }
780
781 /* calculate the possible values after shifting */
782 up = oldsolval + upperbound;
783 down = oldsolval - lowerbound;
784
785 /* if the variable is integer or implied integral, do not shift further than the nearest integer */
787 {
788 SCIP_Real ceilx;
789 SCIP_Real floorx;
790
791 ceilx = SCIPfeasCeil(scip, oldsolval);
792 floorx = SCIPfeasFloor(scip, oldsolval);
793 up = MIN(up, ceilx);
794 down = MAX(down, floorx);
795 }
796
797 /* calculate necessary values */
798 ziup = getZiValue(scip, up);
799 zidown = getZiValue(scip, down);
800 zicurrent = getZiValue(scip, oldsolval);
801
802 /* calculate the shifting direction that reduces ZI-value the most,
803 * if both directions improve ZI-value equally, take the direction which improves the objective
804 */
805 if( SCIPisFeasLT(scip, zidown, zicurrent) || SCIPisFeasLT(scip, ziup, zicurrent) )
806 {
807 if( SCIPisFeasEQ(scip,ziup, zidown) )
808 direction = SCIPisFeasGE(scip, SCIPvarGetObj(var), 0.0) ? DIRECTION_DOWN : DIRECTION_UP;
809 else if( SCIPisFeasLT(scip, zidown, ziup) )
810 direction = DIRECTION_DOWN;
811 else
812 direction = DIRECTION_UP;
813
814 /* once a possible shifting direction and value have been found, variable value is updated */
815 shiftval = (direction == DIRECTION_UP ? up - oldsolval : down - oldsolval);
816
817 /* this improves numerical stability in some cases */
818 if( direction == DIRECTION_UP )
819 shiftval = MIN(shiftval, upperbound);
820 else
821 shiftval = MIN(shiftval, lowerbound);
822 /* update the solution */
823 solarray[c] = direction == DIRECTION_UP ? up : down;
824 SCIP_CALL( SCIPsetSolVal(scip, sol, var, solarray[c]) );
825
826 /* update the rows activities and slacks */
827 SCIP_CALL( updateSlacks(scip, sol, var, shiftval, upslacks,
828 downslacks, activities, slackvars, slackvarcoeffs, nslacks) );
829
830 SCIPdebugMsg(scip, "zirounding update step : %d var index, oldsolval=%g, shiftval=%g\n",
831 SCIPvarGetIndex(var), oldsolval, shiftval);
832 /* since at least one improvement has been found, heuristic will enter main loop for another time because the improvement
833 * might affect many LP rows and their current slacks and thus make further rounding steps possible */
834 improvementfound = TRUE;
835 }
836
837 /* if solution value of variable has become feasibly integral due to rounding step,
838 * variable is put at the end of remaining candidates array so as not to be considered in future loops
839 */
840 if( SCIPisFeasIntegral(scip, solarray[c]) )
841 {
842 zilpcands[c] = zilpcands[currentlpcands - 1];
843 solarray[c] = solarray[currentlpcands - 1];
844 currentlpcands--;
845
846 /* counter is decreased if end of candidates array has not been reached yet */
847 if( c < currentlpcands )
848 c--;
849 }
850 else if( nroundings == heurdata->maxroundingloops )
851 goto TERMINATE;
852 }
853 }
854
855 /* in case that no candidate is left for rounding after the final main loop
856 * the found solution has to be checked for feasibility in the original problem
857 */
858 if( currentlpcands == 0 )
859 {
860 SCIP_Bool stored;
861 SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, FALSE, &stored) );
862 if( stored )
863 {
864#ifdef SCIP_DEBUG
865 SCIPdebugMsg(scip, "found feasible rounded solution:\n");
867#endif
868 SCIPstatisticMessage(" ZI Round solution value: %g \n", SCIPgetSolOrigObj(scip, sol));
869
870 *result = SCIP_FOUNDSOL;
871 }
872 }
873
874 /* free memory for all locally allocated data */
875 TERMINATE:
876 SCIPfreeBufferArrayNull(scip, &activities);
877 SCIPfreeBufferArrayNull(scip, &rowneedsslackvar);
878 SCIPfreeBufferArrayNull(scip, &slackvarcoeffs);
879 SCIPfreeBufferArrayNull(scip, &downslacks);
880 SCIPfreeBufferArrayNull(scip, &upslacks);
881 SCIPfreeBufferArrayNull(scip, &slackvars);
882 SCIPfreeBufferArrayNull(scip, &zilpcands);
883 SCIPfreeBufferArrayNull(scip, &solarray);
884
885 return SCIP_OKAY;
886}
887
888/*
889 * primal heuristic specific interface methods
890 */
891
892/** creates the zirounding primal heuristic and includes it in SCIP */
894 SCIP* scip /**< SCIP data structure */
895 )
896{
897 SCIP_HEURDATA* heurdata;
898 SCIP_HEUR* heur;
899
900 /* create zirounding primal heuristic data */
901 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
902
903 /* include primal heuristic */
906 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecZirounding, heurdata) );
907
908 assert(heur != NULL);
909
910 /* primal heuristic is safe to use in exact solving mode */
911 SCIPheurMarkExact(heur);
912
913 /* set non-NULL pointers to callback methods */
914 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyZirounding) );
915 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeZirounding) );
916 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitZirounding) );
917 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitZirounding) );
918 SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolZirounding) );
919
920 /* add zirounding primal heuristic parameters */
921 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/zirounding/maxroundingloops",
922 "determines maximum number of rounding loops",
923 &heurdata->maxroundingloops, TRUE, DEFAULT_MAXROUNDINGLOOPS, -1, INT_MAX, NULL, NULL) );
924 SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/zirounding/stopziround",
925 "flag to determine if Zirounding is deactivated after a certain percentage of unsuccessful calls",
926 &heurdata->stopziround, TRUE, DEFAULT_STOPZIROUND, NULL, NULL) );
927 SCIP_CALL( SCIPaddRealParam(scip,"heuristics/zirounding/stoppercentage",
928 "if percentage of found solutions falls below this parameter, Zirounding will be deactivated",
929 &heurdata->stoppercentage, TRUE, DEFAULT_STOPPERCENTAGE, 0.0, 1.0, NULL, NULL) );
930 SCIP_CALL( SCIPaddIntParam(scip, "heuristics/zirounding/minstopncalls",
931 "determines the minimum number of calls before percentage-based deactivation of Zirounding is applied",
932 &heurdata->minstopncalls, TRUE, DEFAULT_MINSTOPNCALLS, 1, INT_MAX, NULL, NULL) );
933
934 return SCIP_OKAY;
935}
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 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 REALABS(x)
Definition: def.h:182
#define SCIP_CALL(x)
Definition: def.h:355
#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 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 SCIPincludeHeurZirounding(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
int SCIPcolGetLPPos(SCIP_COL *col)
Definition: lp.c:17487
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 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 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_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:611
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:632
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 SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17686
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17607
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17632
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17696
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17895
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17745
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2068
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_Longint SCIPgetNLPs(SCIP *scip)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
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 SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:23683
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:23386
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
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
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:23652
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
Direction
Definition: heur_twoopt.c:138
enum Direction DIRECTION
Definition: heur_twoopt.c:143
@ DIRECTION_DOWN
@ DIRECTION_UP
static void calculateBounds(SCIP *scip, SCIP_VAR *var, SCIP_Real currentvalue, SCIP_Real *upperbound, SCIP_Real *lowerbound, SCIP_Real *upslacks, SCIP_Real *downslacks, int nslacks, SCIP_Bool *numericalerror)
#define DEFAULT_MAXROUNDINGLOOPS
static SCIP_RETCODE updateSlacks(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real shiftvalue, SCIP_Real *upslacks, SCIP_Real *downslacks, SCIP_Real *activities, SCIP_VAR **slackvars, SCIP_Real *slackcoeffs, int nslacks)
static SCIP_DECL_HEURCOPY(heurCopyZirounding)
#define HEUR_TIMING
#define HEUR_FREQOFS
static void rowFindSlackVar(SCIP *scip, SCIP_ROW *row, SCIP_VAR **varpointer, SCIP_Real *coeffpointer)
#define HEUR_DESC
enum Direction DIRECTION
#define DEFAULT_STOPPERCENTAGE
#define HEUR_DISPCHAR
#define HEUR_MAXDEPTH
static SCIP_DECL_HEURINITSOL(heurInitsolZirounding)
#define HEUR_PRIORITY
#define DEFAULT_STOPZIROUND
static SCIP_DECL_HEUREXEC(heurExecZirounding)
static SCIP_DECL_HEUREXIT(heurExitZirounding)
#define DEFAULT_MINSTOPNCALLS
#define HEUR_NAME
#define MINSHIFT
static SCIP_DECL_HEURINIT(heurInitZirounding)
static SCIP_Real getZiValue(SCIP *scip, SCIP_Real val)
#define HEUR_FREQ
#define HEUR_USESSUBSCIP
static SCIP_DECL_HEURFREE(heurFreeZirounding)
ZI Round primal heuristic.
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
public methods for primal heuristics
public methods for LP management
public methods for message output
#define SCIPstatisticMessage
Definition: pub_message.h:123
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
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:64
@ SCIP_VARSTATUS_COLUMN
Definition: type_var.h:53