Scippy

SCIP

Solving Constraint Integer Programs

benderscut_int.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 benderscut_int.c
26 * @ingroup OTHER_CFILES
27 * @brief Generates a Laporte and Louveaux Benders' decomposition integer cut
28 * @author Stephen J. Maher
29 */
30
31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32
33#include "scip/benderscut_int.h"
34#include "scip/cons_linear.h"
35#include "scip/pub_benderscut.h"
36#include "scip/pub_benders.h"
37#include "scip/pub_lp.h"
38#include "scip/pub_message.h"
39#include "scip/pub_misc.h"
40#include "scip/pub_paramset.h"
41#include "scip/pub_var.h"
42#include "scip/scip_benders.h"
43#include "scip/scip_cons.h"
44#include "scip/scip_cut.h"
45#include "scip/scip_general.h"
46#include "scip/scip_lp.h"
47#include "scip/scip_mem.h"
48#include "scip/scip_message.h"
49#include "scip/scip_numerics.h"
50#include "scip/scip_param.h"
51#include "scip/scip_prob.h"
52#include "scip/scip_sol.h"
53#include <string.h>
54
55#define BENDERSCUT_NAME "integer"
56#define BENDERSCUT_DESC "Laporte and Louveaux Benders' decomposition integer cut"
57#define BENDERSCUT_PRIORITY 0
58#define BENDERSCUT_LPCUT FALSE
59
60#define SCIP_DEFAULT_ADDCUTS FALSE /** Should cuts be generated, instead of constraints */
61#define SCIP_DEFAULT_CUTCONSTANT -10000.0
62
63/*
64 * Data structures
65 */
66
67/** Benders' decomposition cuts data */
68struct SCIP_BenderscutData
69{
70 SCIP_BENDERS* benders; /**< the Benders' decomposition data structure */
71 SCIP_Real cutconstant; /**< the constant for computing the integer cuts */
72 SCIP_Real* subprobconstant; /**< the constant for each subproblem used for computing the integer cuts */
73 SCIP_Bool addcuts; /**< should cuts be generated instead of constraints */
74 SCIP_Bool* firstcut; /**< flag to indicate that the first cut needs to be generated. */
75 int nsubproblems; /**< the number of subproblems for the Benders' decomposition */
76 SCIP_Bool subprobsvalid; /**< is it valid to apply integer cuts for this problem */
77 SCIP_Bool created; /**< has the Benders cut data been created */
78};
79
80/** method to call, when the priority of a Benders' decomposition was changed */
81static
82SCIP_DECL_PARAMCHGD(paramChgdBenderscutintConstant)
83{ /*lint --e{715}*/
84 SCIP_BENDERSCUTDATA* benderscutdata;
85 int i;
86
87 benderscutdata = (SCIP_BENDERSCUTDATA*)SCIPparamGetData(param);
88 assert(benderscutdata != NULL);
89
90 for( i = 0; i < benderscutdata->nsubproblems; i++ )
91 benderscutdata->subprobconstant[i] = benderscutdata->cutconstant;
92
93 return SCIP_OKAY;
94}
95
96
97/** creates the Benders' decomposition cut data */
98static
100 SCIP* scip, /**< the SCIP data structure */
101 SCIP_BENDERSCUTDATA* benderscutdata /**< the Benders' cut data */
102 )
103{
104 int nmastervars;
105 int nmasterbinvars;
106 int i;
107
108 assert(scip != NULL);
109 assert(benderscutdata != NULL);
110
111 benderscutdata->nsubproblems = SCIPbendersGetNSubproblems(benderscutdata->benders);
112 benderscutdata->subprobsvalid = TRUE;
113
114 /* allocating the memory for the subproblem constants */
115 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &benderscutdata->subprobconstant, benderscutdata->nsubproblems) );
116 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &benderscutdata->firstcut, benderscutdata->nsubproblems) );
117
118 for( i = 0; i < benderscutdata->nsubproblems; i++ )
119 {
120 benderscutdata->subprobconstant[i] = benderscutdata->cutconstant;
121 benderscutdata->firstcut[i] = TRUE;
122
123 /* it is only possible to generate the no-good cut for subproblems that only include binary master variables */
124 SCIPbendersGetSubproblemMasterVarsData(benderscutdata->benders, i, NULL, &nmastervars, &nmasterbinvars, NULL);
125
126 if( nmastervars != nmasterbinvars )
127 {
128 benderscutdata->subprobsvalid = FALSE;
129 }
130 }
131
132 benderscutdata->created = TRUE;
133
134 return SCIP_OKAY;
135}
136
137/*
138 * Local methods
139 */
140
141/** updates the cut constant for the given subproblem based upon the global bounds of the associated auxiliary variable */
142static
144 SCIP* masterprob, /**< the SCIP instance of the master problem */
145 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
146 SCIP_BENDERSCUTDATA* benderscutdata, /**< the Benders' decomposition cut data */
147 int probnumber /**< the index for the subproblem */
148 )
149{
150 SCIP_VAR* auxiliaryvar;
151
152 assert(masterprob != NULL);
153 assert(benders != NULL);
154 assert(benderscutdata != NULL);
155
156 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
157
158 /* checking if the subproblem lower bound has been updated. If it is has changed, then firstcut is set to TRUE.
159 * Otherwise, the constant remains the same.
160 */
161 if( SCIPisGT(masterprob, SCIPbendersGetSubproblemLowerbound(benders, probnumber),
162 benderscutdata->subprobconstant[probnumber]) )
163 {
164 benderscutdata->subprobconstant[probnumber] = SCIPbendersGetSubproblemLowerbound(benders, probnumber);
165 benderscutdata->firstcut[probnumber] = TRUE;
166 }
167
168 /* updating the cut constant if the auxiliary variable global lower bound is greater than the current constant */
169 if( SCIPisGT(masterprob, SCIPvarGetLbGlobal(auxiliaryvar), benderscutdata->subprobconstant[probnumber]) )
170 benderscutdata->subprobconstant[probnumber] = SCIPvarGetLbGlobal(auxiliaryvar);
171}
172
173/** computes a standard Benders' optimality cut from the dual solutions of the LP */
174static
176 SCIP* masterprob, /**< the SCIP instance of the master problem */
177 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
178 SCIP_SOL* sol, /**< primal CIP solution */
179 SCIP_CONS* cons, /**< the constraint for the generated cut, can be NULL */
180 SCIP_ROW* row, /**< the row for the generated cut, can be NULL */
181 SCIP_Real cutconstant, /**< the constant value in the integer optimality cut */
182 int probnumber, /**< the number of the pricing problem */
183 SCIP_Bool addcut, /**< indicates whether a cut is created instead of a constraint */
184 SCIP_Bool* success /**< was the cut generation successful? */
185 )
186{
187 SCIP_VAR** vars;
188 int nvars;
189 SCIP_Real subprobobj; /* the objective function value of the subproblem */
190 SCIP_Real lhs; /* the left hand side of the cut */
191 int i;
192 SCIPdebug( SCIP* subproblem; )
193
194#ifndef NDEBUG
195 SCIP_Real verifyobj = 0;
196#endif
197
198 assert(masterprob != NULL);
199 assert(benders != NULL);
200 assert(cons != NULL || addcut);
201 assert(row != NULL || !addcut);
202
203 (*success) = FALSE;
204
205 /* getting the best solution from the subproblem */
206
207 subprobobj = SCIPbendersGetSubproblemObjval(benders, probnumber);
208
209 SCIPdebug( subproblem = SCIPbendersSubproblem(benders, probnumber); )
210 SCIPdebug( SCIPdebugMsg(masterprob, "Subproblem %d - Objective Value: Stored - %g Orig Obj - %g Cut constant - %g\n",
211 probnumber, SCIPbendersGetSubproblemObjval(benders, probnumber), SCIPgetSolOrigObj(subproblem, SCIPgetBestSol(subproblem))*(int)SCIPgetObjsense(subproblem),
212 cutconstant); )
213
214 nvars = SCIPgetNVars(masterprob);
215 vars = SCIPgetVars(masterprob);
216
217 /* adding the subproblem objective function value to the lhs */
218 if( addcut )
219 lhs = SCIProwGetLhs(row);
220 else
221 lhs = SCIPgetLhsLinear(masterprob, cons);
222
223 /* looping over all master problem variables to update the coefficients in the computed cut. */
224 for( i = 0; i < nvars; i++ )
225 {
226 SCIP_VAR* subprobvar;
227 SCIP_Real coef;
228
229 SCIP_CALL( SCIPgetBendersSubproblemVar(masterprob, benders, vars[i], &subprobvar, probnumber) );
230
231 /* if there is a corresponding subproblem variable, then the variable will not be NULL. */
232 if( subprobvar != NULL )
233 {
234 /* if the variable is on its upper bound, then the subproblem objective value is added to the cut */
235 if( SCIPisFeasEQ(masterprob, SCIPgetSolVal(masterprob, sol, vars[i]), 1.0) )
236 {
237 coef = -(subprobobj - cutconstant);
238 lhs -= (subprobobj - cutconstant);
239 }
240 else
241 coef = (subprobobj - cutconstant);
242
243 /* adding the variable to the cut. The coefficient is the subproblem objective value */
244 if( addcut )
245 {
246 SCIP_CALL( SCIPaddVarToRow(masterprob, row, vars[i], coef) );
247 }
248 else
249 {
250 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, vars[i], coef) );
251 }
252 }
253 }
254
255 lhs += subprobobj;
256
257 /* if the bound becomes infinite, then the cut generation terminates. */
258 if( SCIPisInfinity(masterprob, lhs) || SCIPisInfinity(masterprob, -lhs) )
259 {
260 (*success) = FALSE;
261 SCIPdebugMsg(masterprob, "Infinite bound when generating integer optimality cut.\n");
262 return SCIP_OKAY;
263 }
264
265 /* Update the lhs of the cut */
266 if( addcut )
267 {
268 SCIP_CALL( SCIPchgRowLhs(masterprob, row, lhs) );
269 }
270 else
271 {
272 SCIP_CALL( SCIPchgLhsLinear(masterprob, cons, lhs) );
273 }
274
275#ifndef NDEBUG
276 if( addcut )
277 lhs = SCIProwGetLhs(row);
278 else
279 lhs = SCIPgetLhsLinear(masterprob, cons);
280 verifyobj += lhs;
281
282 if( addcut )
283 verifyobj -= SCIPgetRowSolActivity(masterprob, row, sol);
284 else
285 verifyobj -= SCIPgetActivityLinear(masterprob, cons, sol);
286#endif
287
288 assert(SCIPisFeasEQ(masterprob, verifyobj, subprobobj));
289
290 (*success) = TRUE;
291
292 return SCIP_OKAY;
293}
294
295
296/** adds the auxiliary variable to the generated cut. If this is the first optimality cut for the subproblem, then the
297 * auxiliary variable is first created and added to the master problem.
298 */
299static
301 SCIP* masterprob, /**< the SCIP instance of the master problem */
302 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
303 SCIP_CONS* cons, /**< the constraint for the generated cut, can be NULL */
304 SCIP_ROW* row, /**< the row for the generated cut, can be NULL */
305 int probnumber, /**< the number of the pricing problem */
306 SCIP_Bool addcut /**< indicates whether a cut is created instead of a constraint */
307 )
308{
309 SCIP_VAR* auxiliaryvar;
310
311 assert(masterprob != NULL);
312 assert(benders != NULL);
313 assert(cons != NULL || addcut);
314 assert(row != NULL || !addcut);
315
316 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
317
318 /* adding the auxiliary variable to the generated cut */
319 if( addcut )
320 {
321 SCIP_CALL( SCIPaddVarToRow(masterprob, row, auxiliaryvar, 1.0) );
322 }
323 else
324 {
325 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, auxiliaryvar, 1.0) );
326 }
327
328 return SCIP_OKAY;
329}
330
331
332/** generates and applies Benders' cuts */
333static
335 SCIP* masterprob, /**< the SCIP instance of the master problem */
336 SCIP_BENDERS* benders, /**< the benders' decomposition */
337 SCIP_BENDERSCUT* benderscut, /**< the benders' decomposition cut method */
338 SCIP_SOL* sol, /**< primal CIP solution */
339 int probnumber, /**< the number of the pricing problem */
340 SCIP_BENDERSENFOTYPE type, /**< the enforcement type calling this function */
341 SCIP_RESULT* result, /**< the result from solving the subproblems */
342 SCIP_Bool initcons /**< is this function called to generate the initial constraint */
343 )
344{
345 SCIP_BENDERSCUTDATA* benderscutdata;
346 SCIP_CONSHDLR* consbenders;
347 SCIP_CONS* cons;
348 SCIP_ROW* row;
349 char cutname[SCIP_MAXSTRLEN];
350 SCIP_Bool optimal;
351 SCIP_Bool addcut;
352 SCIP_Bool success;
353
354 assert(masterprob != NULL);
355 assert(benders != NULL);
356 assert(benderscut != NULL);
357 assert(result != NULL);
358
359 row = NULL;
360 cons = NULL;
361
362 success = FALSE;
363
364 /* retrieving the Benders' cut data */
365 benderscutdata = SCIPbenderscutGetData(benderscut);
366
367 /* if the cuts are generated prior to the solving stage, then rows can not be generated. So constraints must be added
368 * to the master problem.
369 */
370 if( SCIPgetStage(masterprob) < SCIP_STAGE_INITSOLVE )
371 addcut = FALSE;
372 else
373 addcut = benderscutdata->addcuts;
374
375 /* retrieving the Benders' decomposition constraint handler */
376 consbenders = SCIPfindConshdlr(masterprob, "benders");
377
378 /* checking the optimality of the original problem with a comparison between the auxiliary variable and the
379 * objective value of the subproblem
380 */
381 optimal = FALSE;
382 SCIP_CALL( SCIPcheckBendersSubproblemOptimality(masterprob, benders, sol, probnumber, &optimal) );
383
384 if( optimal )
385 {
386 (*result) = SCIP_FEASIBLE;
387 SCIPdebugMsg(masterprob, "No <%s> cut added. Current Master Problem Obj: %g\n", BENDERSCUT_NAME,
388 SCIPgetSolOrigObj(masterprob, NULL)*(int)SCIPgetObjsense(masterprob));
389 return SCIP_OKAY;
390 }
391
392 /* checking whether the subproblem constant is less than the auxiliary variable global lower bound */
393 updateSubproblemCutConstant(masterprob, benders, benderscutdata, probnumber);
394
395 /* if no integer cuts have been previously generated and the bound on the auxiliary variable is -infinity,
396 * then an initial lower bounding cut is added
397 */
398 if( benderscutdata->firstcut[probnumber]
399 && SCIPisInfinity(masterprob, -SCIPvarGetLbGlobal(SCIPbendersGetAuxiliaryVar(benders, probnumber))) )
400 {
401 benderscutdata->firstcut[probnumber] = FALSE;
402 SCIP_CALL( generateAndApplyBendersIntegerCuts(masterprob, benders, benderscut, sol, probnumber, type, result,
403 TRUE) );
404 }
405
406 /* setting the name of the generated cut */
407 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "integeroptcut_%d_%" SCIP_LONGINT_FORMAT, probnumber,
408 SCIPbenderscutGetNFound(benderscut) );
409
410 /* creating an empty row or constraint for the Benders' cut */
411 if( addcut )
412 {
413 SCIP_CALL( SCIPcreateEmptyRowConshdlr(masterprob, &row, consbenders, cutname, 0.0, SCIPinfinity(masterprob), FALSE,
414 FALSE, TRUE) );
415 }
416 else
417 {
418 SCIP_CALL( SCIPcreateConsBasicLinear(masterprob, &cons, cutname, 0, NULL, NULL, 0.0, SCIPinfinity(masterprob)) );
419 SCIP_CALL( SCIPsetConsDynamic(masterprob, cons, TRUE) );
420 SCIP_CALL( SCIPsetConsRemovable(masterprob, cons, TRUE) );
421 }
422
423 if( initcons )
424 {
425 SCIP_Real lhs;
426
427 /* adding the subproblem objective function value to the lhs */
428 if( addcut )
429 lhs = SCIProwGetLhs(row);
430 else
431 lhs = SCIPgetLhsLinear(masterprob, cons);
432
433 lhs += benderscutdata->subprobconstant[probnumber];
434
435 /* if the bound becomes infinite, then the cut generation terminates. */
436 if( SCIPisInfinity(masterprob, lhs) || SCIPisInfinity(masterprob, -lhs) )
437 {
438 success = FALSE;
439 SCIPdebugMsg(masterprob, "Infinite bound when generating integer optimality cut.\n");
440 }
441
442 /* Update the lhs of the cut */
443 if( addcut )
444 {
445 SCIP_CALL( SCIPchgRowLhs(masterprob, row, lhs) );
446 }
447 else
448 {
449 SCIP_CALL( SCIPchgLhsLinear(masterprob, cons, lhs) );
450 }
451 }
452 else
453 {
454 /* computing the coefficients of the optimality cut */
455 SCIP_CALL( computeStandardIntegerOptCut(masterprob, benders, sol, cons, row,
456 benderscutdata->subprobconstant[probnumber], probnumber, addcut, &success) );
457 }
458
459 /* if success is FALSE, then there was an error in generating the integer optimality cut. No cut will be added to
460 * the master problem. Otherwise, the constraint is added to the master problem.
461 */
462 if( !success )
463 {
464 (*result) = SCIP_DIDNOTFIND;
465 SCIPdebugMsg(masterprob, "Error in generating Benders' integer optimality cut for problem %d.\n", probnumber);
466 }
467 else
468 {
469 /* adding the auxiliary variable to the optimality cut */
470 SCIP_CALL( addAuxiliaryVariableToCut(masterprob, benders, cons, row, probnumber, addcut) );
471
472 /* adding the constraint to the master problem */
473 if( addcut )
474 {
475 SCIP_Bool infeasible;
476
478 {
479 SCIP_CALL( SCIPaddRow(masterprob, row, FALSE, &infeasible) );
480 assert(!infeasible);
481 }
482 else
483 {
485 SCIP_CALL( SCIPaddPoolCut(masterprob, row) );
486 }
487
488#ifdef SCIP_DEBUG
489 SCIP_CALL( SCIPprintRow(masterprob, row, NULL) );
490 SCIPinfoMessage(masterprob, NULL, ";\n");
491#endif
492
493 (*result) = SCIP_SEPARATED;
494 }
495 else
496 {
497 SCIP_CALL( SCIPaddCons(masterprob, cons) );
498
499 SCIPdebugPrintCons(masterprob, cons, NULL);
500
501 (*result) = SCIP_CONSADDED;
502 }
503 }
504
505 if( addcut )
506 {
507 /* release the row */
508 SCIP_CALL( SCIPreleaseRow(masterprob, &row) );
509 }
510 else
511 {
512 /* release the constraint */
513 SCIP_CALL( SCIPreleaseCons(masterprob, &cons) );
514 }
515
516 return SCIP_OKAY;
517}
518
519/*
520 * Callback methods of Benders' decomposition cuts
521 */
522
523/** destructor of Benders' decomposition cuts to free user data (called when SCIP is exiting) */
524static
525SCIP_DECL_BENDERSCUTFREE(benderscutFreeInt)
526{ /*lint --e{715}*/
527 SCIP_BENDERSCUTDATA* benderscutdata;
528
529 assert( benderscut != NULL );
530 assert( strcmp(SCIPbenderscutGetName(benderscut), BENDERSCUT_NAME) == 0 );
531
532 /* free Benders' cut data */
533 benderscutdata = SCIPbenderscutGetData(benderscut);
534 assert( benderscutdata != NULL );
535
536 SCIPfreeBlockMemory(scip, &benderscutdata);
537
538 SCIPbenderscutSetData(benderscut, NULL);
539
540 return SCIP_OKAY;
541}
542
543
544/** deinitialization method of Benders' decomposition cuts (called before transformed problem is freed) */
545static
546SCIP_DECL_BENDERSCUTEXIT(benderscutExitInt)
547{ /*lint --e{715}*/
548 SCIP_BENDERSCUTDATA* benderscutdata;
549
550 assert( benderscut != NULL );
551 assert( strcmp(SCIPbenderscutGetName(benderscut), BENDERSCUT_NAME) == 0 );
552
553 /* free Benders' cut data */
554 benderscutdata = SCIPbenderscutGetData(benderscut);
555 assert( benderscutdata != NULL );
556
557 if( benderscutdata->firstcut != NULL )
558 SCIPfreeBlockMemoryArray(scip, &benderscutdata->firstcut, benderscutdata->nsubproblems);
559
560 if( benderscutdata->subprobconstant != NULL)
561 SCIPfreeBlockMemoryArray(scip, &benderscutdata->subprobconstant, benderscutdata->nsubproblems);
562
563 return SCIP_OKAY;
564}
565
566/** execution method of Benders' decomposition cuts */
567static
568SCIP_DECL_BENDERSCUTEXEC(benderscutExecInt)
569{ /*lint --e{715}*/
570 SCIP* subproblem;
571 SCIP_BENDERSCUTDATA* benderscutdata;
572
573 assert(scip != NULL);
574 assert(benders != NULL);
575 assert(benderscut != NULL);
576 assert(result != NULL);
577
578 subproblem = SCIPbendersSubproblem(benders, probnumber);
579
580 if( subproblem == NULL )
581 {
582 SCIPdebugMsg(scip, "The subproblem %d is set to NULL. The <%s> Benders' decomposition cut can not be executed.\n",
583 probnumber, BENDERSCUT_NAME);
584
585 (*result) = SCIP_DIDNOTRUN;
586 return SCIP_OKAY;
587 }
588
589 /* retrieving the Benders' cut data */
590 benderscutdata = SCIPbenderscutGetData(benderscut);
591 assert(benderscutdata != NULL);
592
593 /* if the Benders' cut data has not been created, then it is created now */
594 if( !benderscutdata->created )
595 {
596 SCIP_CALL( createBenderscutData(scip, benderscutdata) );
597 }
598
599 /* it is only possible to generate the Laporte and Louveaux cuts when the linking variables are all binary */
600 if( !benderscutdata->subprobsvalid )
601 {
602 SCIPinfoMessage(scip, NULL, "The integer optimality cuts can only be applied to problems "
603 "where all linking variables are binary. The integer optimality cuts will be disabled.\n");
604
605 SCIPbenderscutSetEnabled(benderscut, FALSE);
606
607 return SCIP_OKAY;
608 }
609
610 /* the integer subproblem could terminate early if the auxiliary variable value is much greater than the optimal
611 * solution. As such, it is only necessary to generate a cut if the subproblem is OPTIMAL */
612 if( SCIPgetStatus(subproblem) == SCIP_STATUS_OPTIMAL )
613 {
614 /* generating a cut for a given subproblem */
615 SCIP_CALL( generateAndApplyBendersIntegerCuts(scip, benders, benderscut, sol, probnumber, type, result, FALSE) );
616 }
617
618 return SCIP_OKAY;
619}
620
621
622/*
623 * Benders' decomposition cuts specific interface methods
624 */
625
626/** creates the int Benders' decomposition cuts and includes it in SCIP */
628 SCIP* scip, /**< SCIP data structure */
629 SCIP_BENDERS* benders /**< Benders' decomposition */
630 )
631{
632 SCIP_BENDERSCUTDATA* benderscutdata;
633 SCIP_BENDERSCUT* benderscut;
635
636 assert(benders != NULL);
637
638 /* create int Benders' decomposition cuts data */
639 SCIP_CALL( SCIPallocBlockMemory(scip, &benderscutdata) );
640 BMSclearMemory(benderscutdata);
641 benderscutdata->benders = benders;
642
643 benderscut = NULL;
644
645 /* include Benders' decomposition cuts */
647 BENDERSCUT_PRIORITY, BENDERSCUT_LPCUT, benderscutExecInt, benderscutdata) );
648
649 assert(benderscut != NULL);
650
651 /* set non fundamental callbacks via setter functions */
652 SCIP_CALL( SCIPsetBenderscutFree(scip, benderscut, benderscutFreeInt) );
653 SCIP_CALL( SCIPsetBenderscutExit(scip, benderscut, benderscutExitInt) );
654
655 /* add int Benders' decomposition cuts parameters */
656 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/cutsconstant",
659 "the constant term of the integer Benders' cuts.",
660 &benderscutdata->cutconstant, FALSE, SCIP_DEFAULT_CUTCONSTANT, -SCIPinfinity(scip), SCIPinfinity(scip),
661 paramChgdBenderscutintConstant, (SCIP_PARAMDATA*)benderscutdata) );
662
663 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/addcuts",
666 "should cuts be generated and added to the cutpool instead of global constraints directly added to the problem.",
667 &benderscutdata->addcuts, FALSE, SCIP_DEFAULT_ADDCUTS, NULL, NULL) );
668
669 return SCIP_OKAY;
670}
#define SCIP_DEFAULT_ADDCUTS
#define BENDERSCUT_LPCUT
static SCIP_DECL_BENDERSCUTFREE(benderscutFreeInt)
static SCIP_RETCODE computeStandardIntegerOptCut(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_SOL *sol, SCIP_CONS *cons, SCIP_ROW *row, SCIP_Real cutconstant, int probnumber, SCIP_Bool addcut, SCIP_Bool *success)
static SCIP_DECL_BENDERSCUTEXEC(benderscutExecInt)
#define BENDERSCUT_PRIORITY
#define BENDERSCUT_DESC
#define BENDERSCUT_NAME
static SCIP_DECL_BENDERSCUTEXIT(benderscutExitInt)
#define SCIP_DEFAULT_CUTCONSTANT
static SCIP_RETCODE createBenderscutData(SCIP *scip, SCIP_BENDERSCUTDATA *benderscutdata)
static SCIP_RETCODE generateAndApplyBendersIntegerCuts(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, SCIP_SOL *sol, int probnumber, SCIP_BENDERSENFOTYPE type, SCIP_RESULT *result, SCIP_Bool initcons)
static void updateSubproblemCutConstant(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_BENDERSCUTDATA *benderscutdata, int probnumber)
static SCIP_DECL_PARAMCHGD(paramChgdBenderscutintConstant)
static SCIP_RETCODE addAuxiliaryVariableToCut(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_CONS *cons, SCIP_ROW *row, int probnumber, SCIP_Bool addcut)
Generates a Laporte and Louveaux Benders' decomposition integer cut.
Constraint handler for linear constraints in their most general form, .
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#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_LONGINT_FORMAT
Definition: def.h:148
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPincludeBenderscutInt(SCIP *scip, SCIP_BENDERS *benders)
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Real SCIPgetActivityLinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
SCIP_RETCODE SCIPchgLhsLinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:562
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3274
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
Definition: scip_prob.c:1400
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
#define SCIPdebugMsg
Definition: scip_message.h:78
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_VAR * SCIPbendersGetAuxiliaryVar(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6213
SCIP_RETCODE SCIPgetBendersSubproblemVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar, int probnumber)
Definition: scip_benders.c:721
const char * SCIPbendersGetName(SCIP_BENDERS *benders)
Definition: benders.c:5967
int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
Definition: benders.c:6011
SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6021
void SCIPbendersGetSubproblemMasterVarsData(SCIP_BENDERS *benders, int probnumber, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars)
Definition: benders.c:6259
SCIP_RETCODE SCIPcheckBendersSubproblemOptimality(SCIP *scip, SCIP_BENDERS *benders, SCIP_SOL *sol, int probnumber, SCIP_Bool *optimal)
Definition: scip_benders.c:917
SCIP_Real SCIPbendersGetSubproblemObjval(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6302
SCIP_Real SCIPbendersGetSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6893
SCIP_RETCODE SCIPincludeBenderscutBasic(SCIP *scip, SCIP_BENDERS *benders, SCIP_BENDERSCUT **benderscutptr, const char *name, const char *desc, int priority, SCIP_Bool islpcut, SCIP_DECL_BENDERSCUTEXEC((*benderscutexec)), SCIP_BENDERSCUTDATA *benderscutdata)
SCIP_RETCODE SCIPsetBenderscutExit(SCIP *scip, SCIP_BENDERSCUT *benderscut, SCIP_DECL_BENDERSCUTEXIT((*benderscutexit)))
SCIP_RETCODE SCIPsetBenderscutFree(SCIP *scip, SCIP_BENDERSCUT *benderscut, SCIP_DECL_BENDERSCUTFREE((*benderscutfree)))
void SCIPbenderscutSetData(SCIP_BENDERSCUT *benderscut, SCIP_BENDERSCUTDATA *benderscutdata)
Definition: benderscut.c:413
const char * SCIPbenderscutGetName(SCIP_BENDERSCUT *benderscut)
Definition: benderscut.c:492
SCIP_BENDERSCUTDATA * SCIPbenderscutGetData(SCIP_BENDERSCUT *benderscut)
Definition: benderscut.c:403
SCIP_Longint SCIPbenderscutGetNFound(SCIP_BENDERSCUT *benderscut)
Definition: benderscut.c:543
void SCIPbenderscutSetEnabled(SCIP_BENDERSCUT *benderscut, SCIP_Bool enabled)
Definition: benderscut.c:593
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_RETCODE SCIPsetConsDynamic(SCIP *scip, SCIP_CONS *cons, SCIP_Bool dynamic)
Definition: scip_cons.c:1449
SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable)
Definition: scip_cons.c:1474
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:336
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:225
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#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_RETCODE SCIPchgRowLhs(SCIP *scip, SCIP_ROW *row, SCIP_Real lhs)
Definition: scip_lp.c:1529
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1367
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2176
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2108
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2981
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1892
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10827
static const char * paramname[]
Definition: lpi_msk.c:5172
#define BMSclearMemory(ptr)
Definition: memory.h:129
SCIP_PARAMDATA * SCIPparamGetData(SCIP_PARAM *param)
Definition: paramset.c:678
public methods for Benders' decomposition
public methods for Benders' decomposition cuts
public methods for LP management
public methods for message output
#define SCIPdebug(x)
Definition: pub_message.h:93
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
public data structures and miscellaneous methods
public methods for handling parameter settings
public methods for problem variables
public methods for Benders decomposition
public methods for constraint handler plugins and constraints
public methods for cuts and aggregation rows
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 global and local (sub)problems
public methods for solutions
@ SCIP_BENDERSENFOTYPE_RELAX
Definition: type_benders.h:52
@ SCIP_BENDERSENFOTYPE_LP
Definition: type_benders.h:51
@ SCIP_BENDERSENFOTYPE_CHECK
Definition: type_benders.h:54
@ SCIP_BENDERSENFOTYPE_PSEUDO
Definition: type_benders.h:53
enum SCIP_BendersEnfoType SCIP_BENDERSENFOTYPE
Definition: type_benders.h:56
struct SCIP_BenderscutData SCIP_BENDERSCUTDATA
struct SCIP_ParamData SCIP_PARAMDATA
Definition: type_paramset.h:87
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_CONSADDED
Definition: type_result.h:52
@ SCIP_SEPARATED
Definition: type_result.h:49
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_INITSOLVE
Definition: type_set.h:52
@ SCIP_STATUS_OPTIMAL
Definition: type_stat.h:43