Scippy

SCIP

Solving Constraint Integer Programs

prop_redcost.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 prop_redcost.c
26 * @ingroup DEFPLUGINS_PROP
27 * @brief propagator using the LP reduced cost and the cutoff bound
28 * @author Tobias Achterberg
29 * @author Stefan Heinz
30 * @author Matthias Miltenberger
31 * @author Michael Winkler
32 *
33 * This propagator uses the reduced cost of an optimal solved LP relaxation to propagate the variables against the
34 * cutoff bound.
35 */
36
37/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
38
39#include "lpi/type_lpi.h"
40#include "scip/prop_redcost.h"
41#include "scip/pub_lp.h"
42#include "scip/pub_message.h"
43#include "scip/pub_prop.h"
44#include "scip/pub_tree.h"
45#include "scip/pub_var.h"
46#include "scip/scip_branch.h"
47#include "scip/scip_exact.h"
48#include "scip/scip_general.h"
49#include "scip/scip_lp.h"
50#include "scip/scip_mem.h"
51#include "scip/scip_message.h"
52#include "scip/scip_numerics.h"
53#include "scip/scip_param.h"
54#include "scip/scip_pricer.h"
55#include "scip/scip_prob.h"
56#include "scip/scip_prop.h"
58#include "scip/scip_tree.h"
59#include "scip/scip_var.h"
60#include <string.h>
61
62/**@name Propagator properties
63 *
64 * @{
65 */
66
67#define PROP_NAME "redcost"
68#define PROP_DESC "reduced cost strengthening propagator"
69#define PROP_TIMING SCIP_PROPTIMING_DURINGLPLOOP | SCIP_PROPTIMING_AFTERLPLOOP
70#define PROP_PRIORITY +1000000 /**< propagator priority */
71#define PROP_FREQ 1 /**< propagator frequency */
72#define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators found reductions? */
73
74/**@} */
75
76
77/**@name Default parameter values
78 *
79 * @{
80 */
81
82#define DEFAULT_CONTINUOUS FALSE /**< should reduced cost fixing be also applied to continuous variables? */
83#define DEFAULT_USEIMPLICS FALSE /**< should implications be used to strength the reduced cost for binary variables? */
84#define DEFAULT_FORCE FALSE /**< should the propagator be forced even if active pricer are present? Note that
85 * the reductions are always valid, but installing an upper bound on priced
86 * variables may lead to problems in pricing (existing variables at their upper
87 * bound may be priced again since they may have negative reduced costs) */
88
89/**@} */
90
91
92/*
93 * Data structures
94 */
95
96
97/** propagator data */
98struct SCIP_PropData
99{
100 SCIP_Bool continuous; /**< should reduced cost fixing be also applied to continuous variables? */
101 SCIP_Real maxredcost; /**< maximum reduced cost of a single binary variable */
102 SCIP_Bool usefullimplics; /**< are the implied reduced cost useful */
103 SCIP_Bool useimplics; /**< should implications be used to strength the reduced cost for binary variables? */
104 SCIP_Bool force; /**< should the propagator be forced even if active pricer are present? */
105};
106
107
108/**@name Local methods
109 *
110 * @{
111 */
112
113/** propagate the given binary variable/column using the root reduced cost stored in the SCIP internal data structures
114 * and check if the implications can be useful. Depending on that implications are used or not used during the search to
115 * strength the reduced costs.
116 */
117static
119 SCIP* scip, /**< SCIP data structure */
120 SCIP_PROPDATA* propdata, /**< propagator data structure */
121 SCIP_VAR* var, /**< variable to use for propagation */
122 SCIP_COL* col, /**< LP column of the variable */
123 SCIP_Real cutoffbound, /**< the current cutoff bound */
124 int* nchgbds /**< pointer to count the number of bound changes */
125 )
126{
127 SCIP_Real rootredcost;
128 SCIP_Real rootsol;
129 SCIP_Real rootlpobjval;
130
131 assert(scip != NULL);
132 assert(SCIPgetDepth(scip) == 0);
133
134 /* skip binary variable if it is locally fixed */
135 if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 )
136 return SCIP_OKAY;
137
138 rootredcost = SCIPvarGetBestRootRedcost(var);
139 rootsol = SCIPvarGetBestRootSol(var);
140 rootlpobjval = SCIPvarGetBestRootLPObjval(var);
141
142 if( SCIPisDualfeasZero(scip, rootredcost) )
143 return SCIP_OKAY;
144
145 assert(rootlpobjval != SCIP_INVALID); /*lint !e777*/
146
147 if( rootsol > 0.5 )
148 {
149 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
150 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
151 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
152 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
153 */
154 assert(!SCIPisLPDualReliable(scip) || !SCIPisDualfeasPositive(scip, rootredcost));
155
156 /* update maximum reduced cost of a single binary variable */
157 propdata->maxredcost = MAX(propdata->maxredcost, -rootredcost);
158
159 if( rootlpobjval - rootredcost > cutoffbound )
160 {
161 SCIPdebugMsg(scip, "globally fix binary variable <%s> to 1.0\n", SCIPvarGetName(var));
162
163 SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) );
164 (*nchgbds)++;
165 return SCIP_OKAY;
166 }
167 }
168 else
169 {
170 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
171 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
172 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
173 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
174 */
175 assert(!SCIPisLPDualReliable(scip) || !SCIPisDualfeasNegative(scip, rootredcost));
176
177 /* update maximum reduced cost of a single binary variable */
178 propdata->maxredcost = MAX(propdata->maxredcost, rootredcost);
179
180 if( rootlpobjval + rootredcost > cutoffbound )
181 {
182 SCIPdebugMsg(scip, "globally fix binary variable <%s> to 0.0\n", SCIPvarGetName(var));
183
184 SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) );
185 (*nchgbds)++;
186 return SCIP_OKAY;
187 }
188 }
189
190 /* evaluate if the implications are useful; the implications are seen to be useful if they provide an increase for
191 * the root reduced costs
192 */
193 if( !propdata->usefullimplics )
194 {
195 SCIP_Real lbredcost;
196 SCIP_Real ubredcost;
197
198 lbredcost = SCIPgetVarImplRedcost(scip, var, FALSE);
199 assert(!SCIPisDualfeasPositive(scip, lbredcost));
200
201 ubredcost = SCIPgetVarImplRedcost(scip, var, TRUE);
202 assert(!SCIPisDualfeasNegative(scip, ubredcost));
203
204 switch( SCIPcolGetBasisStatus(col) )
205 {
207 ubredcost -= SCIPgetVarRedcost(scip, var);
208
209 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
210 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
211 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
212 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
213 */
214 assert(!SCIPisLPDualReliable(scip) || !SCIPisDualfeasNegative(scip, ubredcost));
215 break;
216
218 lbredcost -= SCIPgetVarRedcost(scip, var);
219
220 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
221 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
222 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
223 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
224 */
225 assert(!SCIPisLPDualReliable(scip) || !SCIPisDualfeasPositive(scip, lbredcost));
226 break;
227
230 default:
231 break;
232 }
233
234 propdata->usefullimplics = (lbredcost < 0.0) || (ubredcost > 0.0);
235 }
236
237 return SCIP_OKAY;
238}
239
240/** propagate the given binary variable/column using the reduced cost */
241static
243 SCIP* scip, /**< SCIP data structure */
244 SCIP_PROPDATA* propdata, /**< propagator data structure */
245 SCIP_VAR* var, /**< variable to use for propagation */
246 SCIP_COL* col, /**< LP column of the variable */
247 SCIP_Real requiredredcost, /**< required reduset cost to be able to fix a binary variable */
248 int* nchgbds, /**< pointer to count the number of bound changes */
249 SCIP_Bool* cutoff /**< pointer to store if an cutoff was detected */
250 )
251{
252 SCIP_Real lbredcost;
253 SCIP_Real ubredcost;
254 SCIP_Real redcost;
255
256 /* skip binary variable if it is locally fixed */
257 if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 )
258 return SCIP_OKAY;
259
260 /* first use the redcost cost to fix the binary variable */
261 switch( SCIPcolGetBasisStatus(col) )
262 {
264 redcost = SCIPgetVarRedcost(scip, var);
265
266 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
267 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
268 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
269 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
270 */
272
273 if( redcost > requiredredcost )
274 {
275 SCIPdebugMsg(scip, "variable <%s>: fixed 0.0 (requiredredcost <%g>, redcost <%g>)\n",
276 SCIPvarGetName(var), requiredredcost, redcost);
277
278 SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) );
279 (*nchgbds)++;
280 return SCIP_OKAY;
281 }
282 break;
283
285 redcost = SCIPgetVarRedcost(scip, var);
286
287 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
288 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
289 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
290 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
291 */
293
294 if( -redcost > requiredredcost )
295 {
296 SCIPdebugMsg(scip, "variable <%s>: fixed 1.0 (requiredredcost <%g>, redcost <%g>)\n",
297 SCIPvarGetName(var), requiredredcost, redcost);
298
299 SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) );
300 (*nchgbds)++;
301 return SCIP_OKAY;
302 }
303 break;
304
306 return SCIP_OKAY;
307
309 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
310 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
311 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
312 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
313 */
315 return SCIP_OKAY;
316
317 default:
318 SCIPerrorMessage("invalid basis state\n");
319 return SCIP_INVALIDDATA;
320 }
321
322 /* second, if the implications should be used and if the implications are seen to be promising use the implied
323 * reduced costs to fix the binary variable
324 */
325 if( propdata->useimplics && propdata->usefullimplics )
326 {
327 /* collect implied reduced costs if the variable would be fixed to its lower bound */
328 lbredcost = SCIPgetVarImplRedcost(scip, var, FALSE);
329
330 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
331 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
332 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
333 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
334 */
337
338 /* collect implied reduced costs if the variable would be fixed to its upper bound */
339 ubredcost = SCIPgetVarImplRedcost(scip, var, TRUE);
342
343 if( -lbredcost > requiredredcost && ubredcost > requiredredcost )
344 {
345 SCIPdebugMsg(scip, "variable <%s>: cutoff (requiredredcost <%g>, lbredcost <%g>, ubredcost <%g>)\n",
346 SCIPvarGetName(var), requiredredcost, lbredcost, ubredcost);
347
348 (*cutoff) = TRUE;
349 }
350 else if( -lbredcost > requiredredcost )
351 {
352 SCIPdebugMsg(scip, "variable <%s>: fixed 1.0 (requiredredcost <%g>, redcost <%g>, lbredcost <%g>)\n",
353 SCIPvarGetName(var), requiredredcost, redcost, lbredcost);
354
355 SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) );
356 (*nchgbds)++;
357 }
358 else if( ubredcost > requiredredcost )
359 {
360 SCIPdebugMsg(scip, "variable <%s>: fixed 0.0 (requiredredcost <%g>, redcost <%g>, ubredcost <%g>)\n",
361 SCIPvarGetName(var), requiredredcost, redcost, ubredcost);
362
363 SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) );
364 (*nchgbds)++;
365 }
366
367 /* update maximum reduced cost of a single binary variable */
368 propdata->maxredcost = MAX3(propdata->maxredcost, -lbredcost, ubredcost);
369 }
370
371 return SCIP_OKAY;
372}
373
374/** propagate the given none binary variable/column using the reduced cost */
375static
377 SCIP* scip, /**< SCIP data structure */
378 SCIP_VAR* var, /**< variable to use for propagation */
379 SCIP_COL* col, /**< LP column of the variable */
380 SCIP_Real lpobjval, /**< objective value of the current LP */
381 SCIP_Real cutoffbound, /**< the current cutoff bound */
382 int* nchgbds /**< pointer to count the number of bound changes */
383 )
384{
385 SCIP_Real redcost;
386
387 switch( SCIPcolGetBasisStatus(col) )
388 {
390 redcost = SCIPgetColRedcost(scip, col);
391
392 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
393 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
394 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
395 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
396 */
399
400 if( SCIPisDualfeasPositive(scip, redcost) )
401 {
402 SCIP_Real oldlb;
403 SCIP_Real oldub;
404
405 oldlb = SCIPvarGetLbLocal(var);
406 oldub = SCIPvarGetUbLocal(var);
407 assert(SCIPisEQ(scip, oldlb, SCIPcolGetLb(col)));
408 assert(SCIPisEQ(scip, oldub, SCIPcolGetUb(col)));
409
410 if( SCIPisFeasLT(scip, oldlb, oldub) )
411 {
412 SCIP_Real newub;
413 SCIP_Bool strengthen;
414
415 /* calculate reduced cost based bound */
416 newub = (cutoffbound - lpobjval) / redcost + oldlb;
417
418 /* check, if new bound is good enough:
419 * - integer variables: take all possible strengthenings
420 * - continuous variables: strengthening must cut part of the variable's dynamic range, and
421 * at least 20% of the current domain
422 */
423 if( SCIPvarIsIntegral(var) )
424 {
425 newub = SCIPadjustedVarUb(scip, var, newub);
426 strengthen = (newub < oldub - 0.5);
427 }
428 else
429 strengthen = (newub < SCIPcolGetMaxPrimsol(col) && newub <= 0.2 * oldlb + 0.8 * oldub);
430
431 if( strengthen )
432 {
433 /* strengthen upper bound */
434 SCIPdebugMsg(scip, "redcost strengthening upper bound: <%s> [%g,%g] -> [%g,%g] (ub=%g, lb=%g, redcost=%g)\n",
435 SCIPvarGetName(var), oldlb, oldub, oldlb, newub, cutoffbound, lpobjval, redcost);
436 SCIP_CALL( SCIPchgVarUb(scip, var, newub) );
437 (*nchgbds)++;
438 }
439 }
440 }
441 break;
442
444 break;
445
447 redcost = SCIPgetColRedcost(scip, col);
448
449 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
450 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
451 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
452 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
453 */
456
457 if( SCIPisDualfeasNegative(scip, redcost) )
458 {
459 SCIP_Real oldlb;
460 SCIP_Real oldub;
461
462 oldlb = SCIPvarGetLbLocal(var);
463 oldub = SCIPvarGetUbLocal(var);
464 assert(SCIPisEQ(scip, oldlb, SCIPcolGetLb(col)));
465 assert(SCIPisEQ(scip, oldub, SCIPcolGetUb(col)));
466
467 if( SCIPisFeasLT(scip, oldlb, oldub) )
468 {
469 SCIP_Real newlb;
470 SCIP_Bool strengthen;
471
472 /* calculate reduced cost based bound */
473 newlb = (cutoffbound - lpobjval) / redcost + oldub;
474
475 /* check, if new bound is good enough:
476 * - integer variables: take all possible strengthenings
477 * - continuous variables: strengthening must cut part of the variable's dynamic range, and
478 * at least 20% of the current domain
479 */
480 if( SCIPvarIsIntegral(var) )
481 {
482 newlb = SCIPadjustedVarLb(scip, var, newlb);
483 strengthen = (newlb > oldlb + 0.5);
484 }
485 else
486 strengthen = (newlb > SCIPcolGetMinPrimsol(col) && newlb >= 0.8 * oldlb + 0.2 * oldub);
487
488 /* check, if new bound is good enough: at least 20% strengthening for continuous variables */
489 if( strengthen )
490 {
491 /* strengthen lower bound */
492 SCIPdebugMsg(scip, "redcost strengthening lower bound: <%s> [%g,%g] -> [%g,%g] (ub=%g, lb=%g, redcost=%g)\n",
493 SCIPvarGetName(var), oldlb, oldub, newlb, oldub, cutoffbound, lpobjval, redcost);
494 SCIP_CALL( SCIPchgVarLb(scip, var, newlb) );
495 (*nchgbds)++;
496 }
497 }
498 }
499 break;
500
502 /* SCIPisLPDualReliable should always return TRUE if the dual feasibility check is enabled and the LP claims to
503 * have a dual feasible solution. if the check is disabled the dual solution might be incorrect and the assert
504 * might fail. however, if the user decides to disable the dual feasibility check (which also can lead to wrong
505 * cutoffs) we don't want to skip propagating with reduced costs as an unexpected side-effect.
506 */
508 break;
509
510 default:
511 SCIPerrorMessage("invalid basis state\n");
512 return SCIP_INVALIDDATA;
513 }
514
515 return SCIP_OKAY;
516}
517
518/**@} */
519
520/**@name Callback methods of propagator
521 *
522 * @{
523 */
524
525/** copy method for propagator plugins (called when SCIP copies plugins) */
526static
527SCIP_DECL_PROPCOPY(propCopyRedcost)
528{ /*lint --e{715}*/
529 assert(scip != NULL);
530 assert(prop != NULL);
531 assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0);
532
533 /* call inclusion method of constraint handler */
535
536 return SCIP_OKAY;
537}
538
539/** destructor of propagator to free user data (called when SCIP is exiting) */
540/**! [SnippetPropFreeRedcost] */
541static
542SCIP_DECL_PROPFREE(propFreeRedcost)
543{ /*lint --e{715}*/
544 SCIP_PROPDATA* propdata;
545
546 /* free propagator data */
547 propdata = SCIPpropGetData(prop);
548 assert(propdata != NULL);
549
550 SCIPfreeBlockMemory(scip, &propdata);
551
552 SCIPpropSetData(prop, NULL);
553
554 return SCIP_OKAY;
555}
556/**! [SnippetPropFreeRedcost] */
557
558/** solving process initialization method of propagator (called when branch and bound process is about to begin) */
559static
560SCIP_DECL_PROPINITSOL(propInitsolRedcost)
561{
562 SCIP_PROPDATA* propdata;
563
564 propdata = SCIPpropGetData(prop);
565 assert(propdata != NULL);
566
567 propdata->usefullimplics = FALSE;
568 propdata->maxredcost = 0.0;
569
570 return SCIP_OKAY;
571}
572
573/** reduced cost propagation method for an LP solution */
574static
575SCIP_DECL_PROPEXEC(propExecRedcost)
576{ /*lint --e{715}*/
577 SCIP_PROPDATA* propdata;
578 SCIP_COL** cols;
579 SCIP_Real requiredredcost;
580 SCIP_Real cutoffbound;
581 SCIP_Real lpobjval;
582 SCIP_Bool propbinvars;
583 SCIP_Bool cutoff;
584 int nchgbds;
585 int ncols;
586 int c;
587
588 *result = SCIP_DIDNOTRUN;
589
590 /* in case we have a zero objective function, we skip the reduced cost propagator */
591 if( SCIPgetNObjVars(scip) == 0 )
592 return SCIP_OKAY;
593
594 /* propagator can only be applied during solving stage */
596 return SCIP_OKAY;
597
598 /* we cannot apply reduced cost fixing, if we want to solve exactly */
599 /**@todo implement reduced cost fixing with interval arithmetics */
600 if( SCIPisExact(scip) )
601 return SCIP_OKAY;
602
603 /* only call propagator, if the current node has an LP */
605 return SCIP_OKAY;
606
607 /* only call propagator, if an optimal LP solution is at hand */
609 return SCIP_OKAY;
610
611 /* only call propagator, if the current LP is a valid relaxation */
612 if( !SCIPisLPRelax(scip) )
613 return SCIP_OKAY;
614
615 /* we cannot apply reduced cost strengthening, if no simplex basis is available */
616 if( !SCIPisLPSolBasic(scip) )
617 return SCIP_OKAY;
618
619 /* do not run if propagation w.r.t. objective is not allowed */
621 return SCIP_OKAY;
622
623 /* get current cutoff bound */
624 cutoffbound = SCIPgetCutoffbound(scip);
625
626 /* reduced cost strengthening can only be applied, if we have a finite cutoff */
627 if( SCIPisInfinity(scip, cutoffbound) )
628 return SCIP_OKAY;
629
630 /* get LP columns */
631 cols = SCIPgetLPCols(scip);
632 ncols = SCIPgetNLPCols(scip);
633
634 /* do nothing if the LP has no columns (is empty) */
635 if( ncols == 0 )
636 return SCIP_OKAY;
637
638 /* get propagator data */
639 propdata = SCIPpropGetData(prop);
640 assert(propdata != NULL);
641
642 /* do nothing if active pricer are present and force flag is not TRUE */
643 if( !propdata->force && SCIPgetNActivePricers(scip) > 0 )
644 return SCIP_OKAY;
645
646 /* check if all integral variables are fixed and the continuous variables should not be propagated */
647 if( !propdata->continuous && SCIPgetNPseudoBranchCands(scip) == 0 )
648 return SCIP_OKAY;
649
650 /* get LP objective value */
651 lpobjval = SCIPgetLPObjval(scip);
652
653 /* check if binary variables should be propagated */
654 propbinvars = (SCIPgetDepth(scip) == 0) || (cutoffbound - lpobjval < 5 * propdata->maxredcost);
655
656 /* skip the propagator if the problem has only binary variables and those should not be propagated */
657 if( !propbinvars && SCIPgetNVars(scip) == SCIPgetNBinVars(scip) )
658 return SCIP_OKAY;
659
660 *result = SCIP_DIDNOTFIND;
661 cutoff = FALSE;
662 nchgbds = 0;
663
664 /* compute the required reduced cost which are needed for a binary variable to be fixed */
665 requiredredcost = cutoffbound - lpobjval;
666
667 SCIPdebugMsg(scip, "lpobjval <%g>, cutoffbound <%g>, max reduced <%g>, propgate binary %u, use implics %u\n",
668 lpobjval, cutoffbound, propdata->maxredcost, propbinvars, propdata->usefullimplics);
669
670 /* check reduced costs for non-basic columns */
671 for( c = 0; c < ncols && !cutoff; ++c )
672 {
673 SCIP_VAR* var;
674
675 var = SCIPcolGetVar(cols[c]);
676
677 /* skip continuous variables in case the corresponding parameter is set */
678 if( !propdata->continuous && !SCIPvarIsIntegral(var) )
679 continue;
680
681 if( SCIPvarIsBinary(var) )
682 {
683 if( propbinvars )
684 {
685 if( SCIPgetDepth(scip) == 0 )
686 {
687 SCIP_CALL( propagateRootRedcostBinvar(scip, propdata, var, cols[c], cutoffbound, &nchgbds) );
688 }
689 else
690 {
691 SCIP_CALL( propagateRedcostBinvar(scip, propdata, var, cols[c], requiredredcost, &nchgbds, &cutoff) );
692 }
693 }
694 }
695 else
696 {
697 SCIP_CALL( propagateRedcostVar(scip, var, cols[c], lpobjval, cutoffbound, &nchgbds) );
698 }
699 }
700
701 if( cutoff )
702 {
703 *result = SCIP_CUTOFF;
704
705 SCIPdebugMsg(scip, "node %" SCIP_LONGINT_FORMAT ": detected cutoff\n",
707 }
708 else if( nchgbds > 0 )
709 {
710 *result = SCIP_REDUCEDDOM;
711
712 SCIPdebugMsg(scip, "node %" SCIP_LONGINT_FORMAT ": %d bound changes (max redcost <%g>)\n",
713 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) , nchgbds, propdata->maxredcost);
714 }
715
716 return SCIP_OKAY;
717}
718
719/**@} */
720
721/** creates the redcost propagator and includes it in SCIP */
723 SCIP* scip /**< SCIP data structure */
724 )
725{
726 SCIP_PROPDATA* propdata;
727 SCIP_PROP* prop;
728
729 /* create redcost propagator data */
730 SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
731
732 /* include propagator */
734 propExecRedcost, propdata) );
735
736 assert(prop != NULL);
737
738 /* set optional callbacks via setter functions */
739 SCIP_CALL( SCIPsetPropCopy(scip, prop, propCopyRedcost) );
740 SCIP_CALL( SCIPsetPropInitsol(scip, prop, propInitsolRedcost) );
741 SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeRedcost) );
742
743 /* add redcost propagator parameters */
745 "propagating/" PROP_NAME "/continuous",
746 "should reduced cost fixing be also applied to continuous variables?",
747 &propdata->continuous, FALSE, DEFAULT_CONTINUOUS, NULL, NULL) );
749 "propagating/" PROP_NAME "/useimplics",
750 "should implications be used to strength the reduced cost for binary variables?",
751 &propdata->useimplics, FALSE, DEFAULT_USEIMPLICS, NULL, NULL) );
753 "propagating/" PROP_NAME "/force",
754 "should the propagator be forced even if active pricer are present?",
755 &propdata->force, TRUE, DEFAULT_FORCE, NULL, NULL) );
756
757 return SCIP_OKAY;
758}
#define NULL
Definition: def.h:248
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_Bool
Definition: def.h:91
#define MAX3(x, y, z)
Definition: def.h:228
#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_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2616
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2293
#define SCIPdebugMsg
Definition: scip_message.h:78
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 SCIPincludePropRedcost(SCIP *scip)
Definition: prop_redcost.c:722
int SCIPgetNPseudoBranchCands(SCIP *scip)
Definition: scip_branch.c:766
SCIP_Real SCIPgetColRedcost(SCIP *scip, SCIP_COL *col)
Definition: scip_lp.c:1163
SCIP_Real SCIPcolGetMinPrimsol(SCIP_COL *col)
Definition: lp.c:17392
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17425
SCIP_Real SCIPcolGetLb(SCIP_COL *col)
Definition: lp.c:17346
SCIP_Real SCIPcolGetUb(SCIP_COL *col)
Definition: lp.c:17356
SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
Definition: lp.c:17414
SCIP_Real SCIPcolGetMaxPrimsol(SCIP_COL *col)
Definition: lp.c:17402
SCIP_Bool SCIPisExact(SCIP *scip)
Definition: scip_exact.c:193
SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition: scip_lp.c:87
SCIP_Bool SCIPisLPRelax(SCIP *scip)
Definition: scip_lp.c:231
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
SCIP_COL ** SCIPgetLPCols(SCIP *scip)
Definition: scip_lp.c:512
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:253
int SCIPgetNLPCols(SCIP *scip)
Definition: scip_lp.c:533
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip_lp.c:673
SCIP_Bool SCIPisLPDualReliable(SCIP *scip)
Definition: scip_lp.c:213
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:8483
int SCIPgetNActivePricers(SCIP *scip)
Definition: scip_pricer.c:348
void SCIPpropSetData(SCIP_PROP *prop, SCIP_PROPDATA *propdata)
Definition: prop.c:801
SCIP_RETCODE SCIPsetPropInitsol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPINITSOL((*propinitsol)))
Definition: scip_prop.c:219
SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
Definition: prop.c:791
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition: prop.c:951
SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPFREE((*propfree)))
Definition: scip_prop.c:171
SCIP_RETCODE SCIPsetPropCopy(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPCOPY((*propcopy)))
Definition: scip_prop.c:155
SCIP_RETCODE SCIPincludePropBasic(SCIP *scip, SCIP_PROP **propptr, const char *name, const char *desc, int priority, int freq, SCIP_Bool delay, SCIP_PROPTIMING timingmask, SCIP_DECL_PROPEXEC((*propexec)), SCIP_PROPDATA *propdata)
Definition: scip_prop.c:118
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_Bool SCIPisDualfeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisDualfeasPositive(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 SCIPisDualfeasZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:91
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_RETCODE SCIPchgVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:5697
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Real SCIPvarGetBestRootSol(SCIP_VAR *var)
Definition: var.c:19480
SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:5875
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:5634
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:5570
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:2608
SCIP_Real SCIPvarGetBestRootRedcost(SCIP_VAR *var)
Definition: var.c:19547
SCIP_Real SCIPvarGetBestRootLPObjval(SCIP_VAR *var)
Definition: var.c:19581
SCIP_Real SCIPgetVarImplRedcost(SCIP *scip, SCIP_VAR *var, SCIP_Bool varfixing)
Definition: scip_var.c:2653
SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
Definition: scip_var.c:10998
#define PROP_DESC
Definition: prop_redcost.c:68
#define PROP_NAME
Definition: prop_redcost.c:67
static SCIP_DECL_PROPFREE(propFreeRedcost)
Definition: prop_redcost.c:542
static SCIP_DECL_PROPEXEC(propExecRedcost)
Definition: prop_redcost.c:575
#define PROP_DELAY
Definition: prop_redcost.c:72
#define DEFAULT_CONTINUOUS
Definition: prop_redcost.c:82
#define PROP_TIMING
Definition: prop_redcost.c:69
#define DEFAULT_USEIMPLICS
Definition: prop_redcost.c:83
static SCIP_DECL_PROPCOPY(propCopyRedcost)
Definition: prop_redcost.c:527
static SCIP_DECL_PROPINITSOL(propInitsolRedcost)
Definition: prop_redcost.c:560
static SCIP_RETCODE propagateRedcostBinvar(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_COL *col, SCIP_Real requiredredcost, int *nchgbds, SCIP_Bool *cutoff)
Definition: prop_redcost.c:242
static SCIP_RETCODE propagateRedcostVar(SCIP *scip, SCIP_VAR *var, SCIP_COL *col, SCIP_Real lpobjval, SCIP_Real cutoffbound, int *nchgbds)
Definition: prop_redcost.c:376
#define PROP_FREQ
Definition: prop_redcost.c:71
#define DEFAULT_FORCE
Definition: prop_redcost.c:84
#define PROP_PRIORITY
Definition: prop_redcost.c:70
static SCIP_RETCODE propagateRootRedcostBinvar(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_VAR *var, SCIP_COL *col, SCIP_Real cutoffbound, int *nchgbds)
Definition: prop_redcost.c:118
propagator using the LP reduced cost and the cutoff bound
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
public methods for propagators
public methods for branch and bound tree
public methods for problem variables
public methods for branching rule plugins and branching
public methods for exact solving
general public methods
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 variable pricer plugins
public methods for global and local (sub)problems
public methods for propagator plugins
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
type definitions for specific LP solvers interface
@ SCIP_BASESTAT_BASIC
Definition: type_lpi.h:92
@ SCIP_BASESTAT_UPPER
Definition: type_lpi.h:93
@ SCIP_BASESTAT_LOWER
Definition: type_lpi.h:91
@ SCIP_BASESTAT_ZERO
Definition: type_lpi.h:94
struct SCIP_PropData SCIP_PROPDATA
Definition: type_prop.h:52
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_REDUCEDDOM
Definition: type_result.h:51
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_SOLVING
Definition: type_set.h:53