SCIP Doxygen Documentation
Loading...
Searching...
No Matches
benders.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-2026 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 benders.c
26 * @ingroup OTHER_CFILES
27 * @brief methods for Benders' decomposition
28 * @author Stephen J. Maher
29 */
30
31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32
33#include "scip/def.h"
34#include "scip/set.h"
35#include "scip/clock.h"
36#include "scip/dcmp.h"
37#include "scip/paramset.h"
38#include "scip/lp.h"
39#include "scip/prob.h"
40#include "scip/pricestore.h"
41#include "scip/scip.h"
42#include "scip/scipdefplugins.h"
43#include "scip/benders.h"
44#include "scip/pub_benders.h"
45#include "scip/pub_message.h"
46#include "scip/pub_misc.h"
47#include "scip/cons_linear.h"
48#include "scip/cons_nonlinear.h"
49
50#include "scip/struct_benders.h"
52
53#include "scip/benderscut.h"
54
55/* Defaults for parameters */
56#define SCIP_DEFAULT_TRANSFERCUTS FALSE /** should Benders' cuts generated in LNS heuristics be transferred to the main SCIP instance? */
57#define SCIP_DEFAULT_CUTSASCONSS TRUE /** should the transferred cuts be added as constraints? */
58#define SCIP_DEFAULT_LNSCHECK TRUE /** should the Benders' decomposition be used in LNS heuristics */
59#define SCIP_DEFAULT_LNSMAXDEPTH -1 /** maximum depth at which the LNS check is performed */
60#define SCIP_DEFAULT_LNSMAXCALLS 10 /** the maximum number of Benders' decomposition calls in LNS heuristics */
61#define SCIP_DEFAULT_LNSMAXCALLSROOT 0 /** the maximum number of root node Benders' decomposition calls in LNS heuristics */
62#define SCIP_DEFAULT_SUBPROBFRAC 1.0 /** fraction of subproblems that are solved in each iteration */
63#define SCIP_DEFAULT_UPDATEAUXVARBOUND FALSE /** should the auxiliary variable lower bound be updated by solving the subproblem */
64#define SCIP_DEFAULT_AUXVARSIMPLINT FALSE /** set the auxiliary variables as implint if the subproblem objective is integer */
65#define SCIP_DEFAULT_CUTCHECK TRUE /** should cuts be generated during the checking of solutions? */
66#define SCIP_DEFAULT_STRENGTHENMULT 0.5 /** the convex combination multiplier for the cut strengthening */
67#define SCIP_DEFAULT_NOIMPROVELIMIT 5 /** the maximum number of cut strengthening without improvement */
68#define SCIP_DEFAULT_STRENGTHENPERTURB 1e-06 /** the amount by which the cut strengthening solution is perturbed */
69#define SCIP_DEFAULT_STRENGTHENENABLED FALSE /** enable the core point cut strengthening approach */
70#define SCIP_DEFAULT_STRENGTHENINTPOINT 'r' /** where should the strengthening interior point be sourced from ('l'p relaxation, 'f'irst solution, 'i'ncumbent solution, 'r'elative interior point, vector of 'o'nes, vector of 'z'eros) */
71#ifdef SCIP_DISABLED_CODE /* temporarily disabling support for multiple threads in Benders' decomposition */
72#define SCIP_DEFAULT_NUMTHREADS 1 /** the number of parallel threads to use when solving the subproblems */
73#endif
74#define SCIP_DEFAULT_EXECFEASPHASE FALSE /** should a feasibility phase be executed during the root node processing */
75#define SCIP_DEFAULT_SLACKVARCOEF 1e+6 /** the initial objective coefficient of the slack variables in the subproblem */
76#define SCIP_DEFAULT_MAXSLACKVARCOEF 1e+9 /** the maximal objective coefficient of the slack variables in the subproblem */
77#define SCIP_DEFAULT_CHECKCONSCONVEXITY TRUE /** should the constraints of the subproblem be checked for convexity? */
78#define SCIP_DEFAULT_NLPITERLIMIT 10000 /** iteration limit for NLP solver */
79
80#define BENDERS_MAXPSEUDOSOLS 5 /** the maximum number of pseudo solutions checked before suggesting
81 * merge candidates */
82#define BENDERS_MASTERVARARRAYSIZE 100 /**< the initial size of the submastervars arrays */
83#define BENDERS_ARRAYSIZE 1000 /**< the initial size of the added constraints/cuts arrays */
85#define AUXILIARYVAR_NAME "##bendersauxiliaryvar" /** the name for the Benders' auxiliary variables in the master problem */
86#define SLACKVAR_NAME "##bendersslackvar" /** the name for the Benders' slack variables added to each
87 * constraints in the subproblems */
88#define NLINEARCONSHDLRS 5
90/* event handler properties */
91#define NODEFOCUS_EVENTHDLR_NAME "bendersnodefocus"
92#define NODEFOCUS_EVENTHDLR_DESC "node focus event handler for Benders' decomposition"
94#define MIPNODEFOCUS_EVENTHDLR_NAME "bendersmipsolvenodefocus"
95#define MIPNODEFOCUS_EVENTHDLR_DESC "node focus event handler for the MIP solve method for Benders' decomposition"
97#define UPPERBOUND_EVENTHDLR_NAME "bendersupperbound"
98#define UPPERBOUND_EVENTHDLR_DESC "found solution event handler to terminate subproblem solve for a given upper bound"
100#define NODESOLVED_EVENTHDLR_NAME "bendersnodesolved"
101#define NODESOLVED_EVENTHDLR_DESC "node solved event handler for the Benders' integer cuts"
102
103
104/** event handler data */
105struct SCIP_EventhdlrData
106{
107 int filterpos; /**< the event filter entry */
108 int numruns; /**< the number of times that the problem has been solved */
109 SCIP_Real upperbound; /**< an upper bound for the problem */
110 SCIP_Bool solvecip; /**< is the event called from a MIP subproblem solve*/
111};
112
113
114/* ---------------- Local methods for event handlers ---------------- */
115
116/** initialises the members of the eventhandler data */
117static
119 SCIP* scip, /**< the SCIP data structure */
120 SCIP_EVENTHDLRDATA* eventhdlrdata /**< the event handler data */
121 )
122{
123 assert(scip != NULL);
124 assert(eventhdlrdata != NULL);
125
126 eventhdlrdata->filterpos = -1;
127 eventhdlrdata->numruns = 0;
128 eventhdlrdata->upperbound = -SCIPinfinity(scip);
129 eventhdlrdata->solvecip = FALSE;
130
131 return SCIP_OKAY;
132}
133
134/** initsol method for the event handlers */
135static
137 SCIP* scip, /**< the SCIP data structure */
138 SCIP_EVENTHDLR* eventhdlr, /**< the event handlers data structure */
139 SCIP_EVENTTYPE eventtype /**< event type mask to select events to catch */
140 )
141{
142 SCIP_EVENTHDLRDATA* eventhdlrdata;
143
144 assert(scip != NULL);
145 assert(eventhdlr != NULL);
146
147 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
148
149 SCIP_CALL( SCIPcatchEvent(scip, eventtype, eventhdlr, NULL, &eventhdlrdata->filterpos) );
150
151 return SCIP_OKAY;
152}
153
154/** the exit sol method for the event handlers */
155static
157 SCIP* scip, /**< the SCIP data structure */
158 SCIP_EVENTHDLR* eventhdlr, /**< the event handlers data structure */
159 SCIP_EVENTTYPE eventtype /**< event type mask to select events to catch */
160 )
161{
162 SCIP_EVENTHDLRDATA* eventhdlrdata;
163
164 assert(scip != NULL);
165 assert(eventhdlr != NULL);
166
167 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
168
169 if( eventhdlrdata->filterpos >= 0 )
170 {
171 SCIP_CALL( SCIPdropEvent(scip, eventtype, eventhdlr, NULL, eventhdlrdata->filterpos) );
172 eventhdlrdata->filterpos = -1;
173 }
174
175 return SCIP_OKAY;
176}
177
178/** the exit method for the event handlers */
179static
181 SCIP* scip, /**< the SCIP data structure */
182 SCIP_EVENTHDLR* eventhdlr /**< the event handlers data structure */
183 )
184{
185 SCIP_EVENTHDLRDATA* eventhdlrdata;
186
187 assert(scip != NULL);
188 assert(eventhdlr != NULL);
189
190 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
191
192 /* reinitialise the event handler data */
193 SCIP_CALL( initEventhandlerData(scip, eventhdlrdata) );
194
195 return SCIP_OKAY;
196}
197
198/** free method for the event handler */
199static
201 SCIP* scip, /**< the SCIP data structure */
202 SCIP_EVENTHDLR* eventhdlr /**< the event handlers data structure */
203 )
204{
205 SCIP_EVENTHDLRDATA* eventhdlrdata;
206
207 assert(scip != NULL);
208 assert(eventhdlr != NULL);
209
210 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
211 assert(eventhdlrdata != NULL);
212
213 SCIPfreeBlockMemory(scip, &eventhdlrdata);
214
215 SCIPeventhdlrSetData(eventhdlr, NULL);
216
217 return SCIP_OKAY;
218}
219
220
221
222/* ---------------- Callback methods of node focus event handler ---------------- */
223
224/** exec the event handler */
225static
226SCIP_DECL_EVENTEXEC(eventExecBendersNodefocus)
227{ /*lint --e{715}*/
228 SCIP_EVENTHDLRDATA* eventhdlrdata;
229
230 assert(scip != NULL);
231 assert(eventhdlr != NULL);
232
234
235 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
236
237 /* sending an interrupt solve signal to return the control back to the Benders' decomposition plugin.
238 * This will ensure the SCIP stage is SCIP_STAGE_SOLVING, allowing the use of probing mode. */
240
241 SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_NODEFOCUSED, eventhdlr, NULL, eventhdlrdata->filterpos) );
242 eventhdlrdata->filterpos = -1;
243
244 return SCIP_OKAY;
245}
246
247/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
248static
249SCIP_DECL_EVENTINITSOL(eventInitsolBendersNodefocus)
250{
251 assert(scip != NULL);
252 assert(eventhdlr != NULL);
253
255
257
258 return SCIP_OKAY;
259}
260
261/** solving process deinitialization method of event handler (called before branch and bound process data is freed) */
262static
263SCIP_DECL_EVENTEXITSOL(eventExitsolBendersNodefocus)
264{
265 assert(scip != NULL);
266 assert(eventhdlr != NULL);
267
269
271
272 return SCIP_OKAY;
273}
274
275/** deinitialization method of event handler (called before transformed problem is freed) */
276static
277SCIP_DECL_EVENTEXIT(eventExitBendersNodefocus)
278{
279 assert(scip != NULL);
280 assert(eventhdlr != NULL);
281
283
284 SCIP_CALL( exitEventhandler(scip, eventhdlr) );
285
286 return SCIP_OKAY;
287}
288
289/** deinitialization method of event handler (called before transformed problem is freed) */
290static
291SCIP_DECL_EVENTFREE(eventFreeBendersNodefocus)
292{
293 assert(scip != NULL);
294 assert(eventhdlr != NULL);
295
297
298 SCIP_CALL( freeEventhandler(scip, eventhdlr) );
299
300 return SCIP_OKAY;
301}
302
303
304/* ---------------- Callback methods of MIP solve node focus event handler ---------------- */
305
306/** exec the event handler */
307static
308SCIP_DECL_EVENTEXEC(eventExecBendersMipnodefocus)
309{ /*lint --e{715}*/
310 SCIP_EVENTHDLRDATA* eventhdlrdata;
311
312 assert(scip != NULL);
313 assert(eventhdlr != NULL);
314
316
317 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
318
319 /* interrupting the solve so that the control is returned back to the Benders' core. */
320 if( eventhdlrdata->numruns == 0 && !eventhdlrdata->solvecip )
321 {
323 }
324
325 SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_NODEFOCUSED, eventhdlr, NULL, eventhdlrdata->filterpos) );
326 eventhdlrdata->filterpos = -1;
327
328 eventhdlrdata->numruns++;
329
330 return SCIP_OKAY;
331}
332
333/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
334static
335SCIP_DECL_EVENTINITSOL(eventInitsolBendersMipnodefocus)
336{
337 assert(scip != NULL);
338 assert(eventhdlr != NULL);
339
341
343
344 return SCIP_OKAY;
345}
346
347/** solving process deinitialization method of event handler (called before branch and bound process data is freed) */
348static
349SCIP_DECL_EVENTEXITSOL(eventExitsolBendersMipnodefocus)
350{
351 assert(scip != NULL);
352 assert(eventhdlr != NULL);
353
355
357
358 return SCIP_OKAY;
359}
360
361/** deinitialization method of event handler (called before transformed problem is freed) */
362static
363SCIP_DECL_EVENTEXIT(eventExitBendersMipnodefocus)
364{
365 assert(scip != NULL);
366 assert(eventhdlr != NULL);
367
369
370 SCIP_CALL( exitEventhandler(scip, eventhdlr) );
371
372 return SCIP_OKAY;
373}
374
375/** deinitialization method of event handler (called before transformed problem is freed) */
376static
377SCIP_DECL_EVENTFREE(eventFreeBendersMipnodefocus)
378{
379 assert(scip != NULL);
380 assert(eventhdlr != NULL);
381
383
384 SCIP_CALL( freeEventhandler(scip, eventhdlr) );
385
386 return SCIP_OKAY;
387}
388
389/* ---------------- Callback methods of solution found event handler ---------------- */
390
391/** exec the event handler */
392static
393SCIP_DECL_EVENTEXEC(eventExecBendersUpperbound)
394{ /*lint --e{715}*/
395 SCIP_EVENTHDLRDATA* eventhdlrdata;
396 SCIP_SOL* bestsol;
397
398 assert(scip != NULL);
399 assert(eventhdlr != NULL);
400
402
403 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
404 assert(eventhdlrdata != NULL);
405
406 bestsol = SCIPgetBestSol(scip);
407
408 if( SCIPisLT(scip, SCIPgetSolOrigObj(scip, bestsol)*(int)SCIPgetObjsense(scip), eventhdlrdata->upperbound) )
409 {
411 }
412
413 return SCIP_OKAY;
414}
415
416/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
417static
418SCIP_DECL_EVENTINITSOL(eventInitsolBendersUpperbound)
419{
420 assert(scip != NULL);
421 assert(eventhdlr != NULL);
422
424
426
427 return SCIP_OKAY;
428}
429
430/** solving process deinitialization method of event handler (called before branch and bound process data is freed) */
431static
432SCIP_DECL_EVENTEXITSOL(eventExitsolBendersUpperbound)
433{
434 assert(scip != NULL);
435 assert(eventhdlr != NULL);
436
438
440
441 return SCIP_OKAY;
442}
443
444/** deinitialization method of event handler (called before transformed problem is freed) */
445static
446SCIP_DECL_EVENTEXIT(eventExitBendersUpperbound)
447{
448 assert(scip != NULL);
449 assert(eventhdlr != NULL);
450
452
453 SCIP_CALL( exitEventhandler(scip, eventhdlr) );
454
455 return SCIP_OKAY;
456}
457
458/** deinitialization method of event handler (called before transformed problem is freed) */
459static
460SCIP_DECL_EVENTFREE(eventFreeBendersUpperbound)
461{
462 assert(scip != NULL);
463 assert(eventhdlr != NULL);
464
466
467 SCIP_CALL( freeEventhandler(scip, eventhdlr) );
468
469 return SCIP_OKAY;
470}
471
472/** updates the upper bound in the event handler data */
473static
475 SCIP_BENDERS* benders, /**< Benders' decomposition */
476 int probnumber, /**< the subproblem number */
477 SCIP_Real upperbound /**< the upper bound value */
478 )
479{
480 SCIP_EVENTHDLR* eventhdlr;
481 SCIP_EVENTHDLRDATA* eventhdlrdata;
482
483 assert(benders != NULL);
484 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
485
486 eventhdlr = SCIPfindEventhdlr(SCIPbendersSubproblem(benders, probnumber), UPPERBOUND_EVENTHDLR_NAME);
487 assert(eventhdlr != NULL);
488
489 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
490 assert(eventhdlrdata != NULL);
491
492 eventhdlrdata->upperbound = upperbound;
493
494 return SCIP_OKAY;
495}
496
497/* ---------------- Callback methods of the node solved event handler ---------------- */
498
499/** Updates the cut constant of the Benders' cuts data.
500 * This function solves the master problem with only the auxiliary variables in the objective function.
501 */
502static
504 SCIP* masterprob, /**< the SCIP instance of the master problem */
505 SCIP_BENDERS* benders /**< Benders' decomposition */
506 )
507{
508 SCIP_VAR** vars;
509 int nvars;
510 int nsubproblems;
511 int i;
514
515 assert(masterprob != NULL);
516 assert(benders != NULL);
517
518 /* don't run in probing or in repropagation */
519 if( SCIPinProbing(masterprob) || SCIPinRepropagation(masterprob) || SCIPinDive(masterprob) )
520 return SCIP_OKAY;
521
522 nsubproblems = SCIPbendersGetNSubproblems(benders);
523
524 SCIP_CALL( SCIPstartProbing(masterprob) );
525
526 /* change the master problem variables to 0 */
527 nvars = SCIPgetNVars(masterprob);
528 vars = SCIPgetVars(masterprob);
529
530 /* setting the objective function coefficient to 0 for all variables */
531 for( i = 0; i < nvars; i++ )
532 {
534 {
535 SCIP_CALL( SCIPchgVarObjProbing(masterprob, vars[i], 0.0) );
536 }
537 }
538
539 /* solving an LP for all subproblems to find the lower bound */
540 for( i = 0; i < nsubproblems; i++)
541 {
542 SCIP_VAR* auxiliaryvar;
543
544 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, i);
545
546 if( SCIPvarGetStatus(auxiliaryvar) != SCIP_VARSTATUS_COLUMN )
547 continue;
548
549 SCIP_CALL( SCIPchgVarObjProbing(masterprob, auxiliaryvar, 1.0) );
550
551 /* solving the probing LP to get a lower bound on the auxiliary variables */
552 SCIP_CALL( SCIPsolveProbingLP(masterprob, -1, &lperror, &cutoff) );
553
554 if( !SCIPisInfinity(masterprob, -SCIPgetSolTransObj(masterprob, NULL)) )
556
557 SCIPdebugMsg(masterprob, "Cut constant for subproblem %d: %g\n", i,
559
560 SCIP_CALL( SCIPchgVarObjProbing(masterprob, auxiliaryvar, 0.0) );
561 }
562
563 SCIP_CALL( SCIPendProbing(masterprob) );
564
565 return SCIP_OKAY;
566}
567
568/** exec the event handler */
569static
570SCIP_DECL_EVENTEXEC(eventExecBendersNodesolved)
571{ /*lint --e{715}*/
572 SCIP_BENDERS* benders;
573
574 assert(scip != NULL);
575 assert(eventhdlr != NULL);
576
578
579 benders = (SCIP_BENDERS*)SCIPeventhdlrGetData(eventhdlr); /*lint !e826*/
580
581 if( SCIPbendersGetNSubproblems(benders) > 0
583 {
585 }
586
588
589 return SCIP_OKAY;
590}
591
592/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
593static
594SCIP_DECL_EVENTINITSOL(eventInitsolBendersNodesolved)
595{
596 SCIP_BENDERS* benders;
597
598 assert(scip != NULL);
599 assert(eventhdlr != NULL);
600
602
603 /* getting the Benders' decomposition data structure */
604 benders = (SCIP_BENDERS*)SCIPeventhdlrGetData(eventhdlr); /*lint !e826*/
605
606 /* The event is only caught if there is an active Benders' decomposition, the integer subproblem are solved and
607 * the Benders' decomposition has not been copied in thread safe mode
608 */
610 && !benders->threadsafe )
611 {
613 }
614
615 return SCIP_OKAY;
616}
617
618
619/* ---------------- Methods for the parallelisation of Benders' decomposition ---------------- */
620
621/** comparison method for sorting the subproblems.
622 * The subproblem that has been called the least is prioritised
623 */
624static
625SCIP_DECL_SORTPTRCOMP(benderssubcompdefault)
626{
627 SCIP_SUBPROBLEMSOLVESTAT* solvestat1;
628 SCIP_SUBPROBLEMSOLVESTAT* solvestat2;
629
630 assert(elem1 != NULL);
631 assert(elem2 != NULL);
632
633 solvestat1 = (SCIP_SUBPROBLEMSOLVESTAT*)elem1;
634 solvestat2 = (SCIP_SUBPROBLEMSOLVESTAT*)elem2;
635
636 /* prefer subproblems with fewer calls, using the index as tie breaker */
637 if( MAX(solvestat1->ncalls, solvestat2->ncalls) == 0 )
638 return solvestat1->idx - solvestat2->idx;
639 else if( solvestat1->ncalls != solvestat2->ncalls )
640 return solvestat1->ncalls - solvestat2->ncalls;
641 else
642 {
643 /* prefer the harder problem (with more average iterations) */
644 int avgiterdiff = (int)solvestat2->avgiter - (int)solvestat1->avgiter;
645
646 if( avgiterdiff != 0 )
647 return avgiterdiff;
648
649 return solvestat1->idx - solvestat2->idx;
650 }
651
652/* the code below does not give a total order of the elements */
653#ifdef SCIP_DISABLED_CODE
654 if( solvestat1->ncalls == 0 )
655 if( solvestat2->ncalls == 0 )
656 if( solvestat1->idx < solvestat2->idx )
657 return -1;
658 else
659 return 1;
660 else
661 return -1;
662 else if( solvestat2->ncalls == 0 )
663 return 1;
664 else
665 {
666 if( solvestat1->ncalls < solvestat2->ncalls )
667 return -1;
668 else if( solvestat2->ncalls < solvestat1->ncalls )
669 return 1;
670 else
671 {
672 /* we want to execute the hard subproblems first */
673 if( solvestat1->avgiter > solvestat2->avgiter )
674 return 1;
675 else
676 return -1;
677 }
678 }
679#endif
680}
681
682/* Local methods */
683
684/** A workaround for GCG. This is a temp vardata that is set for the auxiliary variables */
685struct SCIP_VarData
686{
687 int vartype; /**< the variable type. In GCG this indicates whether the variable is a
688 * master problem or subproblem variable. */
689};
690
691/** adds the auxiliary variables to the Benders' decomposition master problem */
692static
694 SCIP* scip, /**< SCIP data structure */
695 SCIP_BENDERS* benders /**< Benders' decomposition structure */
696 )
697{
698 SCIP_BENDERS* topbenders; /* the highest priority Benders' decomposition */
699 SCIP_VAR* auxiliaryvar;
700 SCIP_CONS* cons;
701 SCIP_VARDATA* vardata;
702 char varname[SCIP_MAXSTRLEN]; /* the name of the auxiliary variable */
703 char consname[SCIP_MAXSTRLEN]; /* the name of the auxiliary variable constraint */
704 SCIP_Bool shareauxvars;
705 SCIP_Bool allsubprobintegralobj;
706 int i;
707
708 /* this is a workaround for GCG. GCG expects that the variable has vardata when added. So a dummy vardata is created */
709 SCIP_CALL( SCIPallocBlockMemory(scip, &vardata) );
710 vardata->vartype = -1;
711
712 /* getting the highest priority Benders' decomposition */
713 topbenders = SCIPgetBenders(scip)[0];
714
715 /* if the current Benders is the highest priority Benders, then we need to create the auxiliary variables.
716 * Otherwise, if the shareauxvars flag is set, then the auxiliary variables from the highest priority Benders' are
717 * stored with this Benders. */
718 shareauxvars = FALSE;
719 if( topbenders != benders && SCIPbendersShareAuxVars(benders) )
720 shareauxvars = TRUE;
721
722 /* creating the auxiliary variable objective sum constraint. If the auxiliary variables are shared, then the constraint
723 * is only added to the top Benders. Otherwise, it is created for each Benders implementation. */
724 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM )
725 {
726 if( shareauxvars )
727 {
728 benders->auxiliaryvarcons = topbenders->auxiliaryvarcons;
729 }
730 else
731 {
732 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_%s", AUXILIARYVAR_NAME, SCIPbendersGetName(benders) );
733 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, consname, 0, NULL, NULL, 0.0, 0.0) );
734 SCIP_CALL( SCIPaddCons(scip, cons) );
735
736 benders->auxiliaryvarcons[0] = cons;
737 }
738 }
739
740 /* sharing or creating the master auxiliary variable */
741 if( shareauxvars )
742 {
743 benders->masterauxvar = topbenders->masterauxvar;
744
745 SCIP_CALL( SCIPcaptureVar(scip, topbenders->masterauxvar) );
746 }
747 else
748 {
749 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "master_%s_%s", AUXILIARYVAR_NAME, SCIPbendersGetName(benders) );
752
753 SCIPvarSetData(benders->masterauxvar, vardata);
754
756
757 /* adding the down lock for the Benders' decomposition constraint handler */
759
760 /* adding the master auxiliary variable to the summation constraint */
761 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM )
762 {
763 SCIP_CALL( SCIPaddCoefLinear(scip, benders->auxiliaryvarcons[0], benders->masterauxvar, 1.0) );
764 }
765 }
766
767 allsubprobintegralobj = TRUE;
768
769 for( i = 0; i < SCIPbendersGetNSubproblems(benders); i++ )
770 {
771 /* if the auxiliary variables are shared, then a pointer to the variable is retrieved from topbenders,
772 * otherwise the auxiliaryvariable is created. The auxiliary variable constraint is also copied from the
773 * topbenders if the auxiliary variables are shared. */
774 if( shareauxvars )
775 {
776 auxiliaryvar = SCIPbendersGetAuxiliaryVar(topbenders, i);
777
778 SCIP_CALL( SCIPcaptureVar(scip, auxiliaryvar) );
779
780 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX )
781 {
782 benders->auxiliaryvarcons[i] = topbenders->auxiliaryvarcons[i];
783
785 }
786 }
787 else
788 {
789 SCIP_IMPLINTTYPE impltype;
790
791 /* declare an auxiliary variable implied integral if the objective function of the
792 * subproblem is guaranteed to be integral and this is desired
793 * NOTE: It is only possible to determine if the objective function is integral if the subproblem is defined as
794 * a SCIP instance, i.e. not NULL.
795 */
796 if( benders->auxvarsimplint && SCIPbendersSubproblem(benders, i) != NULL
798 impltype = SCIP_IMPLINTTYPE_WEAK;
799 else
800 {
801 impltype = SCIP_IMPLINTTYPE_NONE;
802 allsubprobintegralobj = FALSE;
803 }
804
805 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s_%d_%s", AUXILIARYVAR_NAME, i, SCIPbendersGetName(benders) );
806 SCIP_CALL( SCIPcreateVarImpl(scip, &auxiliaryvar, varname, benders->subproblowerbound[i], SCIPinfinity(scip), 0.0,
808
809 SCIPvarSetData(auxiliaryvar, vardata);
810
811 SCIP_CALL( SCIPaddVar(scip, auxiliaryvar) );
812
813 /* adding the down lock for the Benders' decomposition constraint handler */
814 SCIP_CALL( SCIPaddVarLocksType(scip, auxiliaryvar, SCIP_LOCKTYPE_MODEL, 1, 0) );
815
816 /* if the objective type is minimax, then we need to create the auxiliary variable constraints and add the
817 * auxiliary variable to them. If the objective type is sum, then the auxiliary variables are added to the
818 * objective constraint.
819 */
820 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX )
821 {
822 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_%d_%s", AUXILIARYVAR_NAME, i, SCIPbendersGetName(benders) );
823 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, consname, 0, NULL, NULL, 0.0, SCIPinfinity(scip)) );
824 SCIP_CALL( SCIPaddCons(scip, cons) );
825
826 /* adding the coefficients to the constraint */
827 SCIP_CALL( SCIPaddCoefLinear(scip, cons, benders->masterauxvar, 1.0) );
828 SCIP_CALL( SCIPaddCoefLinear(scip, cons, auxiliaryvar, -1.0) );
829
830 benders->auxiliaryvarcons[i] = cons;
831 }
832 else
833 {
835
836 SCIP_CALL( SCIPaddCoefLinear(scip, benders->auxiliaryvarcons[0], auxiliaryvar, -1.0) );
837 }
838 }
839
840 benders->auxiliaryvars[i] = auxiliaryvar;
841 }
842
843 if( !shareauxvars && allsubprobintegralobj )
844 {
845 SCIP_Bool infeasible;
847 assert(!infeasible);
848 }
849
850 SCIPfreeBlockMemory(scip, &vardata);
851
852 return SCIP_OKAY;
853}
854
855
856/** finds the Benders' auxiliary variable for a given sub-SCIP. If probnumber is -1, then the master auxiliary variable
857 * is returned.
858 */
859static
861 SCIP* scip, /**< SCIP data structure, the target scip */
862 SCIP_BENDERS* benders, /**< the Benders' decomposition that the variable belongs to */
863 SCIP_VAR** targetvar, /**< the variable that will be returned */
864 int subscipdepth, /**< the depth of the current sub-SCIP */
865 int probnumber /**< the number of the subproblem, or -1 for the master auxiliary variable */
866 )
867{
868 char varname[SCIP_MAXSTRLEN]; /* the name of the auxiliary variable */
869 char prefix[SCIP_MAXSTRLEN];
870 char tmpprefix[SCIP_MAXSTRLEN];
871 int len = 1;
872 int i;
873
874 assert(targetvar != NULL);
875 i = 0;
876 (*targetvar) = NULL;
877
878 /* the prefix for the variable names is required for UG, since we don't know how many copies have been made. To
879 * find the target variable, we start with an empty prefix. Then t_ is prepended until the target variable is
880 * found
881 */
882 prefix[0] = '\0';
883 while( i <= subscipdepth )
884 {
885 /* when probnumber == -1, we are searching for the master auxiliary variable. Otherwise, we are searching for the
886 * subproblem auxiliary variable.
887 */
888 if( probnumber == -1 )
889 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%smaster_%s_%s", prefix, AUXILIARYVAR_NAME, SCIPbendersGetName(benders));
890 else
891 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s%s_%d_%s", prefix, AUXILIARYVAR_NAME, probnumber, SCIPbendersGetName(benders));
892
893 /* finding the variable in the copied problem that has the same name as the auxiliary variable */
894 (*targetvar) = SCIPfindVar(scip, varname);
895
896 /* if the target variable is found, then we can exit the method */
897 if( (*targetvar) != NULL )
898 return;
899
900 (void) SCIPsnprintf(tmpprefix, len, "t_%s", prefix);
901 len += 2;
902 (void) strncpy(prefix, tmpprefix, len); /*lint !e732*/
903
904 i++;
905 }
906}
907
908/** assigns the copied auxiliary variables in the target SCIP to the target Benders' decomposition data */
909static
911 SCIP* scip, /**< SCIP data structure, the target scip */
912 SCIP_BENDERS* benders /**< Benders' decomposition */
913 )
914{
915 SCIP_BENDERS* topbenders; /* the highest priority Benders' decomposition */
916 SCIP_VAR* targetvar;
917 SCIP_VARDATA* vardata;
918 SCIP_Bool shareauxvars;
919 int subscipdepth;
920 int i;
921
922 assert(scip != NULL);
923 assert(benders != NULL);
924
925 /* this is a workaround for GCG. GCG expects that the variable has vardata when added. So a dummy vardata is created */
926 SCIP_CALL( SCIPallocBlockMemory(scip, &vardata) );
927 vardata->vartype = -1;
928
929 /* getting the highest priority Benders' decomposition */
930 topbenders = SCIPgetBenders(scip)[0];
931
932 /* if the auxiliary variable are shared, then the variable name will have a suffix of the highest priority Benders'
933 * name. So the shareauxvars flag indicates how to search for the auxiliary variables */
934 shareauxvars = FALSE;
935 if( topbenders != benders && SCIPbendersShareAuxVars(benders) )
936 shareauxvars = TRUE;
937
938 subscipdepth = SCIPgetSubscipDepth(scip);
939
940 /* storing the master auxiliary variable in the target Benders' implementation */
941 findAuxiliaryVar(scip, shareauxvars ? topbenders : benders, &targetvar, subscipdepth, -1);
942
943 if( targetvar != NULL )
944 {
945 SCIPvarSetData(targetvar, vardata);
946
947 benders->masterauxvar = SCIPvarGetTransVar(targetvar);
948
950 }
951 else
952 benders->masterauxvar = NULL;
953
954 /* storing the auxiliary variable in the target Benders' implementation */
955 for( i = 0; i < SCIPbendersGetNSubproblems(benders); i++ )
956 {
957 findAuxiliaryVar(scip, shareauxvars ? topbenders : benders, &targetvar, subscipdepth, i);
958
959 if( targetvar != NULL )
960 {
961 SCIPvarSetData(targetvar, vardata);
962
963 benders->auxiliaryvars[i] = SCIPvarGetTransVar(targetvar);
964
965 SCIP_CALL( SCIPcaptureVar(scip, benders->auxiliaryvars[i]) );
966 }
967 else
968 {
969 SCIPABORT();
970 }
971 }
972
973 SCIPfreeBlockMemory(scip, &vardata);
974
975 return SCIP_OKAY;
976}
977
978/** sets the subproblem objective value array to -infinity */
979static
981 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
982 SCIP_SET* set /**< global SCIP settings */
983 )
984{
985 SCIP* subproblem;
986 SCIP_Real inf;
987 int nsubproblems;
988 int i;
989
990 assert(benders != NULL);
991
992 nsubproblems = SCIPbendersGetNSubproblems(benders);
993
994 for( i = 0; i < nsubproblems; i++ )
995 {
996 subproblem = SCIPbendersSubproblem(benders, i);
997 if( subproblem != NULL )
998 inf = SCIPinfinity(subproblem);
999 else
1000 inf = SCIPsetInfinity(set);
1001
1002 SCIPbendersSetSubproblemObjval(benders, i, inf);
1003 }
1004}
1006/** compares two Benders' decompositions w.r.t. their priority */
1007SCIP_DECL_SORTPTRCOMP(SCIPbendersComp)
1008{ /*lint --e{715}*/
1009 return ((SCIP_BENDERS*)elem2)->priority - ((SCIP_BENDERS*)elem1)->priority;
1010}
1012/** comparison method for sorting Benders' decompositions w.r.t. to their name */
1013SCIP_DECL_SORTPTRCOMP(SCIPbendersCompName)
1014{
1015 return strcmp(SCIPbendersGetName((SCIP_BENDERS*)elem1), SCIPbendersGetName((SCIP_BENDERS*)elem2));
1016}
1017
1018/** method to call, when the priority of a Benders' decomposition was changed */
1019static
1020SCIP_DECL_PARAMCHGD(paramChgdBendersPriority)
1021{ /*lint --e{715}*/
1022 SCIP_PARAMDATA* paramdata;
1023
1024 paramdata = SCIPparamGetData(param);
1025 assert(paramdata != NULL);
1026
1027 /* use SCIPsetBendersPriority() to mark the Benders' decompositions as unsorted */
1028 SCIPsetBendersPriority(scip, (SCIP_BENDERS*)paramdata, SCIPparamGetInt(param)); /*lint !e740*/
1029
1030 return SCIP_OKAY;
1031}
1032
1033/** creates a variable mapping between the master problem variables of the source scip and the sub scip */
1034static
1036 SCIP_BENDERS* benders, /**< Benders' decomposition of the target SCIP instance */
1037 SCIP_SET* sourceset, /**< global SCIP settings from the source SCIP */
1038 SCIP_HASHMAP* varmap /**< a hashmap to store the mapping of source variables corresponding
1039 * target variables; must not be NULL */
1040 )
1041{
1042 SCIP_VAR** vars;
1043 SCIP_VAR* targetvar;
1044 int nvars;
1045 int i;
1046
1047 assert(benders != NULL);
1048 assert(sourceset != NULL);
1049 assert(benders->iscopy);
1050 assert(benders->mastervarsmap == NULL);
1051
1052 /* getting the master problem variable data */
1053 vars = SCIPgetVars(sourceset->scip);
1054 nvars = SCIPgetNVars(sourceset->scip);
1055
1056 /* creating the hashmap for the mapping between the master variable of the target and source scip */
1057 SCIP_CALL( SCIPhashmapCreate(&benders->mastervarsmap, SCIPblkmem(sourceset->scip), nvars) );
1058
1059 for( i = 0; i < nvars; i++ )
1060 {
1061 /* getting the variable pointer for the target SCIP variables. The variable mapping returns the target SCIP
1062 * varibale for a given source SCIP variable. */
1063 targetvar = (SCIP_VAR*) SCIPhashmapGetImage(varmap, vars[i]);
1064 if( targetvar != NULL )
1065 {
1066 SCIP_CALL( SCIPhashmapInsert(benders->mastervarsmap, targetvar, vars[i]) );
1067 SCIP_CALL( SCIPcaptureVar(sourceset->scip, vars[i]) );
1068 }
1069 }
1070
1071 return SCIP_OKAY;
1072}
1074/** copies the given Benders' decomposition to a new SCIP */
1076 SCIP_BENDERS* benders, /**< Benders' decomposition */
1077 SCIP_SET* sourceset, /**< SCIP_SET of SCIP to copy from */
1078 SCIP_SET* targetset, /**< SCIP_SET of SCIP to copy to */
1079 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of source variables corresponding
1080 * target variables; if NULL, then the transfer of cuts is not possible */
1081 SCIP_Bool threadsafe, /**< must the Benders' decomposition copy be thread safe */
1082 SCIP_Bool* valid /**< was the copying process valid? */
1083 )
1084{
1085 SCIP_BENDERS* targetbenders; /* the copy of the Benders' decomposition struct in the target set */
1086 int i;
1087
1088 assert(benders != NULL);
1089 assert(targetset != NULL);
1090 assert(valid != NULL);
1091 assert(targetset->scip != NULL);
1092
1093 (*valid) = FALSE;
1094
1095 if( benders->benderscopy != NULL && targetset->benders_copybenders && SCIPbendersIsActive(benders) )
1096 {
1097 SCIPsetDebugMsg(targetset, "including Benders' decomposition %s in subscip %p\n", SCIPbendersGetName(benders), (void*)targetset->scip);
1098 SCIP_CALL( benders->benderscopy(targetset->scip, benders, threadsafe) );
1099
1100 /* copying the Benders' cuts */
1101 targetbenders = SCIPsetFindBenders(targetset, SCIPbendersGetName(benders));
1102
1103 /* storing the pointer to the source scip instance */
1104 targetbenders->sourcescip = sourceset->scip;
1105
1106 /* the flag is set to indicate that the Benders' decomposition is a copy */
1107 targetbenders->iscopy = TRUE;
1108
1109 /* storing whether the lnscheck should be performed */
1110 targetbenders->lnscheck = benders->lnscheck;
1111 targetbenders->lnsmaxdepth = benders->lnsmaxdepth;
1112 targetbenders->lnsmaxcalls = benders->lnsmaxcalls;
1113 targetbenders->lnsmaxcallsroot = benders->lnsmaxcallsroot;
1114
1115 /* storing whether the Benders' copy required thread safety */
1116 targetbenders->threadsafe = threadsafe;
1117
1118 /* calling the copy method for the Benders' cuts */
1120 for( i = 0; i < benders->nbenderscuts; i++ )
1121 {
1122 SCIP_CALL( SCIPbenderscutCopyInclude(targetbenders, benders->benderscuts[i], targetset) );
1123 }
1124
1125 /* When the Benders' decomposition is copied then a variable mapping between the master problem variables is
1126 * required. This variable mapping is used to transfer the cuts generated in the target SCIP to the source SCIP.
1127 * The variable map is stored in the target Benders' decomposition. This will be freed when the sub-SCIP is freed.
1128 */
1129 if( varmap != NULL )
1130 {
1131 SCIP_CALL( createMasterVarMapping(targetbenders, sourceset, varmap) );
1132 }
1133
1134 assert((varmap != NULL && targetbenders->mastervarsmap != NULL)
1135 || (varmap == NULL && targetbenders->mastervarsmap == NULL));
1136 }
1137
1138 /* if the Benders' decomposition is active, then copy is not valid. */
1139 (*valid) = !SCIPbendersIsActive(benders);
1140
1141 return SCIP_OKAY;
1142}
1143
1144/** internal method for creating a Benders' decomposition structure */
1145static
1147 SCIP_BENDERS** benders, /**< pointer to Benders' decomposition data structure */
1148 SCIP_SET* set, /**< global SCIP settings */
1149 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1150 BMS_BLKMEM* blkmem, /**< block memory for parameter settings */
1151 const char* name, /**< name of Benders' decomposition */
1152 const char* desc, /**< description of Benders' decomposition */
1153 int priority, /**< priority of the Benders' decomposition */
1154 SCIP_Bool cutlp, /**< should Benders' cuts be generated for LP solutions */
1155 SCIP_Bool cutpseudo, /**< should Benders' cuts be generated for pseudo solutions */
1156 SCIP_Bool cutrelax, /**< should Benders' cuts be generated for relaxation solutions */
1157 SCIP_Bool shareauxvars, /**< should this Benders' use the highest priority Benders aux vars */
1158 SCIP_DECL_BENDERSCOPY ((*benderscopy)), /**< copy method of Benders' decomposition or NULL if you don't want to copy your plugin into sub-SCIPs */
1159 SCIP_DECL_BENDERSFREE ((*bendersfree)), /**< destructor of Benders' decomposition */
1160 SCIP_DECL_BENDERSINIT ((*bendersinit)), /**< initialize Benders' decomposition */
1161 SCIP_DECL_BENDERSEXIT ((*bendersexit)), /**< deinitialize Benders' decomposition */
1162 SCIP_DECL_BENDERSINITPRE((*bendersinitpre)),/**< presolving initialization method for Benders' decomposition */
1163 SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)),/**< presolving deinitialization method for Benders' decomposition */
1164 SCIP_DECL_BENDERSINITSOL((*bendersinitsol)),/**< solving process initialization method of Benders' decomposition */
1165 SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)),/**< solving process deinitialization method of Benders' decomposition */
1166 SCIP_DECL_BENDERSGETVAR((*bendersgetvar)),/**< returns the master variable for a given subproblem variable */
1167 SCIP_DECL_BENDERSCREATESUB((*benderscreatesub)),/**< creates a Benders' decomposition subproblem */
1168 SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)),/**< called prior to the subproblem solving loop */
1169 SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)),/**< the solving method for convex Benders' decomposition subproblems */
1170 SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)),/**< the solving method for the Benders' decomposition subproblems */
1171 SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)),/**< called after the subproblems are solved. */
1172 SCIP_DECL_BENDERSFREESUB((*bendersfreesub)),/**< the freeing method for the Benders' decomposition subproblems */
1173 SCIP_BENDERSDATA* bendersdata /**< Benders' decomposition data */
1174 )
1175{
1177 char paramdesc[SCIP_MAXSTRLEN];
1178
1179 assert(benders != NULL);
1180 assert(name != NULL);
1181 assert(desc != NULL);
1182
1183 /* Checking whether the benderssolvesub and the bendersfreesub are both implemented or both are not implemented */
1184 if( (benderssolvesubconvex == NULL && benderssolvesub == NULL && bendersfreesub != NULL)
1185 || ((benderssolvesubconvex != NULL || benderssolvesub != NULL) && bendersfreesub == NULL) )
1186 {
1187 SCIPerrorMessage("Benders' decomposition <%s> requires that if bendersFreesub%s is implemented, then at least "
1188 "one of bendersSolvesubconvex%s or bendersSolvesub%s are implemented.\n", name, name, name, name);
1189 return SCIP_INVALIDCALL;
1190 }
1191
1192 SCIP_ALLOC( BMSallocMemory(benders) );
1193 BMSclearMemory(*benders);
1194 SCIP_ALLOC( BMSduplicateMemoryArray(&(*benders)->name, name, strlen(name)+1) );
1195 SCIP_ALLOC( BMSduplicateMemoryArray(&(*benders)->desc, desc, strlen(desc)+1) );
1196 (*benders)->priority = priority;
1197 (*benders)->cutlp = cutlp;
1198 (*benders)->cutpseudo = cutpseudo;
1199 (*benders)->cutrelax = cutrelax;
1200 (*benders)->shareauxvars = shareauxvars;
1201 (*benders)->benderscopy = benderscopy;
1202 (*benders)->bendersfree = bendersfree;
1203 (*benders)->bendersinit = bendersinit;
1204 (*benders)->bendersexit = bendersexit;
1205 (*benders)->bendersinitpre = bendersinitpre;
1206 (*benders)->bendersexitpre = bendersexitpre;
1207 (*benders)->bendersinitsol = bendersinitsol;
1208 (*benders)->bendersexitsol = bendersexitsol;
1209 (*benders)->bendersgetvar = bendersgetvar;
1210 (*benders)->benderscreatesub = benderscreatesub;
1211 (*benders)->benderspresubsolve = benderspresubsolve;
1212 (*benders)->benderssolvesubconvex = benderssolvesubconvex;
1213 (*benders)->benderssolvesub = benderssolvesub;
1214 (*benders)->benderspostsolve = benderspostsolve;
1215 (*benders)->bendersfreesub = bendersfreesub;
1216 (*benders)->objectivetype = SCIP_BENDERSOBJTYPE_SUM;
1217 (*benders)->bendersdata = bendersdata;
1218 SCIP_CALL( SCIPclockCreate(&(*benders)->setuptime, SCIP_CLOCKTYPE_DEFAULT) );
1219 SCIP_CALL( SCIPclockCreate(&(*benders)->bendersclock, SCIP_CLOCKTYPE_DEFAULT) );
1220 (*benders)->nlpparam = SCIP_NLPPARAM_DEFAULT(set->scip); /*lint !e446*/
1221
1222 /* add parameters */
1223 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/priority", name);
1224 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "priority of Benders' decomposition <%s>", name);
1225 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
1226 &(*benders)->priority, FALSE, priority, INT_MIN/4, INT_MAX/4,
1227 paramChgdBendersPriority, (SCIP_PARAMDATA*)(*benders)) ); /*lint !e740*/
1228
1229 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutlp", name);
1230 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1231 "should Benders' cuts be generated for LP solutions?", &(*benders)->cutlp, FALSE, cutlp, NULL, NULL) ); /*lint !e740*/
1232
1233 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutpseudo", name);
1234 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1235 "should Benders' cuts be generated for pseudo solutions?", &(*benders)->cutpseudo, FALSE, cutpseudo, NULL, NULL) ); /*lint !e740*/
1236
1237 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutrelax", name);
1238 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1239 "should Benders' cuts be generated for relaxation solutions?", &(*benders)->cutrelax, FALSE, cutrelax, NULL, NULL) ); /*lint !e740*/
1240
1241 /* These parameters are left for the user to decide in a settings file. This departs from the usual SCIP convention
1242 * where the settings available at the creation of the plugin can be set in the function call.
1243 */
1244 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/transfercuts", name);
1245 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1246 "should Benders' cuts from LNS heuristics be transferred to the main SCIP instance?", &(*benders)->transfercuts,
1247 FALSE, SCIP_DEFAULT_TRANSFERCUTS, NULL, NULL) ); /*lint !e740*/
1248
1249 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/lnscheck", name);
1250 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1251 "should Benders' decomposition be used in LNS heurisics?", &(*benders)->lnscheck, FALSE, SCIP_DEFAULT_LNSCHECK,
1252 NULL, NULL) ); /*lint !e740*/
1253
1254 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/lnsmaxdepth", name);
1255 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
1256 "maximum depth at which the LNS check is performed (-1: no limit)", &(*benders)->lnsmaxdepth, TRUE,
1258
1259 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/lnsmaxcalls", name);
1260 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
1261 "the maximum number of Benders' decomposition calls in LNS heuristics (-1: no limit)", &(*benders)->lnsmaxcalls,
1262 TRUE, SCIP_DEFAULT_LNSMAXCALLS, -1, INT_MAX, NULL, NULL) );
1263
1264 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/lnsmaxcallsroot", name);
1265 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
1266 "the maximum number of root node Benders' decomposition calls in LNS heuristics (-1: no limit)",
1267 &(*benders)->lnsmaxcallsroot, TRUE, SCIP_DEFAULT_LNSMAXCALLSROOT, -1, INT_MAX, NULL, NULL) );
1268
1269 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutsasconss", name);
1270 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1271 "should the transferred cuts be added as constraints?", &(*benders)->cutsasconss, FALSE,
1272 SCIP_DEFAULT_CUTSASCONSS, NULL, NULL) ); /*lint !e740*/
1273
1274 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/subprobfrac", name);
1275 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
1276 "fraction of subproblems that are solved in each iteration", &(*benders)->subprobfrac, FALSE,
1277 SCIP_DEFAULT_SUBPROBFRAC, 0.0, 1.0, NULL, NULL) ); /*lint !e740*/
1278
1279 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/updateauxvarbound", name);
1280 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1281 "should the auxiliary variable bound be updated by solving the subproblem?", &(*benders)->updateauxvarbound,
1282 FALSE, SCIP_DEFAULT_UPDATEAUXVARBOUND, NULL, NULL) ); /*lint !e740*/
1283
1284 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/auxvarsimplint", name);
1285 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1286 "if the subproblem objective is integer, then define the auxiliary variables as implicit integers?",
1287 &(*benders)->auxvarsimplint, FALSE, SCIP_DEFAULT_AUXVARSIMPLINT, NULL, NULL) ); /*lint !e740*/
1288
1289 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutcheck", name);
1290 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1291 "should Benders' cuts be generated while checking solutions?",
1292 &(*benders)->cutcheck, FALSE, SCIP_DEFAULT_CUTCHECK, NULL, NULL) ); /*lint !e740*/
1293
1294 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutstrengthenmult", name);
1295 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
1296 "the convex combination multiplier for the cut strengthening", &(*benders)->convexmult, FALSE,
1297 SCIP_DEFAULT_STRENGTHENMULT, 0.0, 1.0, NULL, NULL) ); /*lint !e740*/
1298
1299 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/noimprovelimit", name);
1300 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
1301 "the maximum number of cut strengthening without improvement", &(*benders)->noimprovelimit, TRUE,
1302 SCIP_DEFAULT_NOIMPROVELIMIT, 0, INT_MAX, NULL, NULL) );
1303
1304 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/corepointperturb", name);
1305 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
1306 "the constant use to perturb the cut strengthening core point", &(*benders)->perturbeps, FALSE,
1307 SCIP_DEFAULT_STRENGTHENPERTURB, 0.0, 1.0, NULL, NULL) ); /*lint !e740*/
1308
1309 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutstrengthenenabled", name);
1310 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1311 "should the core point cut strengthening be employed (only applied to fractional solutions or continuous subproblems)?",
1312 &(*benders)->strengthenenabled, FALSE, SCIP_DEFAULT_STRENGTHENENABLED, NULL, NULL) ); /*lint !e740*/
1313
1314 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/cutstrengthenintpoint", name);
1315 SCIP_CALL( SCIPsetAddCharParam(set, messagehdlr, blkmem, paramname,
1316 "where should the strengthening interior point be sourced from ('l'p relaxation, 'f'irst solution, 'i'ncumbent solution, 'r'elative interior point, vector of 'o'nes, vector of 'z'eros)",
1317 &(*benders)->strengthenintpoint, FALSE, SCIP_DEFAULT_STRENGTHENINTPOINT, "lfiroz", NULL, NULL) ); /*lint !e740*/
1318
1319#ifdef SCIP_DISABLED_CODE /* temporarily disabling support for multiple threads in Benders' decomposition */
1320 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/numthreads", name);
1321 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
1322 "the number of threads to use when solving the subproblems", &(*benders)->numthreads, TRUE,
1323 SCIP_DEFAULT_NUMTHREADS, 1, INT_MAX, NULL, NULL) );
1324#endif
1325
1326 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/execfeasphase", name);
1327 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1328 "should a feasibility phase be executed during the root node, i.e. adding slack variables to constraints to ensure feasibility",
1329 &(*benders)->execfeasphase, FALSE, SCIP_DEFAULT_EXECFEASPHASE, NULL, NULL) ); /*lint !e740*/
1330
1331 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/slackvarcoef", name);
1332 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
1333 "the initial objective coefficient of the slack variables in the subproblem", &(*benders)->slackvarcoef, FALSE,
1334 SCIP_DEFAULT_SLACKVARCOEF, 0.0, SCIPsetInfinity(set), NULL, NULL) ); /*lint !e740*/
1335
1336 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/maxslackvarcoef", name);
1337 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname,
1338 "the maximal objective coefficient of the slack variables in the subproblem", &(*benders)->maxslackvarcoef, FALSE,
1339 SCIP_DEFAULT_MAXSLACKVARCOEF, 0.0, SCIPsetInfinity(set), NULL, NULL) ); /*lint !e740*/
1340
1341 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/checkconsconvexity", name);
1342 SCIP_CALL( SCIPsetAddBoolParam(set, messagehdlr, blkmem, paramname,
1343 "should the constraints of the subproblems be checked for convexity?", &(*benders)->checkconsconvexity, FALSE,
1344 SCIP_DEFAULT_CHECKCONSCONVEXITY, NULL, NULL) ); /*lint !e740*/
1345
1346 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/nlpiterlimit", name);
1347 SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
1348 "iteration limit for NLP solver", &(*benders)->nlpparam.iterlimit, FALSE,
1349 SCIP_DEFAULT_NLPITERLIMIT, 0, INT_MAX, NULL, NULL) ); /*lint !e740*/
1350
1351 return SCIP_OKAY;
1352}
1353
1354/** creates a Benders' decomposition structure
1355 *
1356 * To use the Benders' decomposition for solving a problem, it first has to be activated with a call to SCIPactivateBenders().
1357 */
1359 SCIP_BENDERS** benders, /**< pointer to Benders' decomposition data structure */
1360 SCIP_SET* set, /**< global SCIP settings */
1361 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1362 BMS_BLKMEM* blkmem, /**< block memory for parameter settings */
1363 const char* name, /**< name of Benders' decomposition */
1364 const char* desc, /**< description of Benders' decomposition */
1365 int priority, /**< priority of the Benders' decomposition */
1366 SCIP_Bool cutlp, /**< should Benders' cuts be generated for LP solutions */
1367 SCIP_Bool cutpseudo, /**< should Benders' cuts be generated for pseudo solutions */
1368 SCIP_Bool cutrelax, /**< should Benders' cuts be generated for relaxation solutions */
1369 SCIP_Bool shareauxvars, /**< should this Benders' use the highest priority Benders aux vars */
1370 SCIP_DECL_BENDERSCOPY ((*benderscopy)), /**< copy method of Benders' decomposition or NULL if you don't want to copy your plugin into sub-SCIPs */
1371 SCIP_DECL_BENDERSFREE ((*bendersfree)), /**< destructor of Benders' decomposition */
1372 SCIP_DECL_BENDERSINIT ((*bendersinit)), /**< initialize Benders' decomposition */
1373 SCIP_DECL_BENDERSEXIT ((*bendersexit)), /**< deinitialize Benders' decomposition */
1374 SCIP_DECL_BENDERSINITPRE((*bendersinitpre)),/**< presolving initialization method for Benders' decomposition */
1375 SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)),/**< presolving deinitialization method for Benders' decomposition */
1376 SCIP_DECL_BENDERSINITSOL((*bendersinitsol)),/**< solving process initialization method of Benders' decomposition */
1377 SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)),/**< solving process deinitialization method of Benders' decomposition */
1378 SCIP_DECL_BENDERSGETVAR((*bendersgetvar)),/**< returns the master variable for a given subproblem variable */
1379 SCIP_DECL_BENDERSCREATESUB((*benderscreatesub)),/**< creates a Benders' decomposition subproblem */
1380 SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)),/**< called prior to the subproblem solving loop */
1381 SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)),/**< the solving method for convex Benders' decomposition subproblems */
1382 SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)),/**< the solving method for the Benders' decomposition subproblems */
1383 SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)),/**< called after the subproblems are solved. */
1384 SCIP_DECL_BENDERSFREESUB((*bendersfreesub)),/**< the freeing method for the Benders' decomposition subproblems */
1385 SCIP_BENDERSDATA* bendersdata /**< Benders' decomposition data */
1386 )
1387{
1388 assert(benders != NULL);
1389 assert(name != NULL);
1390 assert(desc != NULL);
1391
1392 SCIP_CALL_FINALLY( doBendersCreate(benders, set, messagehdlr, blkmem, name, desc, priority, cutlp, cutpseudo,
1393 cutrelax, shareauxvars, benderscopy, bendersfree, bendersinit, bendersexit, bendersinitpre, bendersexitpre,
1394 bendersinitsol, bendersexitsol, bendersgetvar, benderscreatesub, benderspresubsolve, benderssolvesubconvex,
1395 benderssolvesub, benderspostsolve, bendersfreesub, bendersdata), (void) SCIPbendersFree(benders, set) );
1396
1397 return SCIP_OKAY;
1398}
1399
1400
1401/** releases the variables that have been captured in the hashmap */
1402static
1404 SCIP* scip, /**< the SCIP data structure */
1405 SCIP_BENDERS* benders /**< Benders' decomposition */
1406 )
1407{
1408 int nentries;
1409 int i;
1410
1411 assert(scip != NULL);
1412 assert(benders != NULL);
1413
1414 assert(benders->mastervarsmap != NULL);
1415
1416 nentries = SCIPhashmapGetNEntries(benders->mastervarsmap);
1417
1418 for( i = 0; i < nentries; ++i )
1419 {
1420 SCIP_HASHMAPENTRY* entry;
1421 entry = SCIPhashmapGetEntry(benders->mastervarsmap, i);
1422
1423 if( entry != NULL )
1424 {
1425 SCIP_VAR* var;
1427
1429 }
1430 }
1431
1432 return SCIP_OKAY;
1433}
1434
1436/** calls destructor and frees memory of Benders' decomposition */
1438 SCIP_BENDERS** benders, /**< pointer to Benders' decomposition data structure */
1439 SCIP_SET* set /**< global SCIP settings */
1440 )
1441{
1442 int i;
1443
1444 assert(benders != NULL);
1445 assert(*benders != NULL);
1446 assert(!(*benders)->initialized);
1447 assert(set != NULL);
1448
1449 /* call destructor of Benders' decomposition */
1450 if( (*benders)->bendersfree != NULL )
1451 {
1452 SCIP_CALL( (*benders)->bendersfree(set->scip, *benders) );
1453 }
1454
1455 /* if the Benders' decomposition is a copy and a varmap has been passed to SCIP_BENDERS, then the variable map
1456 * between the source and the target SCIP needs to be freed.
1457 */
1458 if( (*benders)->iscopy && (*benders)->mastervarsmap != NULL )
1459 {
1460 SCIP_CALL( releaseVarMappingHashmapVars((*benders)->sourcescip, (*benders)) );
1461 SCIPhashmapFree(&(*benders)->mastervarsmap);
1462 }
1463
1464 /* freeing the Benders' cuts */
1465 for( i = 0; i < (*benders)->nbenderscuts; i++ )
1466 {
1467 SCIP_CALL( SCIPbenderscutFree(&((*benders)->benderscuts[i]), set) );
1468 }
1469 BMSfreeMemoryArrayNull(&(*benders)->benderscuts);
1470
1471 SCIPclockFree(&(*benders)->bendersclock);
1472 SCIPclockFree(&(*benders)->setuptime);
1473 BMSfreeMemoryArray(&(*benders)->name);
1474 BMSfreeMemoryArray(&(*benders)->desc);
1475 BMSfreeMemory(benders);
1476
1477 return SCIP_OKAY;
1478}
1480static
1482 SCIP_BENDERS* benders, /**< Benders' decomposition */
1483 SCIP_SET* set, /**< global SCIP settings */
1484 SCIP_VAR* var, /**< the variable to be added to the store */
1485 int probnumber /**< the subproblem number */
1486 )
1487{
1488 assert(benders != NULL);
1489 assert(set != NULL);
1490 assert(var != NULL);
1491 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
1492
1493 /* if the number of stored variables equals the size, then we need to extend the storage */
1494 if( benders->submastervarssize[probnumber] < benders->nsubmastervars[probnumber] + 1 )
1495 {
1496 int newsize;
1497
1498 newsize = SCIPsetCalcMemGrowSize(set, benders->nsubmastervars[probnumber] + 1);
1499 SCIP_ALLOC( BMSreallocMemoryArray(&benders->submastervars[probnumber], newsize) ); /*lint !e866*/
1500
1501 benders->submastervarssize[probnumber] = newsize;
1502 }
1503
1504 benders->submastervars[probnumber][benders->nsubmastervars[probnumber]] = var;
1505 benders->nsubmastervars[probnumber]++;
1506
1507 /* capturing the variable, so that it is not released before */
1508
1509 /* getting the variable type and updating the statistics */
1511 benders->nsubmasterbinvars[probnumber]++;
1513 benders->nsubmasterintvars[probnumber]++;
1514
1515 return SCIP_OKAY;
1516}
1518static
1520 SCIP_BENDERS* benders, /**< Benders' decomposition */
1521 SCIP_SET* set, /**< global SCIP settings */
1522 int probnumber /**< the subproblem number */
1523 )
1524{
1525 SCIP* subproblem;
1526 SCIP_VAR** vars;
1527 SCIP_VAR* mastervar;
1528 int nvars;
1529 int i;
1530
1531 assert(benders != NULL);
1532 assert(set != NULL);
1533 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
1534
1535 subproblem = SCIPbendersSubproblem(benders, probnumber);
1536
1537 /* getting the variables of the subproblem to store the master problem variables */
1538 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, NULL) );
1539
1540 for( i = 0; i < nvars; i++ )
1541 {
1542 /* retrieving the master problem variable */
1543 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
1544
1545 /* if mastervar is not NULL, then the subproblem variable has a corresponding master problem variable */
1546 if( mastervar != NULL )
1547 {
1548 SCIP_CALL( storeSubproblemMasterVar(benders, set, mastervar, probnumber) );
1549 }
1550 }
1551
1552 return SCIP_OKAY;
1553}
1554
1555/* adds a slack variable to the given constraint */
1556static
1558 SCIP* scip, /**< the SCIP data structure */
1559 SCIP_BENDERS* benders, /**< Benders' decomposition */
1560 SCIP_CONS* cons, /**< constraint to which the slack variable(s) is added to */
1561 SCIP_CONSHDLR** linearconshdlrs, /**< an array storing the linear constraint handlers */
1562 SCIP_CONSHDLR* nlconshdlr, /**< pointer to the nonlinear constraint handler */
1563 int nlinearconshdlrs /**< the number of linear constraint handlers */
1564 )
1565{
1566 SCIP_CONSHDLR* conshdlr;
1567 SCIP_VAR* var;
1568 SCIP_Real rhs;
1569 SCIP_Real lhs;
1570 SCIP_Real objcoef;
1571 int i;
1572 SCIP_Bool linearcons;
1573 SCIP_Bool success;
1574 char name[SCIP_MAXSTRLEN];
1575
1576 conshdlr = SCIPconsGetHdlr(cons);
1577
1578 /* assume that the constraint is not linear, then we check whether it is linear */
1579 linearcons = FALSE;
1580
1581 /* checking whether the constraint is a linear constraint. If so, we add a coefficient to the constraint */
1582 for( i = 0; i < nlinearconshdlrs; ++i )
1583 {
1584 if( conshdlr == linearconshdlrs[i] )
1585 {
1586 linearcons = TRUE;
1587 break;
1588 }
1589 }
1590
1591 if( !linearcons && conshdlr != nlconshdlr )
1592 {
1593 SCIPwarningMessage(scip, "The subproblem includes constraint <%s>. "
1594 "This is not supported and the slack variable will not be added to the constraint. Feasibility cuts may be invalid.\n",
1595 SCIPconshdlrGetName(conshdlr));
1596 }
1597
1598 if( linearcons )
1599 {
1600 rhs = SCIPconsGetRhs(scip, cons, &success);
1601 assert(success);
1602 lhs = SCIPconsGetLhs(scip, cons, &success);
1603 assert(success);
1604 }
1605 else
1606 {
1607 rhs = SCIPgetRhsNonlinear(cons);
1608 lhs = SCIPgetLhsNonlinear(cons);
1609 }
1610
1611 /* getting the objective coefficient for the slack variables */
1612 objcoef = benders->slackvarcoef;
1613
1614 /* if the right hand side is finite, then we need to add a slack variable with a negative coefficient */
1615 if( !SCIPisInfinity(scip, rhs) )
1616 {
1617 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%s_neg", SLACKVAR_NAME, SCIPconsGetName(cons) );
1618
1620
1621 /* adding the slack variable to the subproblem */
1623
1624 /* adds the slack variable to the constraint */
1625 if( linearcons )
1626 {
1627 SCIP_CALL( SCIPconsAddCoef(scip, cons, var, -1.0) );
1628 }
1629 else
1630 {
1632 }
1633
1634 /* releasing the variable */
1636 }
1637
1638 /* if the left hand side if finite, then we need to add a slack variable with a positive coefficient */
1639 if( !SCIPisInfinity(scip, -lhs) )
1640 {
1641 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%s_pos", SLACKVAR_NAME, SCIPconsGetName(cons) );
1642
1644
1645 /* adding the slack variable to the subproblem */
1647
1648 /* adds the slack variable to the constraint */
1649 if( linearcons )
1650 {
1651 SCIP_CALL( SCIPconsAddCoef(scip, cons, var, 1.0) );
1652 }
1653 else
1654 {
1656 }
1657
1658 /* releasing the variable */
1660 }
1661
1662 return SCIP_OKAY;
1663}
1664
1665/** adds the slack variables to each of the constraints for the generation of feasibility cuts for the given non-linear
1666 * subproblem
1668static
1670 SCIP_BENDERS* benders, /**< Benders' decomposition */
1671 SCIP_SET* set, /**< global SCIP settings */
1672 int probnumber /**< the subproblem number */
1673 )
1674{
1675 SCIP* subproblem;
1676 SCIP_CONSHDLR* linearconshdlrs[NLINEARCONSHDLRS];
1677 SCIP_CONSHDLR* nlconshdlr;
1678 SCIP_CONS** origconss;
1679 SCIP_CONS* cons;
1680 int norgiconss;
1681 int i;
1682
1683 assert(benders != NULL);
1684 assert(set != NULL);
1685 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
1686
1687 subproblem = SCIPbendersSubproblem(benders, probnumber);
1688
1689 /* get pointers to linear constraints handlers, so can avoid string comparisons */
1690 linearconshdlrs[0] = SCIPfindConshdlr(subproblem, "knapsack");
1691 linearconshdlrs[1] = SCIPfindConshdlr(subproblem, "linear");
1692 linearconshdlrs[2] = SCIPfindConshdlr(subproblem, "logicor");
1693 linearconshdlrs[3] = SCIPfindConshdlr(subproblem, "setppc");
1694 linearconshdlrs[4] = SCIPfindConshdlr(subproblem, "varbound");
1695
1696 nlconshdlr = SCIPfindConshdlr(subproblem, "nonlinear");
1697
1698 origconss = SCIPgetOrigConss(subproblem);
1699 norgiconss = SCIPgetNOrigConss(subproblem);
1700 for( i = 0; i < norgiconss; ++i )
1701 {
1702 cons = origconss[i];
1703
1704 /* adding the slack variables to the constraint */
1705 SCIP_CALL( addSlackVars(subproblem, benders, cons, linearconshdlrs, nlconshdlr, NLINEARCONSHDLRS) );
1706 }
1707
1708 return SCIP_OKAY;
1709}
1710
1711/** initialises a MIP subproblem by putting the problem into SCIP_STAGE_SOLVING. This is achieved by calling SCIPsolve
1712 * and then interrupting the solve in a node focus event handler.
1713 * The LP subproblem is also initialised using this method; however, a different event handler is added. This event
1714 * handler will put the LP subproblem into probing mode.
1715 * The MIP solving function is called to initialise the subproblem because this function calls SCIPsolve with the
1716 * appropriate parameter settings for Benders' decomposition.
1718static
1720 SCIP_BENDERS* benders, /**< Benders' decomposition */
1721 SCIP_SET* set, /**< global SCIP settings */
1722 int probnumber, /**< the subproblem number */
1723 SCIP_Bool* infeasible, /**< pointer to store whether the lp is detected as infeasible */
1724 SCIP_Bool* success /**< was the initialisation process successful */
1725 )
1726{
1727 SCIP* subproblem;
1728 SCIP_STATUS solvestatus;
1729
1730 assert(benders != NULL);
1731 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
1732 assert(success != NULL);
1733
1734 (*success) = FALSE;
1735 (*infeasible) = FALSE;
1736
1737 subproblem = SCIPbendersSubproblem(benders, probnumber);
1738 assert(subproblem != NULL);
1739
1740 /* Getting the problem into the right SCIP stage for solving */
1741 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, FALSE) );
1742
1743 /* Constructing the LP that can be solved in later iterations */
1744 if( solvestatus != SCIP_STATUS_BESTSOLLIMIT && solvestatus != SCIP_STATUS_TIMELIMIT
1745 && solvestatus != SCIP_STATUS_MEMLIMIT )
1746 {
1747 assert(SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING);
1748
1749 SCIP_CALL( SCIPconstructLP(subproblem, infeasible) );
1750
1751 (*success) = !(*infeasible);
1752 }
1753
1754 return SCIP_OKAY;
1755}
1756
1757
1758/** initialises an LP subproblem by putting the problem into probing mode. The probing mode is invoked in a node focus
1759 * event handler. This event handler is added just prior to calling the initialise subproblem function.
1761static
1763 SCIP_BENDERS* benders, /**< Benders' decomposition */
1764 SCIP_SET* set, /**< global SCIP settings */
1765 int probnumber, /**< the subproblem number */
1766 SCIP_Bool* infeasible /**< pointer to store whether the lp is detected as infeasible */
1767 )
1768{
1769 SCIP* subproblem;
1770 SCIP_EVENTHDLR* eventhdlr;
1771 SCIP_EVENTHDLRDATA* eventhdlrdata;
1772 SCIP_Bool success;
1773
1774 assert(benders != NULL);
1775 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
1776 assert(infeasible != NULL);
1777
1778 subproblem = SCIPbendersSubproblem(benders, probnumber);
1779 assert(subproblem != NULL);
1780
1781 /* include event handler into SCIP */
1782 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata) );
1783
1784 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata) );
1785
1787 eventExecBendersNodefocus, eventhdlrdata) );
1788 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersNodefocus) );
1789 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersNodefocus) );
1790 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersNodefocus) );
1791 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersNodefocus) );
1792 assert(eventhdlr != NULL);
1793
1794 /* calling an initial solve to put the problem into probing mode */
1795 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, infeasible, &success) );
1796
1797 return SCIP_OKAY; /*lint !e438*/
1798}
1799
1800/** checks whether the convex relaxation of the subproblem is sufficient to solve the original problem to optimality
1801 *
1802 * We check whether we can conclude that the CIP is actually an LP or a convex NLP.
1803 * To do this, we check that all variables are of continuous type and that every constraint is either handled by known
1804 * linear constraint handler (knapsack, linear, logicor, setppc, varbound) or the nonlinear constraint handler.
1805 * In the latter case, we also check whether the nonlinear constraint is convex.
1806 * Further, nonlinear constraints are only considered if an NLP solver interface is available, i.e., and NLP could
1807 * be solved.
1808 * If constraints are present that cannot be identified as linear or convex nonlinear, then we assume that the
1809 * problem is not convex, thus solving its LP or NLP relaxation will not be sufficient.
1811static
1813 SCIP_BENDERS* benders, /**< Benders' decomposition */
1814 SCIP_SET* set, /**< global SCIP settings */
1815 int probnumber /**< the subproblem number, or -1 for the master problem */
1816 )
1817{
1818 SCIP* subproblem;
1819 SCIP_CONSHDLR* conshdlr;
1820 SCIP_CONS* cons;
1821 SCIP_HASHMAP* assumevarfixed;
1822 SCIP_VAR** vars;
1823 int nvars;
1824 int nbinvars;
1825 int nintvars;
1826 int nimplintvars;
1827 int i;
1828 int j;
1829 SCIP_Bool convexcons;
1830 SCIP_Bool discretevar;
1831 SCIP_Bool isnonlinear;
1832 SCIP_CONSHDLR* linearconshdlrs[NLINEARCONSHDLRS];
1833 SCIP_CONSHDLR* nlconshdlr = NULL;
1834
1835 assert(benders != NULL);
1836 assert(set != NULL);
1837 assert(probnumber >= -1 && probnumber < SCIPbendersGetNSubproblems(benders));
1838
1839 assumevarfixed = NULL;
1840 if( probnumber >= 0 )
1841 subproblem = SCIPbendersSubproblem(benders, probnumber);
1842 else
1843 subproblem = set->scip;
1844
1845 assert(subproblem != NULL);
1846
1847 convexcons = FALSE;
1848 discretevar = FALSE;
1849 isnonlinear = FALSE;
1850
1851 /* getting the number of integer and binary variables to determine the problem type */
1852 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, &nbinvars, &nintvars, &nimplintvars, NULL) );
1853
1854 /* if there are any binary, integer or implicit integer variables, then the subproblems is marked as non-convex */
1855 if( nbinvars != 0 || nintvars != 0 || nimplintvars != 0 )
1856 {
1857 discretevar = TRUE;
1858 }
1859
1860 /* get pointers to linear constraints handlers, so can avoid string comparisons */
1861 linearconshdlrs[0] = SCIPfindConshdlr(subproblem, "knapsack");
1862 linearconshdlrs[1] = SCIPfindConshdlr(subproblem, "linear");
1863 linearconshdlrs[2] = SCIPfindConshdlr(subproblem, "logicor");
1864 linearconshdlrs[3] = SCIPfindConshdlr(subproblem, "setppc");
1865 linearconshdlrs[4] = SCIPfindConshdlr(subproblem, "varbound");
1866
1867 /* Get pointer to the nonlinear constraint handler if we also have an NLP solver to solve NLPs.
1868 * If there is no NLP solver, but there are (convex) nonlinear constraints, then the LP relaxation of subproblems
1869 * will (currently) not be sufficient to solve subproblems to optimality. Thus, we also take the presence of convex
1870 * nonlinear constraints as signal for having to solve the CIP eventually, thus, by abuse of notation,
1871 * return not-convex here. In summary, we do not need to have a special look onto non-linear constraints
1872 * if no NLP solver is present, and can treat them as any other constraint that is not of linear type.
1873 */
1874 if( SCIPgetNNlpis(subproblem) > 0 )
1875 {
1876 nlconshdlr = SCIPfindConshdlr(subproblem, "nonlinear");
1877 }
1878
1879 /* if the nonlinear constraint handler exists, then we create a hashmap of variables that can be assumed to be fixed.
1880 * These variables correspond to the copies of the master variables in the subproblem
1881 */
1882 if( probnumber >= 0 && nlconshdlr != NULL )
1883 {
1884 SCIP_VAR* mappedvar;
1885
1886 SCIP_CALL( SCIPhashmapCreate(&assumevarfixed, SCIPblkmem(set->scip), SCIPgetNVars(subproblem)) );
1887
1888 /* finding the subproblem variables that correspond to master variables */
1889 for( i = 0; i < nvars; i++ )
1890 {
1891 /* getting the corresponding master problem variable for the given variable */
1892 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mappedvar, -1) );
1893
1894 /* if the mapped variable is not NULL, then it must be stored as a possible fixed variable */
1895 if( mappedvar != NULL )
1896 {
1897 SCIP_CALL( SCIPhashmapInsert(assumevarfixed, vars[i], vars[i]) );
1898 }
1899 }
1900 }
1901
1902 for( i = 0; i < SCIPgetNOrigConss(subproblem); ++i )
1903 {
1904 cons = SCIPgetOrigConss(subproblem)[i];
1905 conshdlr = SCIPconsGetHdlr(cons);
1906
1907 for( j = 0; j < NLINEARCONSHDLRS; ++j )
1908 if( conshdlr == linearconshdlrs[j] )
1909 break;
1910
1911 /* if linear constraint, then we are good */
1912 if( j < NLINEARCONSHDLRS )
1913 {
1914#ifdef SCIP_MOREDEBUG
1915 SCIPdebugMsg(subproblem, "subproblem <%s>: constraint <%s> is linear\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
1916#endif
1917 continue;
1918 }
1919
1920 /* if cons_nonlinear (and nlconshdlr != NULL), then check whether convex */
1921 if( conshdlr == nlconshdlr )
1922 {
1923 SCIP_Bool isconvex;
1924 SCIP_EXPRCURV curv;
1925 SCIP_Bool havelhs;
1926 SCIP_Bool haverhs;
1927
1928 isnonlinear = TRUE;
1929
1930 havelhs = !SCIPisInfinity(subproblem, -SCIPgetLhsNonlinear(cons));
1931 haverhs = !SCIPisInfinity(subproblem, SCIPgetRhsNonlinear(cons));
1932 if( havelhs && haverhs )
1933 {
1934 isconvex = FALSE;
1935 }
1936 else
1937 {
1938 /* look at curvature stored in cons, though at this stage this will be unknown a.a. */
1939 curv = SCIPgetCurvatureNonlinear(cons);
1940 isconvex = ((!havelhs || (curv & SCIP_EXPRCURV_CONCAVE) == SCIP_EXPRCURV_CONCAVE)) &&
1941 ((!haverhs || (curv & SCIP_EXPRCURV_CONVEX) == SCIP_EXPRCURV_CONVEX));
1942
1943 if( !isconvex )
1944 {
1945 /* if not found convex, compute curvature via nlhdlr_convex and decide again */
1946
1947 /* make sure activities are up to date. SCIPhasExprCurvature currently assumes that this is already the case */
1949
1950 SCIP_CALL( SCIPhasExprCurvature(subproblem, SCIPgetExprNonlinear(cons), havelhs ? SCIP_EXPRCURV_CONCAVE : SCIP_EXPRCURV_CONVEX, &isconvex, assumevarfixed) );
1951 }
1952 }
1953
1954 if( isconvex )
1955 {
1956#ifdef SCIP_MOREDEBUG
1957 SCIPdebugMsg(subproblem, "subproblem <%s>: nonlinear constraint <%s> is convex\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
1958#endif
1959 continue;
1960 }
1961 else
1962 {
1963#ifdef SCIP_MOREDEBUG
1964 SCIPdebugMsg(subproblem, "subproblem <%s>: nonlinear constraint <%s> not convex\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
1965#endif
1966 goto TERMINATE;
1967 }
1968 }
1969
1970#ifdef SCIP_MOREDEBUG
1971 SCIPdebugMsg(subproblem, "subproblem <%s>: potentially nonconvex constraint <%s>\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
1972#endif
1973 goto TERMINATE;
1974 }
1975
1976 /* if we made it until here, then all constraints are known and convex */
1977 convexcons = TRUE;
1978
1979TERMINATE:
1980 /* setting the flag for the convexity of the subproblem. If convexity doesn't need to be checked, then it is assumed
1981 * that the subproblems are convex. However, if there are discrete variables, then the problem must be set as
1982 * non-convex. The discrete master variables will be changed to continuous, but this will happen at the first call to
1983 * SCIPbendersSetupSubproblem
1984 */
1985 if( probnumber >= 0 )
1986 {
1987 convexcons = convexcons || !benders->checkconsconvexity;
1988
1989 if( convexcons && !discretevar )
1991 else if( convexcons && discretevar )
1993 else if( !convexcons && !discretevar )
1995 else if( !convexcons && discretevar )
1997 else
1998 SCIPABORT();
1999
2000 /* setting the non-linear subproblem flag */
2001 SCIPbendersSetSubproblemIsNonlinear(benders, probnumber, isnonlinear);
2002
2003 SCIPsetDebugMsg(set, "subproblem <%s> has been found to be of type %d\n", SCIPgetProbName(subproblem),
2004 SCIPbendersGetSubproblemType(benders, probnumber));
2005 }
2006 else
2007 {
2008 SCIPbendersSetMasterIsNonlinear(benders, isnonlinear);
2009 }
2010
2011 /* releasing the fixed variable hashmap */
2012 if( assumevarfixed != NULL )
2013 SCIPhashmapFree(&assumevarfixed);
2014
2015 return SCIP_OKAY;
2016}
2017
2018/** creates the subproblems and registers it with the Benders' decomposition struct */
2019static
2021 SCIP_BENDERS* benders, /**< Benders' decomposition */
2022 SCIP_SET* set /**< global SCIP settings */
2023 )
2024{
2025 SCIP* subproblem;
2026 SCIP_EVENTHDLR* eventhdlr;
2027 SCIP_VAR* mastervar;
2028 SCIP_VAR** vars;
2029 int nvars;
2030 int nsubproblems;
2031 int i;
2032 int j;
2033
2034 assert(benders != NULL);
2035 assert(set != NULL);
2036
2037 /* if the subproblems have already been created, then they will not be created again. This is the case if the
2038 * transformed problem has been freed and then retransformed. The subproblems should only be created when the problem
2039 * is first transformed. */
2040 if( benders->subprobscreated )
2041 return SCIP_OKAY;
2042
2043 nsubproblems = SCIPbendersGetNSubproblems(benders);
2044
2045 /* creating all subproblems */
2046 for( i = 0; i < nsubproblems; i++ )
2047 {
2048 /* calling the create subproblem call back method */
2049 SCIP_CALL( benders->benderscreatesub(set->scip, benders, i) );
2050
2051 subproblem = SCIPbendersSubproblem(benders, i);
2052
2053 /* the subproblem SCIP instance could be set to NULL. This is because user defined subproblem solving methods
2054 * could be used that don't solve a SCIP instance. Thus, the following setup of the subproblem SCIP instance is
2055 * not required.
2056 *
2057 * NOTE: since the subproblems are supplied as NULL pointers, the internal convexity check can not be performed.
2058 * The user needs to explicitly specify the subproblem type.
2059 */
2060 if( subproblem != NULL )
2061 {
2062 /* stores the master problem variables that are in the subproblem. This is helpful for all instances where the
2063 * master problem variable needs to extracted from the subproblem
2064 */
2066
2067 /* setting global limits for the subproblems. This overwrites the limits set by the user */
2068 SCIP_CALL( SCIPsetIntParam(subproblem, "limits/maxorigsol", 0) );
2069
2070 /* getting the number of integer and binary variables to determine the problem type */
2071 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, NULL) );
2072
2073 /* The objective function coefficients of the master problem are set to zero. This is necessary for the Benders'
2074 * decomposition algorithm, since the cut methods and the objective function check assumes that the objective
2075 * coefficients of the master problem variables are zero.
2076 *
2077 * This only occurs if the Benders' decomposition is not a copy. It is assumed that the correct objective
2078 * coefficients are given during the first subproblem creation.
2079 *
2080 * If the subproblems were copied, then the master variables will be checked to ensure that they have a zero
2081 * objective value.
2082 */
2083 if( !benders->iscopy || benders->threadsafe )
2084 {
2085 SCIP_Bool objchanged = FALSE;
2086
2087 assert(SCIPgetStage(subproblem) == SCIP_STAGE_PROBLEM);
2088 for( j = 0; j < nvars; j++ )
2089 {
2090 /* retrieving the master problem variable */
2091 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[j], &mastervar, -1) );
2092
2093 /* if mastervar is not NULL, then the subproblem variable has a corresponding master problem variable */
2094 if( mastervar != NULL && SCIPvarGetObj(vars[j]) != 0.0 )
2095 {
2096 SCIPverbMessage(subproblem, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Changing the objective "
2097 "coefficient of copy of master problem variable <%s> in subproblem %d to zero.\n",
2098 SCIPvarGetName(mastervar), i);
2099 /* changing the subproblem variable objective coefficient to zero */
2100 SCIP_CALL( SCIPchgVarObj(subproblem, vars[j], 0.0) );
2101
2102 objchanged = TRUE;
2103 }
2104 }
2105
2106 if( objchanged )
2107 {
2108 SCIPverbMessage(subproblem, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Objective coefficients of "
2109 "copy of master problem variables in a subproblem have been changed to zero.\n");
2110 }
2111 }
2112
2113 /* changing all of the master problem variable to continuous. */
2115
2116 /* checking the convexity of the subproblem. The convexity of the subproblem indicates whether the convex
2117 * relaxation is a valid relaxation for the problem
2118 */
2120
2121 /* if the problem is convex and has nonlinear constraints, then slack variables must be added to each of the
2122 * constraints
2123 */
2124 if( benders->execfeasphase ||
2126 && SCIPbendersSubproblemIsNonlinear(benders, i)) )
2127 {
2128 /* the slack variables are only added to the subproblem once. If the initialisation methods are called from a
2129 * copy, then the slack variables are not re-added. Alternatively, if the copy must be threadsafe, then the
2130 * subproblems are created from scratch again, so the slack variables need to be added.
2131 */
2132 if( !benders->iscopy || benders->threadsafe )
2133 {
2135 }
2136
2137 /* setting the flag to indicate that slack variables have been added to the subproblem constraints. This is only
2138 * set if the slack variables have been added at the request of the user.
2139 */
2140 if( benders->execfeasphase )
2141 benders->feasibilityphase = TRUE;
2142 }
2143
2144 /* after checking the subproblem for convexity, if the subproblem has convex constraints and continuous variables,
2145 * then the problem is entered into probing mode. Otherwise, it is initialised as a CIP
2146 */
2148 {
2149 /* if the user has not implemented a solve subproblem callback, then the subproblem solves are performed
2150 * internally. To be more efficient the subproblem is put into probing mode. */
2151 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
2152 && SCIPgetStage(subproblem) <= SCIP_STAGE_PROBLEM )
2153 {
2154 SCIP_Bool infeasible;
2155 SCIP_CALL( initialiseLPSubproblem(benders, set, i, &infeasible) );
2156
2157 /* if the initialisation process indicates that the LP is infeasible, then the complete problem is
2158 * infeasible. The subprobsinfeasible flag is set so that SCIP can be informed at the correct point
2159 * during the solving process.
2160 */
2161 if( infeasible )
2163 }
2164 }
2165 else
2166 {
2167 SCIP_EVENTHDLRDATA* eventhdlrdata_mipnodefocus;
2168 SCIP_EVENTHDLRDATA* eventhdlrdata_upperbound;
2169
2170 /* because the subproblems could be reused in the copy, the event handler is not created again. If the
2171 * threadsafe is TRUE, then it is assumed that the subproblems are not reused.
2172 * NOTE: This currently works with the benders_default implementation. It may not be very general. */
2173 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
2174 && (!benders->iscopy || benders->threadsafe) )
2175 {
2176 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata_mipnodefocus) );
2177 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata_upperbound) );
2178
2179 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata_mipnodefocus) );
2180 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata_upperbound) );
2181
2182 /* include the first LP solved event handler into the subproblem */
2184 MIPNODEFOCUS_EVENTHDLR_DESC, eventExecBendersMipnodefocus, eventhdlrdata_mipnodefocus) );
2185 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersMipnodefocus) );
2186 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersMipnodefocus) );
2187 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersMipnodefocus) );
2188 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersMipnodefocus) );
2189 assert(eventhdlr != NULL);
2190
2191 /* include the upper bound interrupt event handler into the subproblem */
2193 UPPERBOUND_EVENTHDLR_DESC, eventExecBendersUpperbound, eventhdlrdata_upperbound) );
2194 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersUpperbound) );
2195 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersUpperbound) );
2196 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersUpperbound) );
2197 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersUpperbound) );
2198 assert(eventhdlr != NULL);
2199 }
2200 }
2201 }
2202 else
2203 {
2204 /* a user must specify the subproblem type if they are not supplying a SCIP instance. */
2206 {
2207 SCIPerrorMessage("If the subproblem is set to NULL, then the subproblem type must be specified.\n");
2208 SCIPerrorMessage("In the subproblem creation callback, call SCIPbendersSetSubproblemType with the appropriate problem type.\n");
2209
2210 return SCIP_ERROR;
2211 }
2212 }
2213 }
2214
2215 /* checking the convexity of the master problem. This information is useful for the cut generation methods, such as
2216 * non-good and integer cuts
2217 */
2218 SCIP_CALL( checkSubproblemConvexity(benders, set, -1) );
2219
2220 benders->subprobscreated = TRUE;
2221
2222 return SCIP_OKAY;
2223}
2224
2226/** initializes Benders' decomposition */
2228 SCIP_BENDERS* benders, /**< Benders' decomposition */
2229 SCIP_SET* set /**< global SCIP settings */
2230 )
2231{
2232 int i;
2233
2234 assert(benders != NULL);
2235 assert(set != NULL);
2236
2237 if( benders->initialized )
2238 {
2239 SCIPerrorMessage("Benders' decomposition <%s> already initialized\n", benders->name);
2240 return SCIP_INVALIDCALL;
2241 }
2242
2243 if( set->misc_resetstat )
2244 {
2245 SCIPclockReset(benders->setuptime);
2246 SCIPclockReset(benders->bendersclock);
2247
2248 benders->ncalls = 0;
2249 benders->ncutsfound = 0;
2250 benders->ntransferred = 0;
2251 }
2252
2253 /* start timing */
2254 SCIPclockStart(benders->setuptime, set);
2255
2256 if( benders->bendersinit != NULL )
2257 {
2258 SCIP_CALL( benders->bendersinit(set->scip, benders) );
2259 }
2260
2261 benders->initialized = TRUE;
2262
2263 /* if the Benders' decomposition is a copy, then the auxiliary variables already exist. So they are registered with
2264 * the Benders' decomposition struct during the init stage. If the Benders' decomposition is not a copy, then the
2265 * auxiliary variables need to be created, which occurs in the initpre stage
2266 */
2267 if( benders->iscopy )
2268 {
2269 /* the copied auxiliary variables must be assigned to the target Benders' decomposition */
2270 SCIP_CALL( assignAuxiliaryVariables(set->scip, benders) );
2271 }
2272
2273 /* creates the subproblems and sets up the probing mode for LP subproblems. This function calls the benderscreatesub
2274 * callback. */
2275 SCIP_CALL( createSubproblems(benders, set) );
2276
2277 /* storing the solution tolerance set by the SCIP parameters */
2278 SCIP_CALL( SCIPsetGetRealParam(set, "benders/solutiontol", &benders->solutiontol) );
2279
2280 /* allocating memory for the stored constraints array */
2281 if( benders->storedcutssize == 0 )
2282 {
2285 benders->nstoredcuts = 0;
2286 }
2287
2288 /* initialising the Benders' cuts */
2290 for( i = 0; i < benders->nbenderscuts; i++ )
2291 {
2293 }
2294
2295 /* stop timing */
2296 SCIPclockStop(benders->setuptime, set);
2297
2298 return SCIP_OKAY;
2299}
2300
2301
2302/** Transfers Benders' cuts that were generated while solving a sub-SCIP to the original SCIP instance. This involves
2303 * creating a constraint/cut that is equivalent to the generated cut in the sub-SCIP. This new constraint/cut is then
2304 * added to the original SCIP instance.
2306static
2308 SCIP* sourcescip, /**< the source SCIP from when the Benders' decomposition was copied */
2309 SCIP_BENDERS* benders, /**< the Benders' decomposition structure of the sub SCIP */
2310 SCIP_VAR** vars, /**< the variables from the source constraint */
2311 SCIP_Real* vals, /**< the coefficients of the variables in the source constriant */
2312 SCIP_Real lhs, /**< the LHS of the source constraint */
2313 SCIP_Real rhs, /**< the RHS of the source constraint */
2314 int nvars /**< the number of variables in the source constraint */
2315 )
2316{
2317 SCIP_BENDERS* sourcebenders; /* the Benders' decomposition of the source SCIP */
2318 SCIP_CONSHDLR* consbenders; /* a helper variable for the Benders' decomposition constraint handler */
2319 SCIP_CONS* transfercons = NULL; /* the constraint that is generated to transfer the constraints/cuts */
2320 SCIP_ROW* transfercut = NULL; /* the cut that is generated to transfer the constraints/cuts */
2321 SCIP_VAR* sourcevar; /* the source variable that will be added to the transferred cut */
2322 SCIP_VAR* origvar;
2323 SCIP_Real scalar;
2324 SCIP_Real constant;
2325 char cutname[SCIP_MAXSTRLEN]; /* the name of the transferred cut */
2326 int i;
2327 SCIP_Bool fail;
2328
2329 assert(sourcescip != NULL);
2330 assert(benders != NULL);
2331 assert(vars != NULL);
2332 assert(vals != NULL);
2333
2334 /* retrieving the source Benders' decomposition structure */
2335 sourcebenders = SCIPfindBenders(sourcescip, SCIPbendersGetName(benders));
2336
2337 /* retrieving the Benders' decomposition constraint handler */
2338 consbenders = SCIPfindConshdlr(sourcescip, "benders");
2339
2340 /* setting the name of the transferred cut */
2341 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "transferredcut_%d",
2342 SCIPbendersGetNTransferredCuts(sourcebenders) );
2343
2344 /* TODO: It could be more efficient to pass an updated vars array with the vals array to the
2345 * SCIPcreateConsBasicLinear/SCIPcreateEmptyRowConshdlr. This should be implemented to improve the performance of the
2346 * Large Neighbourhood Benders Search.
2347 */
2348
2349 /* creating an empty row/constraint for the transferred cut */
2350 if( sourcebenders->cutsasconss )
2351 {
2352 SCIP_CALL( SCIPcreateConsBasicLinear(sourcescip, &transfercons, cutname, 0, NULL, NULL, lhs, rhs) );
2353 SCIP_CALL( SCIPsetConsRemovable(sourcescip, transfercons, TRUE) );
2354 }
2355 else
2356 {
2357 SCIP_CALL( SCIPcreateEmptyRowConshdlr(sourcescip, &transfercut, consbenders, cutname, lhs, rhs, FALSE,
2358 FALSE, TRUE) );
2359 }
2360
2361 fail = FALSE;
2362 for( i = 0; i < nvars; i++ )
2363 {
2364 /* getting the original variable for the transformed variable */
2365 origvar = vars[i];
2366 scalar = 1.0;
2367 constant = 0.0;
2368 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
2369
2370 /* getting the source var from the hash map */
2371 sourcevar = (SCIP_VAR*) SCIPhashmapGetImage(benders->mastervarsmap, origvar);
2372
2373 /* if the source variable is not found, then the mapping in incomplete. So the constraint can not be
2374 * transferred. */
2375 if( sourcevar == NULL )
2376 {
2377 fail = TRUE;
2378 break;
2379 }
2380
2381 if( sourcebenders->cutsasconss )
2382 {
2383 assert( transfercons != NULL );
2384 SCIP_CALL( SCIPaddCoefLinear(sourcescip, transfercons, sourcevar, vals[i]) ); /*lint !e644*/
2385 }
2386 else
2387 {
2388 assert( transfercut != NULL );
2389 SCIP_CALL( SCIPaddVarToRow(sourcescip, transfercut, sourcevar, vals[i]) ); /*lint !e644*/
2390 }
2391 }
2392
2393 /* if all of the source variables were found to generate the cut */
2394 if( !fail )
2395 {
2396 if( sourcebenders->cutsasconss )
2397 {
2398 SCIP_CALL( SCIPaddCons(sourcescip, transfercons) );
2399 }
2400 else
2401 {
2402 SCIP_CALL( SCIPaddPoolCut(sourcescip, transfercut) );
2403 }
2404
2405 sourcebenders->ntransferred++;
2406 }
2407
2408 /* release the row/constraint */
2409 if( sourcebenders->cutsasconss )
2410 {
2411 /* only release if the creation of the constraint failed. */
2412 SCIP_CALL( SCIPreleaseCons(sourcescip, &transfercons) );
2413 }
2414 else
2415 {
2416 SCIP_CALL( SCIPreleaseRow(sourcescip, &transfercut) );
2417 }
2418
2419 return SCIP_OKAY;
2420}
2421
2422
2423/** transfers the cuts generated in a subscip to the source scip */
2424static
2426 SCIP* sourcescip, /**< the source SCIP from when the Benders' decomposition was copied */
2427 SCIP* subscip, /**< the sub SCIP where the Benders' cuts were generated */
2428 SCIP_BENDERS* benders /**< the Benders' decomposition structure of the sub SCIP */
2429 )
2430{
2431 SCIP_BENDERS* sourcebenders; /* the Benders' decomposition of the source SCIP */
2432 SCIP_VAR** vars; /* the variables of the added constraint/row */
2433 SCIP_Real* vals; /* the values of the added constraint/row */
2434 SCIP_Real lhs; /* the LHS of the added constraint/row */
2435 SCIP_Real rhs; /* the RHS of the added constraint/row */
2436 int naddedcuts;
2437 int nvars;
2438 int i;
2439
2440 assert(subscip != NULL);
2441 assert(benders != NULL);
2442
2443 /* retrieving the source Benders' decomposition structure */
2444 sourcebenders = SCIPfindBenders(sourcescip, SCIPbendersGetName(benders));
2445
2446 /* exit if the cuts should not be transferred from the sub SCIP to the source SCIP. */
2447 if( !sourcebenders->transfercuts || benders->mastervarsmap == NULL )
2448 return SCIP_OKAY;
2449
2450 /* retrieving the number of stored Benders' cuts */
2451 naddedcuts = SCIPbendersGetNStoredCuts(benders);
2452
2453 /* looping over all added cuts to construct the cut for the source scip */
2454 for( i = 0; i < naddedcuts; i++ )
2455 {
2456 /* collecting the variable information from the constraint */
2457 SCIP_CALL( SCIPbendersGetStoredCutData(benders, i, &vars, &vals, &lhs, &rhs, &nvars) );
2458
2459 if( nvars > 0 )
2460 {
2461 /* create and add the cut to be transferred from the sub SCIP to the source SCIP */
2462 SCIP_CALL( createAndAddTransferredCut(sourcescip, benders, vars, vals, lhs, rhs, nvars) );
2463 }
2464 }
2465
2466 return SCIP_OKAY;
2467}
2468
2470/** calls exit method of Benders' decomposition */
2472 SCIP_BENDERS* benders, /**< Benders' decomposition */
2473 SCIP_SET* set /**< global SCIP settings */
2474 )
2475{
2476 int nsubproblems;
2477 int i;
2478
2479 assert(benders != NULL);
2480 assert(set != NULL);
2481
2482 if( !benders->initialized )
2483 {
2484 SCIPerrorMessage("Benders' decomposition <%s> not initialized\n", benders->name);
2485 return SCIP_INVALIDCALL;
2486 }
2487
2488 /* start timing */
2489 SCIPclockStart(benders->setuptime, set);
2490
2491 if( benders->bendersexit != NULL )
2492 {
2493 SCIP_CALL( benders->bendersexit(set->scip, benders) );
2494 }
2495
2496 /* if the Benders' decomposition is a copy, then is a variable mapping was provided, then the generated cuts will
2497 * be transferred to the source scip
2498 */
2499 if( benders->iscopy && benders->mastervarsmap != NULL )
2500 {
2501 SCIP_CALL( transferBendersCuts(benders->sourcescip, set->scip, benders) );
2502 }
2503
2504 /* releasing the stored constraints */
2505 for( i = benders->nstoredcuts - 1; i >= 0; i-- )
2506 {
2507 SCIPfreeBlockMemoryArray(set->scip, &benders->storedcuts[i]->vals, benders->storedcuts[i]->nvars);
2508 SCIPfreeBlockMemoryArray(set->scip, &benders->storedcuts[i]->vars, benders->storedcuts[i]->nvars);
2509 SCIPfreeBlockMemory(set->scip, &benders->storedcuts[i]); /*lint !e866*/
2510 }
2511
2512 BMSfreeBlockMemoryArray(SCIPblkmem(set->scip), &benders->storedcuts, benders->storedcutssize);
2513 benders->storedcutssize = 0;
2514 benders->nstoredcuts = 0;
2515
2516 /* releasing all of the auxiliary variables and constraints */
2517 nsubproblems = SCIPbendersGetNSubproblems(benders);
2518 for( i = 0; i < nsubproblems; i++ )
2519 {
2520 /* it is possible that the master problem is not solved. As such, the auxiliary variables will not be created. So
2521 * we don't need to release the variables or the constraints
2522 */
2523 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX && benders->auxiliaryvarcons[i] != NULL )
2524 {
2525 SCIP_CALL( SCIPreleaseCons(set->scip, &benders->auxiliaryvarcons[i]) );
2526 }
2527
2528 if( benders->auxiliaryvars[i] != NULL )
2529 {
2530 /* we need to remove the locks from the auxiliary variables. This will be called always for the highest priority
2531 * Benders' plugin and others if the auxiliary variables are not shared
2532 */
2533 if( !benders->iscopy && SCIPvarGetNLocksDown(benders->auxiliaryvars[i]) > 0 )
2535
2536 SCIP_CALL( SCIPreleaseVar(set->scip, &benders->auxiliaryvars[i]) );
2537 }
2538 }
2539
2540 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM && benders->auxiliaryvarcons[0] != NULL )
2541 {
2542 SCIP_CALL( SCIPreleaseCons(set->scip, &benders->auxiliaryvarcons[0]) );
2543 }
2544
2545 if( benders->masterauxvar != NULL )
2546 {
2547 /* we need to remove the locks from the auxiliary variables. This will be called always for the highest priority
2548 * Benders' plugin and others if the auxiliary variables are not shared
2549 */
2550 if( !benders->iscopy && SCIPvarGetNLocksDown(benders->masterauxvar) > 0 )
2551 {
2553 }
2554
2555 SCIP_CALL( SCIPreleaseVar(set->scip, &benders->masterauxvar) );
2556 }
2557
2559
2560 /* if a corepoint has been used for cut strengthening, then this needs to be freed */
2561 if( benders->corepoint != NULL )
2562 {
2563 SCIP_CALL( SCIPfreeSol(set->scip, &benders->corepoint) );
2564 }
2565
2566 /* calling the exit method for the Benders' cuts */
2568 for( i = 0; i < benders->nbenderscuts; i++ )
2569 {
2571 }
2572
2573 benders->initialized = FALSE;
2574
2575 /* stop timing */
2576 SCIPclockStop(benders->setuptime, set);
2577
2578 return SCIP_OKAY;
2579}
2580
2581/** Checks whether a subproblem is independent. */
2582static
2584 SCIP* scip, /**< the SCIP data structure */
2585 SCIP_BENDERS* benders /**< Benders' decomposition */
2586 )
2587{
2588 SCIP_VAR** vars;
2589 int nvars;
2590 int nsubproblems;
2591 int i;
2592 int j;
2593
2594 assert(scip != NULL);
2595 assert(benders != NULL);
2596
2597 /* retrieving the master problem variables */
2599
2600 nsubproblems = SCIPbendersGetNSubproblems(benders);
2601
2602 /* looping over all subproblems to check whether there exists at least one master problem variable */
2603 for( i = 0; i < nsubproblems; i++ )
2604 {
2605 /* if there are user defined solving or freeing functions, then it is not possible to declare the independence of
2606 * the subproblems.
2607 */
2608 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
2609 && benders->bendersfreesub == NULL )
2610 {
2611 SCIP_Bool independent = TRUE;
2612
2613 for( j = 0; j < nvars; j++ )
2614 {
2615 SCIP_VAR* subprobvar;
2616
2617 /* getting the subproblem problem variable corresponding to the master problem variable */
2618 SCIP_CALL( SCIPgetBendersSubproblemVar(scip, benders, vars[j], &subprobvar, i) );
2619
2620 /* if the subporblem variable is not NULL, then the subproblem depends on the master problem */
2621 if( subprobvar != NULL )
2622 {
2623 independent = FALSE;
2624 break;
2625 }
2626 }
2627
2628 /* setting the independent flag */
2629 SCIPbendersSetSubproblemIsIndependent(benders, i, independent);
2630 }
2631 }
2632
2633 return SCIP_OKAY;
2634}
2636/** informs the Benders' decomposition that the presolving process is being started */
2638 SCIP_BENDERS* benders, /**< Benders' decomposition */
2639 SCIP_SET* set, /**< global SCIP settings */
2640 SCIP_STAT* stat /**< dynamic problem statistics */
2641 )
2642{
2643 assert(benders != NULL);
2644 assert(set != NULL);
2645 assert(stat != NULL);
2646
2647 /* the arrays for the auxiliary variables and constraints are not allocated at the activate stage. This is because
2648 * SCIPbendersActivate can be called during SCIP_STAGE_PROBLEM. As such, the user may still change the objective type
2649 * after the Benders' decomposition has been activated. The memory allocation occurs immediately before the variables
2650 * are created, then freed in SCIPbendersExit.
2651 */
2652 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM )
2653 {
2655 }
2656 else
2657 {
2660 }
2661
2662 /* if the Benders' decomposition is the original, then the auxiliary variables need to be created. If the Benders'
2663 * decomposition is a copy, then the auxiliary variables already exist. The assignment of the auxiliary variables
2664 * occurs in bendersInit
2665 */
2666 if( !benders->iscopy )
2667 {
2668 /* check the subproblem independence. This check is only performed if the user has not implemented a solve
2669 * subproblem function.
2670 */
2671 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL )
2672 SCIP_CALL( checkSubproblemIndependence(set->scip, benders) );
2673
2674 /* adding the auxiliary variables to the master problem */
2675 SCIP_CALL( addAuxiliaryVariablesToMaster(set->scip, benders) );
2676 }
2677
2678 /* call presolving initialization method of Benders' decomposition */
2679 if( benders->bendersinitpre != NULL )
2680 {
2681 /* start timing */
2682 SCIPclockStart(benders->setuptime, set);
2683
2684 SCIP_CALL( benders->bendersinitpre(set->scip, benders) );
2685
2686 /* stop timing */
2687 SCIPclockStop(benders->setuptime, set);
2688 }
2689
2690 return SCIP_OKAY;
2691}
2692
2694/** informs the Benders' decomposition that the presolving process has completed */
2696 SCIP_BENDERS* benders, /**< Benders' decomposition */
2697 SCIP_SET* set, /**< global SCIP settings */
2698 SCIP_STAT* stat /**< dynamic problem statistics */
2699 )
2700{
2701 assert(benders != NULL);
2702 assert(set != NULL);
2703 assert(stat != NULL);
2704
2705 /* call presolving deinitialization method of Benders' decomposition */
2706 if( benders->bendersexitpre != NULL )
2707 {
2708 /* start timing */
2709 SCIPclockStart(benders->setuptime, set);
2710
2711 SCIP_CALL( benders->bendersexitpre(set->scip, benders) );
2712
2713 /* stop timing */
2714 SCIPclockStop(benders->setuptime, set);
2715 }
2716
2717 return SCIP_OKAY;
2718}
2720/** informs Benders' decomposition that the branch and bound process is being started */
2722 SCIP_BENDERS* benders, /**< Benders' decomposition */
2723 SCIP_SET* set /**< global SCIP settings */
2724 )
2725{
2726 int i;
2727
2728 assert(benders != NULL);
2729 assert(set != NULL);
2730
2731 /* call solving process initialization method of Benders' decomposition */
2732 if( benders->bendersinitsol != NULL )
2733 {
2734 /* start timing */
2735 SCIPclockStart(benders->setuptime, set);
2736
2737 SCIP_CALL( benders->bendersinitsol(set->scip, benders) );
2738
2739 /* stop timing */
2740 SCIPclockStop(benders->setuptime, set);
2741 }
2742
2743 /* calling the initsol method for the Benders' cuts */
2745 for( i = 0; i < benders->nbenderscuts; i++ )
2746 {
2748 }
2749
2750 return SCIP_OKAY;
2751}
2753/** informs Benders' decomposition that the branch and bound process data is being freed */
2755 SCIP_BENDERS* benders, /**< Benders' decomposition */
2756 SCIP_SET* set /**< global SCIP settings */
2757 )
2758{
2759 int nsubproblems;
2760 int i;
2761
2762 assert(benders != NULL);
2763 assert(set != NULL);
2764
2765 nsubproblems = SCIPbendersGetNSubproblems(benders);
2766 /* freeing all subproblems that are independent, this is because they have not bee freed during the subproblem
2767 * solving loop.
2768 */
2769 for( i = 0; i < nsubproblems; i++ )
2770 {
2772 {
2773 /* disabling the independence of the subproblem so that it can be freed */
2775
2776 /* freeing the independent subproblem */
2778 }
2779 }
2780
2781 /* call solving process deinitialization method of Benders' decomposition */
2782 if( benders->bendersexitsol != NULL )
2783 {
2784 /* start timing */
2785 SCIPclockStart(benders->setuptime, set);
2786
2787 SCIP_CALL( benders->bendersexitsol(set->scip, benders) );
2788
2789 /* stop timing */
2790 SCIPclockStop(benders->setuptime, set);
2791 }
2792
2793 /* sorting the Benders' decomposition cuts in order of priority. Only a single cut is generated for each subproblem
2794 * per solving iteration. This is particularly important in the case of the optimality and feasibility cuts. Since
2795 * these work on two different solutions to the subproblem, it is not necessary to generate both cuts. So, once the
2796 * feasibility cut is generated, then no other cuts will be generated.
2797 */
2799
2800 /* calling the exitsol method for the Benders' cuts */
2801 for( i = 0; i < benders->nbenderscuts; i++ )
2802 {
2804 }
2805
2806 return SCIP_OKAY;
2807}
2809/** activates Benders' decomposition such that it is called in LP solving loop */
2811 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
2812 SCIP_SET* set, /**< global SCIP settings */
2813 int nsubproblems /**< the number subproblems used in this decomposition */
2814 )
2815{
2816 SCIP_EVENTHDLR* eventhdlr;
2817 SCIP_EVENTHDLRDATA* eventhdlrdata;
2818 int i;
2819
2820 assert(benders != NULL);
2821 assert(set != NULL);
2822 assert(set->stage == SCIP_STAGE_INIT || set->stage == SCIP_STAGE_PROBLEM);
2823
2824 if( !benders->active )
2825 {
2826 benders->active = TRUE;
2827 set->nactivebenders++;
2828 set->benderssorted = FALSE;
2829
2830 benders->nsubproblems = nsubproblems;
2831 benders->nactivesubprobs = nsubproblems;
2832 benders->prevlowerbound = -SCIPsetInfinity(set);
2833 benders->strengthenround = FALSE;
2834
2835 /* allocating memory for the subproblems arrays */
2843 SCIP_ALLOC( BMSallocMemoryArray(&benders->solvestat, benders->nsubproblems) );
2854
2855 /* creating the priority queue for the subproblem solving status */
2856 SCIP_CALL( SCIPpqueueCreate(&benders->subprobqueue, benders->nsubproblems, 1.1,
2857 benders->benderssubcomp == NULL ? benderssubcompdefault : benders->benderssubcomp, NULL) );
2858
2859 for( i = 0; i < benders->nsubproblems; i++ )
2860 {
2861 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
2862
2864
2865 benders->subproblems[i] = NULL;
2866 benders->auxiliaryvars[i] = NULL;
2868 benders->nsubmastervars[i] = 0;
2869 benders->nsubmasterbinvars[i] = 0;
2870 benders->nsubmasterintvars[i] = 0;
2871 benders->subprobobjval[i] = SCIPsetInfinity(set);
2873 benders->subproblowerbound[i] = -SCIPsetInfinity(set);
2875 benders->subprobisconvex[i] = FALSE;
2876 benders->subprobisnonlinear[i] = FALSE;
2877 benders->subprobsetup[i] = FALSE;
2878 benders->indepsubprob[i] = FALSE;
2879 benders->subprobenabled[i] = TRUE;
2880 benders->mastervarscont[i] = FALSE;
2881
2882 /* initialising the subproblem solving status */
2883 SCIP_ALLOC( BMSallocMemory(&solvestat) );
2884 solvestat->idx = i;
2885 solvestat->ncalls = 0;
2886 solvestat->avgiter = 0;
2887 benders->solvestat[i] = solvestat;
2888
2889 /* inserting the initial elements into the priority queue */
2890 SCIP_CALL( SCIPpqueueInsert(benders->subprobqueue, benders->solvestat[i]) );
2891 }
2892
2894 {
2895 /* adding an eventhandler for updating the lower bound when the root node is solved. */
2896 eventhdlrdata = (SCIP_EVENTHDLRDATA*)benders;
2897
2898 /* include event handler into SCIP */
2900 eventExecBendersNodesolved, eventhdlrdata) );
2901 SCIP_CALL( SCIPsetEventhdlrInitsol(set->scip, eventhdlr, eventInitsolBendersNodesolved) );
2902 assert(eventhdlr != NULL);
2903 }
2904 }
2905
2906 return SCIP_OKAY;
2907}
2909/** deactivates Benders' decomposition such that it is no longer called in LP solving loop */
2911 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
2912 SCIP_SET* set /**< global SCIP settings */
2913 )
2914{
2915 int i;
2916
2917 assert(benders != NULL);
2918 assert(set != NULL);
2919 assert(set->stage == SCIP_STAGE_INIT || set->stage == SCIP_STAGE_PROBLEM);
2920
2921 if( benders->active )
2922 {
2923 SCIP_EVENTHDLR* eventhdlr;
2924 int nsubproblems;
2925
2926 nsubproblems = SCIPbendersGetNSubproblems(benders);
2927
2928#ifndef NDEBUG
2929 /* checking whether the auxiliary variables and subproblems are all NULL */
2930 for( i = 0; i < nsubproblems; i++ )
2931 assert(benders->auxiliaryvars[i] == NULL);
2932#endif
2933
2934 /* if the subproblems were created by the Benders' decomposition core, then they need to be freed */
2935 if( benders->freesubprobs )
2936 {
2937 for( i = SCIPbendersGetNSubproblems(benders) - 1; i >= 0; i-- )
2938 {
2939 SCIP* subproblem = SCIPbendersSubproblem(benders, i);
2940 SCIP_CALL( SCIPfree(&subproblem) );
2941 }
2942 }
2943
2944 benders->active = FALSE;
2945 set->nactivebenders--;
2946 set->benderssorted = FALSE;
2947
2948 /* freeing the priority queue memory */
2949 SCIPpqueueFree(&benders->subprobqueue);
2950
2951 for( i = nsubproblems - 1; i >= 0; i-- )
2952 BMSfreeMemory(&benders->solvestat[i]);
2953
2954 /* freeing the master variable storage if it exists */
2955 for( i = nsubproblems - 1; i >= 0; i-- )
2957
2958 /* freeing the memory allocated during the activation of the Benders' decomposition */
2969 BMSfreeMemoryArray(&benders->solvestat);
2977
2978 benders->ncalls = 0;
2979 benders->ncutsfound = 0;
2980 benders->ntransferred = 0;
2981
2982 benders->naddedsubprobs = 0;
2983 benders->nconvexsubprobs = 0;
2984 benders->nnonlinearsubprobs = 0;
2985 benders->subprobscreated = FALSE;
2986 benders->freesubprobs = FALSE;
2987 benders->masterisnonlinear = FALSE;
2988
2989 benders->nstrengthencuts = 0;
2990 benders->nstrengthencalls = 0;
2991 benders->nstrengthenfails = 0;
2992
2993 benders->npseudosols = 0;
2994 benders->feasibilityphase = FALSE;
2995
2996 /* dropping the event from the node solved event handler */
2998 if( eventhdlr != NULL && SCIPsetGetStage(set) >= SCIP_STAGE_INITSOLVE )
2999 {
3000 SCIP_CALL( SCIPdropEvent(set->scip, SCIP_EVENTTYPE_NODESOLVED, eventhdlr, NULL, -1) );
3001 }
3002 }
3003
3004 return SCIP_OKAY;
3005}
3007/** returns whether the given Benders' decomposition is in use in the current problem */
3009 SCIP_BENDERS* benders /**< the Benders' decomposition structure */
3010 )
3011{
3012 assert(benders != NULL);
3013
3014 return benders->active;
3015}
3016
3017/** updates the lower bound for all auxiliary variables. This is called if the first LP enforced is unbounded. */
3018static
3020 SCIP_BENDERS* benders, /**< Benders' decomposition */
3021 SCIP_SET* set, /**< global SCIP settings */
3022 SCIP_RESULT* result /**< the result from updating the auxiliary variable lower bound */
3023 )
3024{
3025 int nsubproblems;
3026 int i;
3027
3028 assert(benders != NULL);
3029 assert(set != NULL);
3030
3031 (*result) = SCIP_DIDNOTRUN;
3032
3033 nsubproblems = SCIPbendersGetNSubproblems(benders);
3034
3035 for( i = 0; i < nsubproblems; i++ )
3036 {
3037 SCIP_VAR* auxiliaryvar;
3038 SCIP_Real lowerbound;
3039 SCIP_Bool infeasible;
3040
3041 infeasible = FALSE;
3042
3043 /* computing the lower bound of the subproblem by solving it without any variable fixings */
3044 SCIP_CALL( SCIPbendersComputeSubproblemLowerbound(benders, set, i, &lowerbound, &infeasible) );
3045
3046 /* if the subproblem is infeasible, then the original problem is infeasible */
3047 if( infeasible )
3048 {
3049 (*result) = SCIP_INFEASIBLE;
3050 break;
3051 }
3052
3053 /* retrieving the auxiliary variable */
3054 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, i);
3055
3056 /* only update the lower bound if it is greater than the current lower bound */
3057 if( SCIPsetIsGT(set, lowerbound, SCIPvarGetLbGlobal(auxiliaryvar)) )
3058 {
3059 SCIPsetDebugMsg(set, "Tightened lower bound of <%s> to %g\n", SCIPvarGetName(auxiliaryvar), lowerbound);
3060 /* updating the lower bound of the auxiliary variable */
3061 SCIP_CALL( SCIPchgVarLb(set->scip, auxiliaryvar, lowerbound) );
3062 (*result) = SCIP_REDUCEDDOM;
3063 }
3064
3065 /* stores the lower bound for the subproblem */
3066 SCIPbendersUpdateSubproblemLowerbound(benders, i, lowerbound);
3067 }
3068
3069 return SCIP_OKAY;
3070}
3071
3072/** sets the core point used for cut strengthening. If the strenghtenintpoint is set to 'i', then the core point is
3073 * reinitialised each time the incumbent is updated
3075static
3077 SCIP* scip, /**< the SCIP data structure */
3078 SCIP_BENDERS* benders /**< Benders' decomposition */
3079 )
3080{
3081 SCIP_SOL* bestsol;
3082
3083 assert(scip != NULL);
3084 assert(benders != NULL);
3085
3086 /* if the core point is not NULL and the interior point is not reinitialised, then nothing is done */
3087 if( benders->corepoint != NULL && benders->strengthenintpoint != 'i' )
3088 return SCIP_OKAY;
3089
3090 bestsol = SCIPgetBestSol(scip);
3091
3092 /* if the core point should be updated, then this only happens if the incumbent solution has been updated */
3093 if( benders->strengthenintpoint == 'i' && benders->initcorepoint == bestsol )
3094 return SCIP_OKAY;
3095
3096 /* if a corepoint has been used for cut strengthening, then this needs to be freed */
3097 if( benders->corepoint != NULL )
3098 {
3099 SCIP_CALL( SCIPfreeSol(scip, &benders->corepoint) );
3100 }
3101
3102 switch( benders->strengthenintpoint )
3103 {
3104 SCIP_VAR** vars;
3105 SCIP_Real timelimit;
3106 int nvars;
3107 int i;
3108
3109 case 'l':
3111 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
3112 break;
3113 case 'f':
3114 case 'i':
3115 SCIP_CALL( SCIPcreateSolCopy(scip, &benders->corepoint, bestsol) );
3116 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
3117 benders->initcorepoint = bestsol;
3118 break;
3119 case 'r':
3120 /* prepare time limit */
3121 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3122 if ( ! SCIPisInfinity(scip, timelimit) )
3123 timelimit -= SCIPgetSolvingTime(scip);
3124
3125 /* if there is time remaining, then compute the relative interior point. Otherwise, return the LP solution */
3126 if ( timelimit > 0.0 )
3127 {
3128 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, 0, "Computing relative interior point (time limit: %g, iter limit: %d) ...\n", timelimit, INT_MAX);
3129 SCIP_CALL( SCIPcomputeLPRelIntPoint(scip, TRUE, FALSE, timelimit, INT_MAX, &benders->corepoint) );
3130 }
3131 else
3132 {
3134 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
3135 }
3136 break;
3137 case 'z':
3138 SCIP_CALL( SCIPcreateSol(scip, &benders->corepoint, NULL) );
3139 break;
3140 case 'o':
3141 SCIP_CALL( SCIPcreateSol(scip, &benders->corepoint, NULL) );
3142
3143 /* getting the variable data so that the */
3145
3146 /* setting all variable values to 1.0 */
3147 for( i = 0; i < nvars; i++ )
3148 {
3149 SCIP_CALL( SCIPsetSolVal(scip, benders->corepoint, vars[i], 1.0) );
3150 }
3151 break;
3152 default:
3154 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
3155 }
3156
3157 return SCIP_OKAY;
3158}
3159
3160/** performs cut strengthening by using an interior solution to generate cuts */
3161static
3163 SCIP_BENDERS* benders, /**< Benders' decomposition */
3164 SCIP_SET* set, /**< global SCIP settings */
3165 SCIP_SOL* sol, /**< primal CIP solution */
3166 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3167 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
3168 SCIP_Bool perturbsol, /**< should the solution be perturbed to escape infeasibility? */
3169 SCIP_Bool* auxviol, /**< set to TRUE only if the solution is feasible but the aux vars are violated */
3170 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
3171 SCIP_Bool* skipsolve, /**< should the main solve be skipped as a result of this strengthening? */
3172 SCIP_RESULT* result /**< result of the pricing process */
3173 )
3174{
3175 SCIP_SOL* sepapoint;
3176 SCIP_VAR** vars;
3177 int prevcutsfound;
3178 int nvars;
3179 int i;
3180
3181 assert(benders != NULL);
3182 assert(set != NULL);
3183
3184 (*result) = SCIP_DIDNOTRUN;
3185 (*skipsolve) = FALSE;
3186
3187 /* the cut stabilisation is only performed when enforcing LP solutions. The solution is not NULL if the stabilisation
3188 * is currently being performed. It is important to avoid recursion
3189 */
3190 if( type != SCIP_BENDERSENFOTYPE_LP || sol != NULL )
3191 return SCIP_OKAY;
3192
3193 /* checking if a change to the lower bound has occurred */
3194 if( SCIPsetIsGT(set, SCIPgetLowerbound(set->scip), benders->prevlowerbound)
3195 || SCIPgetCurrentNode(set->scip) != benders->prevnode )
3196 {
3197 benders->prevnode = SCIPgetCurrentNode(set->scip);
3198 benders->prevlowerbound = SCIPgetLowerbound(set->scip);
3199 benders->noimprovecount = 0;
3200 }
3201 else
3202 benders->noimprovecount++;
3203
3204 /* if the number of iterations without improvement exceeds 3*noimprovelimit, then the no stabilisation is performed
3205 */
3206 if( benders->noimprovecount > 3*benders->noimprovelimit )
3207 return SCIP_OKAY;
3208
3209 /* if there is no incumbent solution, then it is not possible to create the core point and hence the strengthening
3210 * can not be performed
3211 */
3212 if( SCIPgetBestSol(set->scip) == NULL )
3213 return SCIP_OKAY;
3214
3215 /* if no LP iterations have been performed since the last call of the cut strenghtening, then the strengthening is
3216 * aborted
3217 */
3218 if( benders->prevnlpiter == SCIPgetNLPIterations(set->scip) )
3219 return SCIP_OKAY;
3220
3221 benders->prevnlpiter = SCIPgetNLPIterations(set->scip);
3222
3223 /* if the separation point solution is NULL, then we create the solution using the current LP relaxation. */
3224 SCIP_CALL( setAndUpdateCorePoint(set->scip, benders) );
3225
3226 /* creating the separation point
3227 * TODO: This could be a little to memory heavy, it may be better just to create the separation point once and then
3228 * update it each time.
3229 */
3230 SCIP_CALL( SCIPcreateLPSol(set->scip, &sepapoint, NULL) );
3231 SCIP_CALL( SCIPunlinkSol(set->scip, sepapoint) );
3232
3234 assert(vars != NULL);
3235
3236 /* creating a solution that is a convex combination of the LP solution and the separation point */
3237 for( i = 0; i < nvars; i++ )
3238 {
3239 SCIP_VAR* subvar;
3240 SCIP_Real corepointval;
3241 SCIP_Real lpsolval;
3242 SCIP_Real newsolval;
3243 int j;
3244
3245 corepointval = SCIPgetSolVal(set->scip, benders->corepoint, vars[i]);
3246 lpsolval = SCIPgetSolVal(set->scip, sol, vars[i]);
3247 newsolval = lpsolval;
3248
3249 /* checking whether the master variable is mapped to any subproblem variables */
3250 subvar = NULL;
3251 j = 0;
3252 while( subvar == NULL && j < SCIPgetBendersNSubproblems(set->scip, benders) )
3253 {
3254 SCIP_CALL( SCIPgetBendersSubproblemVar(set->scip, benders, vars[i], &subvar, j) );
3255 j++;
3256 }
3257
3258 /* if the variable is a linking variable and it is not fixed, then a convex combination with the corepoint is
3259 * computed.
3260 */
3261 if( subvar != NULL && SCIPvarGetStatus(vars[i]) != SCIP_VARSTATUS_FIXED )
3262 {
3263 /* if the number of iterations without improvement exceeds noimprovelimit, then no convex combination is
3264 * created
3265 */
3266 if( !perturbsol && benders->noimprovecount <= benders->noimprovelimit )
3267 {
3268 newsolval = lpsolval*benders->convexmult + corepointval*(1 - benders->convexmult);
3269
3270 /* updating the core point */
3271 SCIP_CALL( SCIPsetSolVal(set->scip, benders->corepoint, vars[i], newsolval) );
3272 }
3273
3274 /* if the number of iterations without improvement is less than 2*noimprovelimit, then perturbation is
3275 * performed
3276 * TODO: This should be a random vector!!!!
3277 */
3278 if( perturbsol || benders->noimprovecount <= 2*benders->noimprovelimit )
3279 newsolval += benders->perturbeps;
3280 }
3281
3282 /* updating the separation point */
3283 SCIP_CALL( SCIPsetSolVal(set->scip, sepapoint, vars[i], newsolval) );
3284 }
3285
3286 /* storing the number of cuts found */
3287 prevcutsfound = SCIPbendersGetNCutsFound(benders);
3288
3289 SCIPsetDebugMsg(set, "solving Benders' decomposition subproblems with stabilised point.\n");
3290
3291 /* calling the subproblem solving method to generate cuts from the separation solution */
3292 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sepapoint, result, infeasible, auxviol, type, checkint) );
3293
3294 SCIPsetDebugMsg(set, "solved Benders' decomposition subproblems with stabilised point. noimprovecount %d result %d\n",
3295 benders->noimprovecount, (*result));
3296
3297 /* if constraints were added, then the main Benders' solving loop is skipped. */
3298 if( !(*infeasible) && ((*result) == SCIP_CONSADDED || (*result) == SCIP_SEPARATED) )
3299 (*skipsolve) = TRUE;
3300
3301 /* capturing cut strengthening statistics */
3302 benders->nstrengthencalls++;
3303 benders->nstrengthencuts += (SCIPbendersGetNCutsFound(benders) - prevcutsfound);
3304
3305 /* if no cuts were added, then the strengthening round is marked as failed */
3306 if( SCIPbendersGetNCutsFound(benders) == prevcutsfound )
3307 benders->nstrengthenfails++;
3308
3309 /* freeing the sepapoint solution */
3310 SCIP_CALL( SCIPfreeSol(set->scip, &sepapoint) );
3311
3312 return SCIP_OKAY;
3313}
3314
3315
3316/** Returns whether only the convex relaxations will be checked in this solve loop
3317 * when Benders' is used in the LNS heuristics, only the convex relaxations of the master/subproblems are checked,
3318 * i.e. no integer cuts are generated. In this case, then Benders' decomposition is performed under the assumption
3319 * that all subproblems are convex relaxations.
3320 */
3322 SCIP_BENDERS* benders, /**< Benders' decomposition */
3323 SCIP_Bool subscipsoff /**< flag indicating whether plugins using sub-SCIPs are deactivated */
3324 )
3325{
3326 return benders->iscopy && benders->lnscheck && subscipsoff;
3327}
3328
3329/** returns the number of subproblems that will be checked in this iteration */
3330static
3332 SCIP_BENDERS* benders, /**< Benders' decomposition */
3333 SCIP_SET* set, /**< global SCIP settings */
3334 SCIP_BENDERSENFOTYPE type /**< the type of solution being enforced */
3335 )
3336{
3337 if( benders->ncalls == 0 || type == SCIP_BENDERSENFOTYPE_CHECK
3339 return SCIPbendersGetNSubproblems(benders);
3340 else
3341 return (int) SCIPsetCeil(set, (SCIP_Real) SCIPbendersGetNSubproblems(benders)*benders->subprobfrac);
3342}
3343
3344/** returns whether the solving of the given subproblem needs to be executed */
3345static
3347 SCIP_BENDERS* benders, /**< Benders' decomposition */
3348 int probnumber /**< the subproblem index */
3349 )
3350{
3351 return (!SCIPbendersSubproblemIsIndependent(benders, probnumber)
3352 && SCIPbendersSubproblemIsEnabled(benders, probnumber));
3353}
3354
3355/** creates an ordered list of subproblem indices to be solved */
3356static
3358 SCIP_BENDERS* benders, /**< Benders' decomposition */
3359 SCIP_SET* set, /**< global SCIP settings */
3360 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3361 int** solveidx, /**< a list of subproblem indices to the solved in the current iteration */
3362 int* nsolveidx /**< the number of subproblem indices in the list */
3363 )
3364{
3365 int nsubproblems;
3366 int numtocheck;
3367 int subproblemcount;
3368
3369 assert(benders != NULL);
3370 assert(set != NULL);
3371 assert((*solveidx) != NULL);
3372 assert(nsolveidx != NULL);
3374
3375 nsubproblems = SCIPbendersGetNSubproblems(benders);
3376
3377 /* it is possible to only solve a subset of subproblems. This is given by a parameter. */
3378 numtocheck = numSubproblemsToCheck(benders, set, type);
3379
3380 (*nsolveidx) = 0;
3381
3382 subproblemcount = 0;
3383 while( subproblemcount < nsubproblems && subproblemcount < numtocheck )
3384 {
3385 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
3386
3388 (*solveidx)[(*nsolveidx)] = solvestat->idx;
3389 (*nsolveidx)++;
3390
3391 subproblemcount++;
3392 }
3393}
3394
3395/** updates the subproblem solving statistics and inserts the indices into the queue */
3396static
3398 SCIP_BENDERS* benders, /**< Benders' decomposition */
3399 int* solveidx, /**< the list of indices of subproblems that were solved */
3400 int nsolveidx, /**< the number of subproblem indices */
3401 SCIP_Bool updatestat /**< should the statistics be updated */
3402 )
3403{
3404 int i;
3405
3406 assert(benders != NULL);
3407 assert(solveidx != NULL);
3408
3409 for( i = 0; i < nsolveidx; i++ )
3410 {
3411 SCIP* subproblem;
3412 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
3413
3414 subproblem = SCIPbendersSubproblem(benders, solveidx[i]);
3415 solvestat = benders->solvestat[solveidx[i]];
3416 assert(solvestat->idx == solveidx[i]);
3417
3418 /* updating the solving statistics */
3419 if( updatestat )
3420 {
3421 if( !subproblemIsActive(benders, solveidx[i]) || subproblem == NULL )
3422 solvestat->avgiter = 1;
3423 else
3424 solvestat->avgiter = (SCIP_Real)(solvestat->avgiter*solvestat->ncalls + SCIPgetNLPIterations(subproblem))
3425 /(SCIP_Real)(solvestat->ncalls + 1);
3426 solvestat->ncalls++;
3427 }
3428
3429 /* inserting the solving statistics into the priority queue */
3430 SCIP_CALL( SCIPpqueueInsert(benders->subprobqueue, solvestat) );
3431 }
3432
3434
3435 return SCIP_OKAY;
3436}
3437
3438/** Solves each of the Benders' decomposition subproblems for the given solution. All, or a fraction, of subproblems are
3439 * solved before the Benders' decomposition cuts are generated.
3440 * Since a convex relaxation of the subproblem could be solved to generate cuts, a parameter nverified is used to
3441 * identified the number of subproblems that have been solved in their "original" form. For example, if the subproblem
3442 * is a MIP, then if the LP is solved to generate cuts, this does not constitute a verification. The verification is
3443 * only performed when the MIP is solved.
3445static
3447 SCIP_BENDERS* benders, /**< Benders' decomposition */
3448 SCIP_SET* set, /**< global SCIP settings */
3449 SCIP_SOL* sol, /**< primal CIP solution */
3450 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3451 SCIP_BENDERSSOLVELOOP solveloop, /**< the current solve loop */
3452 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
3453 int* nverified, /**< the number of subproblems verified in the current loop */
3454 int* solveidx, /**< the indices of subproblems to be solved in this loop */
3455 int nsolveidx, /**< the number of subproblems to be solved in this loop */
3456 SCIP_Bool** subprobsolved, /**< an array indicating the subproblems that were solved in this loop. */
3457 SCIP_BENDERSSUBSTATUS** substatus, /**< array to store the status of the subsystem */
3458 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
3459 SCIP_Bool* optimal, /**< is the current solution optimal? */
3460 SCIP_Bool* stopped /**< was the solving process stopped? */
3461 )
3462{
3463 SCIP_Bool onlyconvexcheck;
3464 int i;
3465 int j;
3466
3467 SCIP_RETCODE retcode = SCIP_OKAY;
3468
3469 assert(benders != NULL);
3470 assert(set != NULL);
3471
3472 /* in the case of an LNS check, only the convex relaxations of the subproblems will be solved. This is a performance
3473 * feature, since solving the convex relaxation is typically much faster than solving the corresponding CIP. While
3474 * the CIP is not solved during the LNS check, the solutions are still of higher quality than when Benders' is not
3475 * employed.
3476 */
3477 onlyconvexcheck = SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set));
3478
3479 SCIPsetDebugMsg(set, "Performing the subproblem solving process. Number of subproblems to check %d\n", nsolveidx);
3480
3481 SCIPsetDebugMsg(set, "Benders' decomposition - solve loop %d\n", solveloop);
3482
3483 if( type == SCIP_BENDERSENFOTYPE_CHECK && sol == NULL )
3484 {
3485 /* TODO: Check whether this is absolutely necessary. I think that this if statment can be removed. */
3486 (*infeasible) = TRUE;
3487 }
3488 else
3489 {
3490 /* solving each of the subproblems for Benders' decomposition */
3491 /* TODO: ensure that the each of the subproblems solve and update the parameters with the correct return values
3492 */
3493 for( j = 0; j < nsolveidx; j++ )
3494 {
3495 SCIP_Bool subinfeas = FALSE;
3496 SCIP_Bool convexsub;
3497 SCIP_Bool solvesub = TRUE;
3498 SCIP_Bool solved;
3499
3500 i = solveidx[j];
3502
3503 /* the subproblem is initially flagged as not solved for this solving loop */
3504 (*subprobsolved)[i] = FALSE;
3505
3506 /* setting the subsystem status to UNKNOWN at the start of each solve loop */
3507 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_UNKNOWN;
3508
3509 /* for the second solving loop, if the problem is an LP, it is not solved again. If the problem is a MIP,
3510 * then the subproblem objective function value is set to infinity. However, if the subproblem is proven
3511 * infeasible from the LP, then the IP loop is not performed.
3512 * If the solve loop is SCIP_BENDERSSOLVELOOP_USERCIP, then nothing is done. It is assumed that the user will
3513 * correctly update the objective function within the user-defined solving function.
3514 */
3515 if( solveloop == SCIP_BENDERSSOLVELOOP_CIP )
3516 {
3517 if( convexsub )
3518 solvesub = FALSE;
3519 else
3520 {
3523 }
3524 }
3525
3526 /* if the subproblem is independent, then it does not need to be solved. In this case, the nverified flag will
3527 * increase by one. When the subproblem is not independent, then it needs to be checked.
3528 */
3529 if( !subproblemIsActive(benders, i) )
3530 {
3531 /* NOTE: There is no need to update the optimal flag. This is because optimal is always TRUE until a
3532 * non-optimal subproblem is found.
3533 */
3534 /* if the auxiliary variable value is infinity, then the subproblem has not been solved yet. Currently the
3535 * subproblem statue is unknown. */
3539 {
3542
3543 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_UNKNOWN;
3544 (*optimal) = FALSE;
3545
3546 SCIPsetDebugMsg(set, "Benders' decomposition: subproblem %d is not active, but has not been solved."
3547 " setting status to UNKNOWN\n", i);
3548 }
3549 else
3550 {
3552 SCIPbendersGetAuxiliaryVarVal(benders, set, sol, i)) < benders->solutiontol )
3553 {
3555 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_OPTIMAL;
3556 }
3557 else
3558 {
3560 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_AUXVIOL;
3561 }
3562
3563 SCIPsetDebugMsg(set, "Benders' decomposition: subproblem %d is not active, setting status to OPTIMAL\n", i);
3564 }
3565
3566 (*subprobsolved)[i] = TRUE;
3567
3568 /* the nverified counter is only increased in the convex solving loop */
3569 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX )
3570 (*nverified)++;
3571 }
3572 else if( solvesub )
3573 {
3574 retcode = SCIPbendersExecSubproblemSolve(benders, set, sol, i, solveloop, FALSE, &solved, &subinfeas, type);
3575
3576 /* the solution for the subproblem is only processed if the return code is SCIP_OKAY */
3577 if( retcode == SCIP_OKAY )
3578 {
3579#ifdef SCIP_DEBUG
3580 if( type == SCIP_BENDERSENFOTYPE_LP )
3581 {
3582 SCIPsetDebugMsg(set, "Enfo LP: Subproblem %d Type %d (%f < %f)\n", i,
3585 }
3586#endif
3587 (*subprobsolved)[i] = solved;
3588
3589 (*infeasible) = (*infeasible) || subinfeas;
3590 if( subinfeas )
3591 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_INFEAS;
3592
3593 /* if the subproblems are solved to check integer feasibility, then the optimality check must be performed.
3594 * This will only be performed if checkint is TRUE and the subproblem was solved. The subproblem may not be
3595 * solved if the user has defined a solving function
3596 */
3597 if( checkint && (*subprobsolved)[i] )
3598 {
3599 /* if the subproblem is feasible, then it is necessary to update the value of the auxiliary variable to the
3600 * objective function value of the subproblem.
3601 */
3602 if( !subinfeas )
3603 {
3604 SCIP_Bool subproboptimal;
3605
3606 subproboptimal = SCIPbendersSubproblemIsOptimal(benders, set, sol, i);
3607
3608 if( subproboptimal )
3609 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_OPTIMAL;
3610 else
3611 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_AUXVIOL;
3612
3613 /* It is only possible to determine the optimality of a solution within a given subproblem in four
3614 * different cases:
3615 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX or USERCONVEX and the subproblem is convex.
3616 * ii) solveloop == SCIP_BENDERSOLVELOOP_CONVEX and only the convex relaxations will be checked.
3617 * iii) solveloop == SCIP_BENDERSSOLVELOOP_USERCIP and the subproblem was solved, since the user has
3618 * defined a solve function, it is expected that the solving is correctly executed.
3619 * iv) solveloop == SCIP_BENDERSSOLVELOOP_CIP and the MIP for the subproblem has been solved.
3620 */
3621 if( convexsub || onlyconvexcheck
3622 || solveloop == SCIP_BENDERSSOLVELOOP_CIP
3623 || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
3624 (*optimal) = (*optimal) && subproboptimal;
3625
3626#ifdef SCIP_DEBUG
3627 if( convexsub || solveloop >= SCIP_BENDERSSOLVELOOP_CIP )
3628 {
3629 if( subproboptimal )
3630 {
3631 SCIPsetDebugMsg(set, "Subproblem %d is Optimal (%f >= %f)\n", i,
3633 }
3634 else
3635 {
3636 SCIPsetDebugMsg(set, "Subproblem %d is NOT Optimal (%f < %f)\n", i,
3638 }
3639 }
3640#endif
3641
3642 /* the nverified variable is only incremented when the original form of the subproblem has been solved.
3643 * What is meant by "original" is that the LP relaxation of CIPs are solved to generate valid cuts. So
3644 * if the subproblem is defined as a CIP, then it is only classified as checked if the CIP is solved.
3645 * There are three cases where the "original" form is solved are:
3646 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX or USERCONVEX and the subproblem is an LP
3647 * - the original form has been solved.
3648 * ii) solveloop == SCIP_BENDERSSOLVELOOP_CIP or USERCIP and the CIP for the subproblem has been
3649 * solved.
3650 * iii) or, only a convex check is performed.
3651 */
3652 if( ((solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX)
3653 && convexsub)
3654 || ((solveloop == SCIP_BENDERSSOLVELOOP_CIP || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP)
3655 && !convexsub)
3656 || onlyconvexcheck )
3657 (*nverified)++;
3658 }
3659 }
3660 }
3661 }
3662
3663 /* checking whether the limits have been exceeded in the master problem */
3664 (*stopped) = SCIPisStopped(set->scip);
3665 }
3666 }
3667
3668 return retcode;
3669}
3670
3671/** Calls the Benders' decompsition cuts for the given solve loop. There are four cases:
3672 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX - only the LP Benders' cuts are called
3673 * ii) solveloop == SCIP_BENDERSSOLVELOOP_CIP - only the CIP Benders' cuts are called
3674 * iii) solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX - only the LP Benders' cuts are called
3675 * iv) solveloop == SCIP_BENDERSSOLVELOOP_USERCIP - only the CIP Benders' cuts are called
3676 *
3677 * The priority of the results are: SCIP_CONSADDED (SCIP_SEPARATED), SCIP_DIDNOTFIND, SCIP_FEASIBLE, SCIP_DIDNOTRUN. In
3678 * this function, there are four levels of results that need to be assessed. These are:
3679 * i) The result from the individual cut for the subproblem
3680 * ii) The overall result for the subproblem from all cuts
3681 * iii) the overall result for the solve loop from all cuts
3682 * iv) the over all result from all solve loops.
3683 * In each level, the priority of results must be adhered to.
3685static
3687 SCIP_BENDERS* benders, /**< Benders' decomposition */
3688 SCIP_SET* set, /**< global SCIP settings */
3689 SCIP_SOL* sol, /**< primal CIP solution */
3690 SCIP_RESULT* result, /**< result of the pricing process */
3691 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3692 SCIP_BENDERSSOLVELOOP solveloop, /**< the current solve loop */
3693 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
3694 SCIP_Bool* subprobsolved, /**< an array indicating the subproblems that were solved in this loop. */
3695 SCIP_BENDERSSUBSTATUS* substatus, /**< array to store the status of the subsystem */
3696 int* solveidx, /**< the indices of subproblems to be solved in this loop */
3697 int nsolveidx, /**< the number of subproblems to be solved in this loop */
3698 int* mergecands, /**< the subproblems that are merge candidates */
3699 int* npriomergecands, /**< the number of priority merge candidates. */
3700 int* nmergecands, /**< the number of merge candidates. */
3701 int* nsolveloops /**< the number of solve loops, is updated w.r.t added cuts */
3702 )
3703{
3704 SCIP_BENDERSCUT** benderscuts;
3705 SCIP_RESULT solveloopresult;
3706 int nbenderscuts;
3707 SCIP_Longint addedcuts = 0;
3708 int i;
3709 int j;
3710 int k;
3711 SCIP_Bool onlyconvexcheck;
3712
3713 assert(benders != NULL);
3714 assert(set != NULL);
3715
3716 /* getting the Benders' decomposition cuts */
3717 benderscuts = SCIPbendersGetBenderscuts(benders);
3718 nbenderscuts = SCIPbendersGetNBenderscuts(benders);
3719
3720 solveloopresult = SCIP_DIDNOTRUN;
3721
3722 /* in the case of an LNS check, only the convex relaxations of the subproblems will be solved. This is a performance
3723 * feature, since solving the convex relaxation is typically much faster than solving the corresponding CIP. While
3724 * the CIP is not solved during the LNS check, the solutions are still of higher quality than when Benders' is not
3725 * employed.
3726 */
3727 onlyconvexcheck = SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set));
3728
3729 /* It is only possible to add cuts to the problem if it has not already been solved */
3732 && (benders->cutcheck || type != SCIP_BENDERSENFOTYPE_CHECK) )
3733 {
3734 /* This is done in two loops. The first is by subproblem and the second is by cut type. */
3735 for( k = 0; k < nsolveidx; k++ )
3736 {
3737 SCIP_RESULT subprobresult;
3738 SCIP_Bool convexsub;
3739
3740 i = solveidx[k];
3741
3743
3744 /* cuts can only be generated if the subproblem is not independent and if it has been solved. Additionally, the
3745 * status of the subproblem solving must not be INFEASIBLE while in a cut strengthening round.
3746 * The subproblem solved flag is important for the user-defined subproblem solving methods
3747 */
3748 if( subproblemIsActive(benders, i) && subprobsolved[i]
3749 && !(substatus[i] == SCIP_BENDERSSUBSTATUS_INFEAS && benders->strengthenround) )
3750 {
3751 subprobresult = SCIP_DIDNOTRUN;
3752 for( j = 0; j < nbenderscuts; j++ )
3753 {
3754 SCIP_RESULT cutresult;
3755 SCIP_Longint prevaddedcuts;
3756
3757 assert(benderscuts[j] != NULL);
3758
3759 prevaddedcuts = SCIPbenderscutGetNFound(benderscuts[j]);
3760 cutresult = SCIP_DIDNOTRUN;
3761
3762 /* the result is updated only if a Benders' cut is generated or one was not found. However, if a cut has
3763 * been found in a previous iteration, then the result is returned as SCIP_CONSADDED or SCIP_SEPARATED.
3764 * This result is permitted because if a constraint was added, the solution that caused the error in the cut
3765 * generation will be cutoff from the master problem.
3766 */
3767 if( (SCIPbenderscutIsLPCut(benderscuts[j]) && (solveloop == SCIP_BENDERSSOLVELOOP_CONVEX
3768 || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX))
3769 || (!SCIPbenderscutIsLPCut(benderscuts[j]) && ((solveloop == SCIP_BENDERSSOLVELOOP_CIP && !convexsub)
3770 || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP)) )
3771 SCIP_CALL( SCIPbenderscutExec(benderscuts[j], set, benders, sol, i, type, &cutresult) );
3772
3773 addedcuts += (SCIPbenderscutGetNFound(benderscuts[j]) - prevaddedcuts);
3774
3775 /* the result is updated only if a Benders' cut is generated */
3776 if( cutresult == SCIP_CONSADDED || cutresult == SCIP_SEPARATED )
3777 {
3778 subprobresult = cutresult;
3779
3780 benders->ncutsfound++;
3781
3782 /* at most a single cut is generated for each subproblem */
3783 break;
3784 }
3785 else
3786 {
3787 /* checking from lowest priority result */
3788 if( subprobresult == SCIP_DIDNOTRUN )
3789 subprobresult = cutresult;
3790 else if( subprobresult == SCIP_FEASIBLE && cutresult == SCIP_DIDNOTFIND )
3791 subprobresult = cutresult;
3792 /* if the subprobresult is SCIP_DIDNOTFIND, then it can't be updated. */
3793 }
3794 }
3795
3796 /* the highest priority for the results is CONSADDED and SEPARATED. The solveloopresult will always be
3797 * updated if the subprobresult is either of these.
3798 */
3799 if( subprobresult == SCIP_CONSADDED || subprobresult == SCIP_SEPARATED )
3800 {
3801 solveloopresult = subprobresult;
3802 }
3803 else if( subprobresult == SCIP_FEASIBLE )
3804 {
3805 /* updating the solve loop result based upon the priority */
3806 if( solveloopresult == SCIP_DIDNOTRUN )
3807 solveloopresult = subprobresult;
3808 }
3809 else if( subprobresult == SCIP_DIDNOTFIND )
3810 {
3811 /* updating the solve loop result based upon the priority */
3812 if( solveloopresult == SCIP_DIDNOTRUN || solveloopresult == SCIP_FEASIBLE )
3813 solveloopresult = subprobresult;
3814
3815 /* since a cut was not found, then merging could be useful to avoid this in subsequent iterations. The
3816 * candidate is labelled as a non-priority merge candidate
3817 */
3818 if( substatus[i] != SCIP_BENDERSSUBSTATUS_OPTIMAL )
3819 {
3820 mergecands[(*nmergecands)] = i;
3821 (*nmergecands)++;
3822 }
3823 }
3824 else if( subprobresult == SCIP_DIDNOTRUN )
3825 {
3826 /* if the subproblem is infeasible and no cut generation methods were run, then the infeasibility will
3827 * never be resolved. As such, the subproblem will be merged into the master problem. If the subproblem
3828 * was not infeasible, then it is added as a possible merge candidate
3829 */
3830 if( substatus[i] == SCIP_BENDERSSUBSTATUS_INFEAS )
3831 {
3832 mergecands[(*nmergecands)] = mergecands[(*npriomergecands)];
3833 mergecands[(*npriomergecands)] = i;
3834 (*npriomergecands)++;
3835 (*nmergecands)++;
3836 }
3837 else if( substatus[i] != SCIP_BENDERSSUBSTATUS_OPTIMAL )
3838 {
3839 mergecands[(*nmergecands)] = i;
3840 (*nmergecands)++;
3841 }
3842 }
3843 }
3844 }
3845 }
3846
3847 /* updating the overall result based upon the priorities */
3848 if( solveloopresult == SCIP_CONSADDED || solveloopresult == SCIP_SEPARATED )
3849 {
3850 (*result) = solveloopresult;
3851 }
3852 else if( solveloopresult == SCIP_FEASIBLE )
3853 {
3854 /* updating the solve loop result based upon the priority */
3855 if( (*result) == SCIP_DIDNOTRUN )
3856 (*result) = solveloopresult;
3857 }
3858 else if( solveloopresult == SCIP_DIDNOTFIND )
3859 {
3860 /* updating the solve loop result based upon the priority */
3861 if( (*result) == SCIP_DIDNOTRUN || (*result) == SCIP_FEASIBLE )
3862 (*result) = solveloopresult;
3863 }
3864
3865 /* if no cuts were added, then the number of solve loops is increased */
3866 if( addedcuts == 0 && SCIPbendersGetNConvexSubproblems(benders) < SCIPbendersGetNSubproblems(benders)
3867 && checkint && !onlyconvexcheck )
3868 (*nsolveloops) = 2;
3869
3870 return SCIP_OKAY;
3871}
3872
3873/** Solves the subproblem using the current master problem solution.
3874 *
3875 * The checkint flag indicates whether integer feasibility can be assumed. If it is not assumed, i.e. checkint ==
3876 * FALSE, then only the convex relaxations of the subproblems are solved. If integer feasibility is assumed, i.e.
3877 * checkint == TRUE, then the convex relaxations and the full CIP are solved to generate Benders' cuts and check
3878 * solution feasibility.
3879 *
3880 * TODO: consider allowing the possibility to pass solution information back from the subproblems instead of the scip
3881 * instance. This would allow the use of different solvers for the subproblems, more importantly allowing the use of an
3882 * LP solver for LP subproblems.
3883 */
3885 SCIP_BENDERS* benders, /**< Benders' decomposition */
3886 SCIP_SET* set, /**< global SCIP settings */
3887 SCIP_SOL* sol, /**< primal CIP solution */
3888 SCIP_RESULT* result, /**< result of the pricing process */
3889 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
3890 SCIP_Bool* auxviol, /**< set to TRUE only if the solution is feasible but the aux vars are violated */
3891 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3892 SCIP_Bool checkint /**< should the integer solution be checked by the subproblems */
3893 )
3894{
3895 int nsubproblems;
3896 int subproblemcount;
3897 int nsolveloops;
3898 int nverified;
3899 int nsolved;
3900 int* mergecands;
3901 int npriomergecands;
3902 int nmergecands;
3903 int* solveidx;
3904 int* executedidx;
3905 int nsolveidx;
3906 int nexecutedidx;
3907 int nfree;
3908 SCIP_Bool* subprobsolved;
3909 SCIP_BENDERSSUBSTATUS* substatus;
3910 SCIP_Bool optimal;
3911 SCIP_Bool allverified;
3912 SCIP_Bool success;
3913 SCIP_Bool stopped;
3914 int i;
3915 int l;
3916
3917 assert(benders != NULL);
3918 assert(result != NULL);
3919 assert(infeasible != NULL);
3920 assert(auxviol != NULL);
3921
3922 success = TRUE;
3923 stopped = FALSE;
3924
3925 *auxviol = FALSE;
3926 *infeasible = FALSE;
3927
3928 SCIPsetDebugMsg(set, "Starting Benders' decomposition subproblem solving; type: %d, checkint: %u\n", type, checkint);
3929
3930#ifdef SCIP_MOREDEBUG
3931 SCIP_CALL( SCIPprintSol(set->scip, sol, NULL, FALSE) );
3932#endif
3933
3934 /* start timing */
3935 SCIPclockStart(benders->bendersclock, set);
3936
3937 nsubproblems = SCIPbendersGetNSubproblems(benders);
3938
3939 /* It is assumed that the problem is optimal, until a subproblem is found not to be optimal. However, not all
3940 * subproblems could be checked in each iteration. As such, it is not possible to state that the problem is optimal
3941 * if not all subproblems are checked. Situations where this may occur is when a subproblem is a MIP and only the LP
3942 * is solved. Also, in a distributed computation, then it may be advantageous to only solve some subproblems before
3943 * resolving the master problem. As such, for a problem to be optimal, then (optimal && allverified) == TRUE
3944 */
3945 optimal = TRUE;
3946 nverified = 0;
3947 nsolved = 0;
3948
3949 /* if the Benders' decomposition is called from a sub-SCIP and the sub-SCIPs have been deactivated, then it is
3950 * assumed that this is an LNS heuristic. As such, the check is not performed and the solution is assumed to be
3951 * feasible
3952 */
3953 if( benders->iscopy && set->subscipsoff
3954 && (!benders->lnscheck
3955 || (benders->lnsmaxdepth > -1 && SCIPgetDepth(benders->sourcescip) >= benders->lnsmaxdepth)
3956 || (benders->lnsmaxcalls > -1 && SCIPbendersGetNCalls(benders) >= benders->lnsmaxcalls)
3957 || (type != SCIP_BENDERSENFOTYPE_CHECK && SCIPgetDepth(set->scip) == 0 && benders->lnsmaxcallsroot > -1
3958 && SCIPbendersGetNCalls(benders) >= benders->lnsmaxcallsroot)) )
3959 {
3960 (*result) = SCIP_DIDNOTRUN;
3961 return SCIP_OKAY;
3962 }
3963
3964 /* it is not necessary to check all primal solutions by solving the Benders' decomposition subproblems.
3965 * Only the improving solutions are checked to improve efficiency of the algorithm.
3966 * If the solution is non-improving, the result FEASIBLE is returned. While this may be incorrect w.r.t to the
3967 * Benders' subproblems, this solution will never be the optimal solution. A non-improving solution may be used
3968 * within LNS primal heuristics. If this occurs, the improving solution, if found, will be checked by the solving
3969 * the Benders' decomposition subproblems.
3970 * TODO: Add a parameter to control this behaviour.
3971 */
3972 if( checkint && SCIPsetIsLE(set, SCIPgetPrimalbound(set->scip)*(int)SCIPgetObjsense(set->scip),
3973 SCIPgetSolOrigObj(set->scip, sol)*(int)SCIPgetObjsense(set->scip)) )
3974 {
3975 (*result) = SCIP_DIDNOTRUN;
3976 return SCIP_OKAY;
3977 }
3978
3979 /* if the enforcement type is SCIP_BENDERSENFOTYPE_LP and the LP is currently unbounded. This could mean that there
3980 * is no lower bound on the auxiliary variables. In this case, we try to update the lower bound for the auxiliary
3981 * variables.
3982 */
3984 && benders->updateauxvarbound )
3985 {
3987
3988 /* the auxiliary variable bound will only be updated once. */
3989 benders->updateauxvarbound = FALSE;
3990 }
3991
3992 /* sets the stored objective function values of the subproblems to infinity */
3994
3996
3997 if( benders->benderspresubsolve != NULL && !benders->strengthenround )
3998 {
3999 SCIP_Bool skipsolve;
4000
4001 skipsolve = FALSE;
4002 SCIP_CALL( benders->benderspresubsolve(set->scip, benders, sol, type, checkint, infeasible, auxviol, &skipsolve,
4003 result) );
4004
4005 /* evaluate result */
4006 if( (*result) != SCIP_DIDNOTRUN
4007 && (*result) != SCIP_FEASIBLE
4008 && (*result) != SCIP_INFEASIBLE
4009 && (*result) != SCIP_CONSADDED
4010 && (*result) != SCIP_SEPARATED )
4011 {
4012 SCIPerrorMessage("the user-defined pre subproblem solving method for the Benders' decomposition <%s> returned "
4013 "invalid result <%d>\n", benders->name, *result);
4014 return SCIP_INVALIDRESULT;
4015 }
4016
4017 /* if the solve must be skipped, then the solving loop is exited and the user defined result is returned */
4018 if( skipsolve )
4019 {
4020 SCIPsetDebugMsg(set, "skipping the subproblem solving for Benders' decomposition <%s>. "
4021 "returning result <%d>\n", benders->name, *result);
4022 return SCIP_OKAY;
4023 }
4024 }
4025
4026 /* the cut strengthening is performed before the regular subproblem solve is called. To avoid recursion, the flag
4027 * strengthenround is set to TRUE when the cut strengthening is performed. The cut strengthening is not performed as
4028 * part of the large neighbourhood Benders' search.
4029 *
4030 * NOTE: cut strengthening is only applied for fractional solutions and integer solutions if there are no CIP
4031 * subproblems.
4032 */
4033 if( benders->strengthenenabled && !benders->strengthenround && !benders->iscopy
4034 && (!checkint || SCIPbendersGetNConvexSubproblems(benders) == SCIPbendersGetNSubproblems(benders)) )
4035 {
4036 SCIP_Bool skipsolve;
4037
4038 benders->strengthenround = TRUE;
4039 /* if the user has not requested the solve to be skipped, then the cut strengthening is performed */
4040 SCIP_CALL( performInteriorSolCutStrengthening(benders, set, sol, type, checkint, FALSE, infeasible, auxviol,
4041 &skipsolve, result) );
4042 benders->strengthenround = FALSE;
4043
4044 /* if the solve must be skipped, then the solving loop is exited and the user defined result is returned */
4045 if( skipsolve )
4046 {
4047 SCIPsetDebugMsg(set, "skipping the subproblem solving because cut strengthening found a cut "
4048 "for Benders' decomposition <%s>. Returning result <%d>\n", benders->name, *result);
4049 return SCIP_OKAY;
4050 }
4051
4052 /* the result flag need to be reset to DIDNOTRUN for the main subproblem solve */
4053 (*result) = SCIP_DIDNOTRUN;
4054 }
4055
4056 /* allocating memory for the infeasible subproblem array */
4057 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &subprobsolved, nsubproblems) );
4058 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &substatus, nsubproblems) );
4059 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &mergecands, nsubproblems) );
4060 npriomergecands = 0;
4061 nmergecands = 0;
4062
4063 /* allocating the memory for the subproblem solving and cut generation indices */
4064 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &solveidx, nsubproblems) );
4065 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &executedidx, nsubproblems) );
4066 nsolveidx = 0;
4067 nexecutedidx = 0;
4068
4069 /* only a subset of the subproblems are initially solved. Both solving loops are executed for the subproblems to
4070 * check whether any cuts are generated. If a cut is generated, then no further subproblems are solved. If a cut is
4071 * not generated, then an additional set of subproblems are solved.
4072 */
4073 while( nsolved < nsubproblems )
4074 {
4075 /* getting the indices for the subproblems that will be solved */
4076 createSolveSubproblemIndexList(benders, set, type, &solveidx, &nsolveidx);
4077
4078 /* by default the number of solve loops is 1. This is the case if all subproblems are LP or the user has defined a
4079 * benderssolvesub callback. If there is a subproblem that is not an LP, then 2 solve loops are performed. The first
4080 * loop is the LP solving loop, the second solves the subproblem to integer optimality.
4081 */
4082 nsolveloops = 1;
4083
4084 for( l = 0; l < nsolveloops; l++ )
4085 {
4086 SCIP_BENDERSSOLVELOOP solveloop; /* identifies what problem type is solve in this solve loop */
4087
4088 /* if either benderssolvesubconvex or benderssolvesub are implemented, then the user callbacks are invoked */
4089 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL )
4090 {
4091 if( l == 0 )
4093 else
4095 }
4096 else
4097 solveloop = (SCIP_BENDERSSOLVELOOP) l;
4098
4099 /* solving the subproblems for this round of enforcement/checking. */
4100 SCIP_CALL( solveBendersSubproblems(benders, set, sol, type, solveloop, checkint, &nverified,
4101 solveidx, nsolveidx, &subprobsolved, &substatus, infeasible, &optimal, &stopped) );
4102
4103 /* if the solving has been stopped, then the subproblem solving and cut generation must terminate */
4104 if( stopped )
4105 break;
4106
4107 /* Generating cuts for the subproblems. Cuts are only generated when the solution is from primal heuristics,
4108 * relaxations or the LP
4109 */
4110 if( type != SCIP_BENDERSENFOTYPE_PSEUDO )
4111 {
4112 SCIP_CALL( generateBendersCuts(benders, set, sol, result, type, solveloop, checkint, subprobsolved,
4113 substatus, solveidx, nsolveidx, mergecands, &npriomergecands, &nmergecands, &nsolveloops) );
4114 }
4115 else
4116 {
4117 /* The first solving loop solves the convex subproblems and the convex relaxations of the CIP subproblems. The
4118 * second solving loop solves the CIP subproblems. The second solving loop is only called if the integer
4119 * feasibility is being checked and if the convex subproblems and convex relaxations are not infeasible.
4120 */
4121 if( !(*infeasible) && checkint && !SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set))
4123 nsolveloops = 2;
4124 }
4125 }
4126
4127 nsolved += nsolveidx;
4128
4129 /* storing the indices of the subproblems for which the solving loop was executed */
4130 for( i = 0; i < nsolveidx; i++ )
4131 executedidx[nexecutedidx++] = solveidx[i];
4132
4133 /* if the result is CONSADDED or SEPARATED, then a cut is generated and no further subproblem processing is
4134 * required
4135 */
4136 if( (*result) == SCIP_CONSADDED || (*result) == SCIP_SEPARATED )
4137 break;
4138 }
4139
4140 /* inserting the subproblems into the priority queue for the next solve call */
4141 SCIP_CALL( updateSubproblemStatQueue(benders, executedidx, nexecutedidx, TRUE) );
4142
4143 if( stopped ) /*lint !e774*/
4144 goto TERMINATE;
4145
4146 allverified = (nverified == nsubproblems);
4147
4148 SCIPsetDebugMsg(set, "End Benders' decomposition subproblem solve. result %d infeasible %u auxviol %u nverified %d\n",
4149 *result, *infeasible, *auxviol, nverified);
4150
4151#ifdef SCIP_DEBUG
4152 if( (*result) == SCIP_CONSADDED )
4153 {
4154 SCIPsetDebugMsg(set, "Benders' decomposition: Cut added\n");
4155 }
4156#endif
4157
4158 /* if the number of checked pseudo solutions exceeds a set limit, then all subproblems are passed as merge
4159 * candidates. Currently, merging subproblems into the master problem is the only method for resolving numerical
4160 * troubles.
4161 *
4162 * We are only interested in the pseudo solutions that have been checked completely for integrality. This is
4163 * identified by checkint == TRUE. This means that the Benders' decomposition constraint is one of the last
4164 * constraint handlers that must resolve the infeasibility. If the Benders' decomposition framework can't resolve the
4165 * infeasibility, then this will result in an error.
4166 */
4167 if( type == SCIP_BENDERSENFOTYPE_PSEUDO && checkint )
4168 {
4169 benders->npseudosols++;
4170
4171 if( benders->npseudosols > BENDERS_MAXPSEUDOSOLS )
4172 {
4173 /* if a priority merge candidate already exists, then no other merge candidates need to be added.*/
4174 if( npriomergecands == 0 )
4175 {
4176 /* all subproblems are added to the merge candidate list. The first active subproblem is added as a
4177 * priority merge candidate
4178 */
4179 nmergecands = 0;
4180 npriomergecands = 1;
4181 for( i = 0; i < nsubproblems; i++ )
4182 {
4183 /* only active subproblems are added to the merge candidate list */
4184 if( subproblemIsActive(benders, i) )
4185 {
4186 mergecands[nmergecands] = i;
4187 nmergecands++;
4188 }
4189 }
4190
4191 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_HIGH, NULL, " The number of checked pseudo solutions exceeds the "
4192 "limit of %d. All active subproblems are merge candidates, with subproblem %d a priority candidate.\n",
4193 BENDERS_MAXPSEUDOSOLS, mergecands[0]);
4194 }
4195 }
4196 }
4197 else
4198 benders->npseudosols = 0;
4199
4200 /* if the result is SCIP_DIDNOTFIND, then there was a error in generating cuts in all subproblems that are not
4201 * optimal. This result does not cutoff any solution, so the Benders' decomposition algorithm will fail.
4202 *
4203 * It could happen that the cut strengthening approach causes an error the cut generation. In this case, an error
4204 * should not be thrown. So, this check will be skipped when in a strengthening round.
4205 * TODO: Work out a way to ensure Benders' decomposition does not terminate due to a SCIP_DIDNOTFIND result.
4206 */
4207 if( (*result) == SCIP_DIDNOTFIND && !benders->strengthenround )
4208 {
4209 if( type == SCIP_BENDERSENFOTYPE_PSEUDO )
4210 (*result) = SCIP_SOLVELP;
4211 else
4213
4214 SCIPerrorMessage("An error was found when generating cuts for non-optimal subproblems of Benders' "
4215 "decomposition <%s>. Consider merging the infeasible subproblems into the master problem.\n", SCIPbendersGetName(benders));
4216
4217 /* since no other cuts are generated, then this error will result in a crash. It is possible to avoid the error,
4218 * by merging the affected subproblem into the master problem.
4219 *
4220 * NOTE: If the error occurs while checking solutions, i.e. SCIP_BENDERSENFOTYPE_CHECK, then it is valid to set
4221 * the result to SCIP_INFEASIBLE and the success flag to TRUE
4222 */
4223 if( type != SCIP_BENDERSENFOTYPE_CHECK )
4224 success = FALSE;
4225
4226 goto POSTSOLVE;
4227 }
4228
4229 if( type == SCIP_BENDERSENFOTYPE_PSEUDO )
4230 {
4231 if( (*infeasible) || !allverified )
4232 (*result) = SCIP_SOLVELP;
4233 else
4234 {
4235 (*result) = SCIP_FEASIBLE;
4236
4237 /* if the subproblems are not infeasible, but they are also not optimal. This means that there is a violation
4238 * in the auxiliary variable values. In this case, a feasible result is returned with the auxviol flag set to
4239 * TRUE.
4240 */
4241 (*auxviol) = !optimal;
4242 }
4243 }
4244 else if( checkint && (type == SCIP_BENDERSENFOTYPE_CHECK
4245 || ((*result) != SCIP_CONSADDED && (*result) != SCIP_SEPARATED)) )
4246 {
4247 /* if the subproblems are being solved as part of conscheck, then the results flag must be returned after the solving
4248 * has completed.
4249 */
4250 if( (*infeasible) || !allverified )
4251 (*result) = SCIP_INFEASIBLE;
4252 else
4253 {
4254 (*result) = SCIP_FEASIBLE;
4255
4256 /* if the subproblems are not infeasible, but they are also not optimal. This means that there is a violation
4257 * in the auxiliary variable values. In this case, a feasible result is returned with the auxviol flag set to
4258 * TRUE.
4259 */
4260 (*auxviol) = !optimal;
4261 }
4262 }
4263
4264POSTSOLVE:
4265 /* calling the post-solve call back for the Benders' decomposition algorithm. This allows the user to work directly
4266 * with the solved subproblems and the master problem */
4267 if( benders->benderspostsolve != NULL )
4268 {
4269 SCIP_Bool merged;
4270
4271 merged = FALSE;
4272
4273 SCIP_CALL( benders->benderspostsolve(set->scip, benders, sol, type, mergecands, npriomergecands, nmergecands,
4274 checkint, (*infeasible), &merged) );
4275
4276 if( merged )
4277 {
4278 (*result) = SCIP_CONSADDED;
4279
4280 /* since subproblems have been merged, then constraints have been added. This could resolve the unresolved
4281 * infeasibility, so the error has been corrected.
4282 */
4283 success = TRUE;
4284 }
4285 else if( !success )
4286 {
4287 SCIPerrorMessage("An error occurred during Benders' decomposition cut generations and no merging had been "
4288 "performed. It is not possible to continue solving the problem by Benders' decomposition\n");
4289 }
4290 }
4291
4292TERMINATE:
4293 /* if the solving process has stopped, then all subproblems need to be freed */
4294 if( stopped ) /*lint !e774*/
4295 nfree = nsubproblems;
4296 else
4297 nfree = nexecutedidx;
4298
4299 /* freeing the subproblems after the cuts are generated */
4300 subproblemcount = 0;
4301 while( subproblemcount < nfree )
4302 {
4303 int subidx;
4304
4305 if( stopped )
4306 subidx = subproblemcount;
4307 else
4308 subidx = executedidx[subproblemcount];
4309
4310 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, subidx) );
4311
4312 subproblemcount++;
4313 }
4314
4315#ifndef NDEBUG
4316 for( i = 0; i < nsubproblems; i++ )
4317 assert(SCIPbendersSubproblem(benders, i) == NULL
4320 || !subproblemIsActive(benders, i));
4321#endif
4322
4323 /* increment the number of calls to the Benders' decomposition subproblem solve */
4324 benders->ncalls++;
4325
4326 SCIPsetDebugMsg(set, "End Benders' decomposition execution method. result %d infeasible %u auxviol %u\n", *result,
4327 *infeasible, *auxviol);
4328
4329 /* end timing */
4330 SCIPclockStop(benders->bendersclock, set);
4331
4332 /* freeing memory */
4333 SCIPfreeBlockMemoryArray(set->scip, &executedidx, nsubproblems);
4334 SCIPfreeBlockMemoryArray(set->scip, &solveidx, nsubproblems);
4335 SCIPfreeBlockMemoryArray(set->scip, &mergecands, nsubproblems);
4336 SCIPfreeBlockMemoryArray(set->scip, &substatus, nsubproblems);
4337 SCIPfreeBlockMemoryArray(set->scip, &subprobsolved, nsubproblems);
4338
4339 /* if there was an error in generating cuts and merging was not performed, then the solution is perturbed in an
4340 * attempt to generate a cut and correct the infeasibility
4341 */
4342 if( !success && !stopped )
4343 {
4344 SCIP_Bool skipsolve;
4345 SCIP_RESULT perturbresult;
4346
4347 skipsolve = FALSE;
4348
4349 benders->strengthenround = TRUE;
4350 /* if the user has not requested the solve to be skipped, then the cut strengthening is performed */
4351 SCIP_CALL( performInteriorSolCutStrengthening(benders, set, sol, type, checkint, TRUE, infeasible, auxviol,
4352 &skipsolve, &perturbresult) );
4353 benders->strengthenround = FALSE;
4354
4355 if( perturbresult == SCIP_CONSADDED || perturbresult == SCIP_SEPARATED )
4356 (*result) = perturbresult;
4357
4358 success = skipsolve;
4359 }
4360
4361 /* if the Benders' decomposition subproblem check stopped, then we don't have a valid result. In this case, the
4362 * safest thing to do is report INFEASIBLE.
4363 */
4364 if( stopped )
4365 (*result) = SCIP_INFEASIBLE;
4366
4367 /* if the subproblem verification identifies the solution as feasible, then a check whether slack variables have been
4368 * used is necessary. If any slack variables are non-zero, then the solution is reverified after the objective
4369 * coefficient for the slack variables is increased.
4370 */
4371 if( (*result) == SCIP_FEASIBLE )
4372 {
4373 SCIP_Bool activeslack;
4374
4375 SCIP_CALL( SCIPbendersSolSlackVarsActive(benders, &activeslack) );
4376 SCIPsetDebugMsg(set, "Type: %d Active slack: %u Feasibility Phase: %u\n", type, activeslack,
4377 benders->feasibilityphase);
4378 if( activeslack )
4379 {
4380 if( type == SCIP_BENDERSENFOTYPE_CHECK )
4381 (*result) = SCIP_INFEASIBLE;
4382 else
4383 {
4384 /* increasing the value of the slack variable by a factor of 10 */
4385 benders->slackvarcoef *= 10.0;
4386
4387 if( benders->slackvarcoef <= benders->maxslackvarcoef )
4388 {
4389 SCIPmessagePrintVerbInfo(SCIPgetMessagehdlr(set->scip), set->disp_verblevel, SCIP_VERBLEVEL_HIGH, "Increasing the slack variable coefficient to %g.\n", benders->slackvarcoef);
4390 }
4391 else
4392 {
4393 SCIPmessagePrintVerbInfo(SCIPgetMessagehdlr(set->scip), set->disp_verblevel, SCIP_VERBLEVEL_HIGH, "Fixing the slack variables to zero.\n");
4394 }
4395
4396 /* resolving the subproblems with an increased slack variable */
4397 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sol, result, infeasible, auxviol, type, checkint) );
4398 }
4399 }
4400 else if( benders->feasibilityphase )
4401 {
4402 if( type != SCIP_BENDERSENFOTYPE_CHECK )
4403 {
4404 /* disabling the feasibility phase */
4405 benders->feasibilityphase = FALSE;
4406
4407 /* resolving the subproblems with the slack variables set to zero */
4408 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sol, result, infeasible, auxviol, type, checkint) );
4409 }
4410 }
4411 }
4412
4413 if( !success )
4414 return SCIP_ERROR;
4415 else
4416 return SCIP_OKAY;
4417}
4418
4419/** solves the user-defined subproblem solving function */
4420static
4422 SCIP_BENDERS* benders, /**< Benders' decomposition */
4423 SCIP_SET* set, /**< global SCIP settings */
4424 SCIP_SOL* sol, /**< primal CIP solution */
4425 int probnumber, /**< the subproblem number */
4426 SCIP_BENDERSSOLVELOOP solveloop, /**< the solve loop iteration. The first iter is for LP, the second for IP */
4427 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
4428 SCIP_Real* objective, /**< the objective function value of the subproblem */
4429 SCIP_RESULT* result /**< the result from solving the subproblem */
4430 )
4431{
4432 assert(benders != NULL);
4433 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
4434 assert(benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL);
4435
4437
4438 (*objective) = -SCIPsetInfinity(set);
4439
4440 /* calls the user defined subproblem solving method. Only the convex relaxations are solved during the Large
4441 * Neighbourhood Benders' Search. */
4442 if( solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX )
4443 {
4444 if( benders->benderssolvesubconvex != NULL )
4445 {
4446 SCIP_CALL( benders->benderssolvesubconvex(set->scip, benders, sol, probnumber,
4448 }
4449 else
4451 }
4452 else if( solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
4453 {
4454 if( benders->benderssolvesub != NULL )
4455 {
4456 SCIP_CALL( benders->benderssolvesub(set->scip, benders, sol, probnumber, objective, result) );
4457 }
4458 else
4460 }
4461
4462 /* evaluate result */
4463 if( (*result) != SCIP_DIDNOTRUN
4464 && (*result) != SCIP_FEASIBLE
4465 && (*result) != SCIP_INFEASIBLE
4466 && (*result) != SCIP_UNBOUNDED )
4467 {
4468 SCIPerrorMessage("the user-defined solving method for the Benders' decomposition <%s> returned invalid result <%d>\n",
4469 benders->name, *result);
4470 return SCIP_INVALIDRESULT;
4471 }
4472
4473 if( (*result) == SCIP_INFEASIBLE )
4474 (*infeasible) = TRUE;
4475
4476 if( (*result) == SCIP_FEASIBLE
4477 && (SCIPsetIsInfinity(set, -(*objective)) || SCIPsetIsInfinity(set, (*objective))) )
4478 {
4479 SCIPerrorMessage("the user-defined solving method for the Benders' decomposition <%s> returned objective value %g\n",
4480 benders->name, (*objective));
4481 return SCIP_ERROR;
4482 }
4483
4484 /* if the result is SCIP_DIDNOTFIND, then an error is returned and SCIP will terminate. */
4485 if( (*result) == SCIP_DIDNOTFIND )
4486 return SCIP_ERROR;
4487 else
4488 return SCIP_OKAY;
4489}
4491/** executes the subproblem solving process */
4493 SCIP_BENDERS* benders, /**< Benders' decomposition */
4494 SCIP_SET* set, /**< global SCIP settings */
4495 SCIP_SOL* sol, /**< primal CIP solution */
4496 int probnumber, /**< the subproblem number */
4497 SCIP_BENDERSSOLVELOOP solveloop, /**< the solve loop iteration. The first iter is for LP, the second for IP */
4498 SCIP_Bool enhancement, /**< is the solve performed as part of and enhancement? */
4499 SCIP_Bool* solved, /**< flag to indicate whether the subproblem was solved */
4500 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
4501 SCIP_BENDERSENFOTYPE type /**< the enforcement type calling this function */
4502 )
4503{ /*lint --e{715}*/
4504 SCIP* subproblem;
4506 SCIP_Real objective;
4507 SCIP_STATUS solvestatus = SCIP_STATUS_UNKNOWN;
4508
4509 assert(benders != NULL);
4510 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
4511
4512 SCIPsetDebugMsg(set, "Benders' decomposition: solving subproblem %d\n", probnumber);
4513
4515 objective = SCIPsetInfinity(set);
4516
4517 subproblem = SCIPbendersSubproblem(benders, probnumber);
4518
4519 if( subproblem == NULL && (benders->benderssolvesubconvex == NULL || benders->benderssolvesub == NULL) )
4520 {
4521 SCIPerrorMessage("The subproblem %d is set to NULL, but both bendersSolvesubconvex%s and bendersSolvesub%s "
4522 "are not defined.\n", probnumber, benders->name, benders->name);
4523 SCIPABORT();
4524 return SCIP_ERROR;
4525 }
4526
4527 /* initially setting the solved flag to FALSE */
4528 (*solved) = FALSE;
4529
4530 /* if the subproblem solve callback is implemented, then that is used instead of the default setup */
4531 if( solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
4532 {
4533 /* calls the user defined subproblem solving method. Only the convex relaxations are solved during the Large
4534 * Neighbourhood Benders' Search. */
4535 SCIP_CALL( executeUserDefinedSolvesub(benders, set, sol, probnumber, solveloop, infeasible, &objective, &result) );
4536
4537 /* if the result is DIDNOTRUN, then the subproblem was not solved */
4538 (*solved) = (result != SCIP_DIDNOTRUN);
4539 }
4540 else if( subproblem != NULL )
4541 {
4542 /* setting up the subproblem */
4543 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX )
4544 {
4545 SCIP_CALL( SCIPbendersSetupSubproblem(benders, set, sol, probnumber, type) );
4546
4547 /* if the limits of the master problem were hit during the setup process, then the subproblem will not have
4548 * been setup. In this case, the solving function must be exited.
4549 */
4550 if( !SCIPbendersSubproblemIsSetup(benders, probnumber) )
4551 {
4552 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
4553 (*solved) = FALSE;
4554 return SCIP_OKAY;
4555 }
4556 }
4557 else
4558 {
4559 SCIP_CALL( updateEventhdlrUpperbound(benders, probnumber, SCIPbendersGetAuxiliaryVarVal(benders, set, sol, probnumber)) );
4560 }
4561
4562 /* solving the subproblem
4563 * the LP of the subproblem is solved in the first solveloop.
4564 * In the second solve loop, the MIP problem is solved */
4565 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX
4567 {
4568 SCIP_CALL( SCIPbendersSolveSubproblemLP(set->scip, benders, probnumber, &solvestatus, &objective) );
4569
4570 /* if the (N)LP was solved without error, then the subproblem is labelled as solved */
4571 if( solvestatus == SCIP_STATUS_OPTIMAL || solvestatus == SCIP_STATUS_INFEASIBLE )
4572 (*solved) = TRUE;
4573
4574 if( solvestatus == SCIP_STATUS_INFEASIBLE )
4575 (*infeasible) = TRUE;
4576 }
4577 else
4578 {
4579 SCIP_SOL* bestsol;
4580
4581 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, FALSE) );
4582
4583 if( solvestatus == SCIP_STATUS_INFEASIBLE )
4584 (*infeasible) = TRUE;
4585
4586 /* if the generic subproblem solving methods are used, then the CIP subproblems are always solved. */
4587 (*solved) = TRUE;
4588
4589 bestsol = SCIPgetBestSol(subproblem);
4590 if( bestsol != NULL )
4591 objective = SCIPgetSolOrigObj(subproblem, bestsol)*(int)SCIPgetObjsense(set->scip);
4592 else
4593 objective = SCIPsetInfinity(set);
4594 }
4595 }
4596 else
4597 {
4598 SCIPABORT();
4599 }
4600
4601 if( !enhancement )
4602 {
4603 /* The following handles the cases when the subproblem is OPTIMAL, INFEASIBLE and UNBOUNDED.
4604 * If a subproblem is unbounded, then the auxiliary variables are set to -infinity and the unbounded flag is
4605 * returned as TRUE. No cut will be generated, but the result will be set to SCIP_FEASIBLE.
4606 */
4607 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_CIP )
4608 {
4609 /* TODO: Consider whether other solutions status should be handled */
4610 if( solvestatus == SCIP_STATUS_OPTIMAL )
4611 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
4612 else if( solvestatus == SCIP_STATUS_INFEASIBLE )
4613 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
4614 else if( solvestatus == SCIP_STATUS_USERINTERRUPT || solvestatus == SCIP_STATUS_BESTSOLLIMIT )
4615 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
4616 else if( solvestatus == SCIP_STATUS_MEMLIMIT || solvestatus == SCIP_STATUS_TIMELIMIT
4617 || solvestatus == SCIP_STATUS_UNKNOWN )
4618 {
4619 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_FULL, NULL, " Benders' decomposition: Error solving "
4620 "subproblem %d. No cut will be generated for this subproblem.\n", probnumber);
4621 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
4622 }
4623 else if( solvestatus == SCIP_STATUS_UNBOUNDED )
4624 {
4625 SCIPerrorMessage("The Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
4626 probnumber);
4627 SCIPABORT();
4628 }
4629 else
4630 {
4631 SCIPerrorMessage("Invalid status returned from solving Benders' decomposition subproblem %d. Solution status: %d\n",
4632 probnumber, solvestatus);
4633 SCIPABORT();
4634 }
4635 }
4636 else
4637 {
4639 if( result == SCIP_FEASIBLE )
4640 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
4641 else if( result == SCIP_INFEASIBLE )
4642 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
4643 else if( result == SCIP_UNBOUNDED )
4644 {
4645 SCIPerrorMessage("The Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
4646 probnumber);
4647 SCIPABORT();
4648 }
4649 else if( result != SCIP_DIDNOTRUN )
4650 {
4651 SCIPerrorMessage("Invalid result <%d> from user-defined subproblem solving method. This should not happen.\n",
4652 result);
4653 }
4654 }
4655 }
4656
4657 return SCIP_OKAY;
4658}
4660/** sets up the subproblem using the solution to the master problem */
4662 SCIP_BENDERS* benders, /**< Benders' decomposition */
4663 SCIP_SET* set, /**< global SCIP settings */
4664 SCIP_SOL* sol, /**< primal CIP solution */
4665 int probnumber, /**< the subproblem number */
4666 SCIP_BENDERSENFOTYPE type /**< the enforcement type calling this function */
4667 )
4668{
4669 SCIP* subproblem;
4670 SCIP_VAR** vars;
4671 SCIP_VAR* mastervar;
4672 SCIP_Real solval;
4673 int nvars;
4674 int i;
4675
4676 assert(benders != NULL);
4677 assert(set != NULL);
4678 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
4679
4680 subproblem = SCIPbendersSubproblem(benders, probnumber);
4681
4682 /* the subproblem setup can only be performed if the subproblem is not NULL */
4683 if( subproblem == NULL )
4684 {
4685 SCIPerrorMessage("The subproblem %d is NULL. Thus, the subproblem setup must be performed manually in either "
4686 "bendersSolvesubconvex%s or bendersSolvesub%s.\n", probnumber, benders->name, benders->name);
4687 return SCIP_ERROR;
4688 }
4689 assert(subproblem != NULL);
4690
4691 /* changing all of the master problem variable to continuous. */
4692 SCIP_CALL( SCIPbendersChgMastervarsToCont(benders, set, probnumber) );
4693
4694 /* if the Benders' decomposition subproblem is convex and has continuous variables, then probing mode
4695 * must be started.
4696 * If the subproblem contains non-convex constraints or discrete variables, then the problem must be initialised,
4697 * and then put into SCIP_STAGE_SOLVING to be able to change the variable bounds. The probing mode is entered once
4698 * the variable bounds are set.
4699 * In the latter case, the transformed problem is freed after each subproblem solve round. */
4701 {
4702 SCIP_CALL( SCIPstartProbing(subproblem) );
4703 }
4704 else
4705 {
4706 SCIP_Bool infeasible;
4707 SCIP_Bool success;
4708
4709 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, &infeasible, &success) );
4710 assert(success == !infeasible);
4711
4712 /* if the problem is identified as infeasible, this means that the underlying LP is infeasible. Since no variable
4713 * fixings have been applied at this stage, this means that the complete problem is infeasible. It is only
4714 * possible to set this parameter if we are at the root node or in an initialisation stage.
4715 */
4716 if( infeasible )
4718
4719 if( !success )
4720 {
4721 /* set the flag to indicate that the subproblems have been set up */
4722 SCIPbendersSetSubproblemIsSetup(benders, probnumber, FALSE);
4723
4724 return SCIP_OKAY;
4725 }
4726 }
4727
4728 vars = SCIPgetVars(subproblem);
4729 nvars = SCIPgetNVars(subproblem);
4730
4731 /* looping over all variables in the subproblem to find those corresponding to the master problem variables. */
4732 /* TODO: It should be possible to store the pointers to the master variables to speed up the subproblem setup */
4733 for( i = 0; i < nvars; i++ )
4734 {
4735 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
4736
4737 if( mastervar != NULL )
4738 {
4739 /* It is possible due to numerics that the solution value exceeds the upper or lower bounds. When this
4740 * happens, it causes an error in the LP solver as a result of inconsistent bounds. So the following statements
4741 * are used to ensure that the bounds are not exceeded when applying the fixings for the Benders'
4742 * decomposition subproblems
4743 */
4744 solval = SCIPgetSolVal(set->scip, sol, mastervar);
4745 if( !SCIPisLT(set->scip, solval, SCIPvarGetUbLocal(vars[i])) )
4746 solval = SCIPvarGetUbLocal(vars[i]);
4747 else if( !SCIPisGT(set->scip, solval, SCIPvarGetLbLocal(vars[i])) )
4748 solval = SCIPvarGetLbLocal(vars[i]);
4749
4750 /* fixing the variable in the subproblem */
4751 if( !SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])) )
4752 {
4753 if( SCIPisGT(subproblem, solval, SCIPvarGetLbLocal(vars[i])) )
4754 {
4755 SCIP_CALL( SCIPchgVarLb(subproblem, vars[i], solval) );
4756 }
4757 if( SCIPisLT(subproblem, solval, SCIPvarGetUbLocal(vars[i])) )
4758 {
4759 SCIP_CALL( SCIPchgVarUb(subproblem, vars[i], solval) );
4760 }
4761 }
4762
4764 }
4765 else if( strstr(SCIPvarGetName(vars[i]), SLACKVAR_NAME) != NULL )
4766 {
4767 /* if the slack variables have been added to help improve feasibility, then they remain unfixed with a large
4768 * objective coefficient. Once the root node has been solved to optimality, then the slack variables are
4769 * fixed to zero.
4770 */
4771 if( benders->feasibilityphase && SCIPgetDepth(set->scip) == 0 && type != SCIP_BENDERSENFOTYPE_CHECK )
4772 {
4773 /* The coefficient update or variable fixing can only be performed if the subproblem is in probing mode.
4774 * If the slack var coef gets very large, then we fix the slack variable to 0 instead.
4775 */
4776 if( SCIPinProbing(subproblem) )
4777 {
4778 if( benders->slackvarcoef <= benders->maxslackvarcoef )
4779 {
4780 SCIP_CALL( SCIPchgVarObjProbing(subproblem, vars[i], benders->slackvarcoef) );
4781 }
4782 else
4783 {
4784 SCIP_CALL( SCIPchgVarUbProbing(subproblem, vars[i], 0.0) );
4785 }
4786 }
4787 }
4788 else
4789 {
4790 /* if the subproblem is non-linear and convex, then slack variables have been added to the subproblem. These
4791 * need to be fixed to zero when first solving the subproblem. However, if the slack variables have been added
4792 * by setting the execfeasphase runtime parameter, then they must not get fixed to zero
4793 */
4795 assert( SCIPisZero(subproblem, SCIPvarGetLbLocal(vars[i])) );
4796
4797 if( SCIPisLT(subproblem, 0.0, SCIPvarGetUbLocal(vars[i])) )
4798 {
4799 SCIP_CALL( SCIPchgVarUb(subproblem, vars[i], 0.0) );
4800 }
4801 }
4802 }
4803 }
4804
4805 /* if the subproblem contain non-convex constraints or discrete variables, then the probing mode is entered after
4806 * setting up the subproblem
4807 */
4809 {
4810 SCIP_CALL( SCIPstartProbing(subproblem) );
4811 }
4812
4813 /* set the flag to indicate that the subproblems have been set up */
4814 SCIPbendersSetSubproblemIsSetup(benders, probnumber, TRUE);
4815
4816 return SCIP_OKAY;
4817}
4818
4819/** Solve a Benders' decomposition subproblems. This will either call the user defined method or the generic solving
4820 * methods. If the generic method is called, then the subproblem must be set up before calling this method. */
4822 SCIP_BENDERS* benders, /**< Benders' decomposition */
4823 SCIP_SET* set, /**< global SCIP settings */
4824 SCIP_SOL* sol, /**< primal CIP solution, can be NULL */
4825 int probnumber, /**< the subproblem number */
4826 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
4827 SCIP_Bool solvecip, /**< directly solve the CIP subproblem */
4828 SCIP_Real* objective /**< the objective function value of the subproblem, can be NULL */
4829 )
4830{
4831 assert(benders != NULL);
4832 assert(set != NULL);
4833 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
4834
4835 assert(infeasible != NULL);
4836 (*infeasible) = FALSE;
4837
4838 /* the subproblem must be set up before this function is called. */
4839 if( SCIPbendersSubproblem(benders, probnumber) != NULL && !SCIPbendersSubproblemIsSetup(benders, probnumber)
4840 && !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
4841 {
4842 SCIPerrorMessage("Benders' decomposition subproblem %d must be set up before calling SCIPbendersSolveSubproblem(). Call SCIPsetupSubproblem() first.\n", probnumber);
4843 return SCIP_ERROR;
4844 }
4845
4846 /* if the subproblem solve callback is implemented, then that is used instead of the default setup */
4847 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL)
4848 {
4849 SCIP_BENDERSSOLVELOOP solveloop;
4851 SCIP_Real subobj;
4852
4853 if( solvecip )
4855 else
4857
4858 SCIP_CALL( executeUserDefinedSolvesub(benders, set, sol, probnumber, solveloop, infeasible, &subobj, &result) );
4859
4860 if( objective != NULL )
4861 (*objective) = subobj;
4862 }
4863 else
4864 {
4865 SCIP* subproblem;
4866
4867 subproblem = SCIPbendersSubproblem(benders, probnumber);
4868 assert(subproblem != NULL);
4869
4870 /* solving the subproblem */
4871 if( solvecip && SCIPbendersGetSubproblemType(benders, probnumber) != SCIP_BENDERSSUBTYPE_CONVEXCONT )
4872 {
4873 SCIP_STATUS solvestatus;
4874
4875 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, solvecip) );
4876
4877 if( solvestatus == SCIP_STATUS_INFEASIBLE )
4878 (*infeasible) = TRUE;
4879 if( objective != NULL )
4880 (*objective) = SCIPgetSolOrigObj(subproblem, SCIPgetBestSol(subproblem))*(int)SCIPgetObjsense(subproblem);
4881 }
4882 else
4883 {
4884 SCIP_Bool success;
4885
4886 /* if the subproblem has convex constraints and continuous variables, then it should have been initialised and
4887 * in SCIP_STAGE_SOLVING. In this case, the subproblem only needs to be put into probing mode.
4888 */
4890 {
4891 /* if the subproblem is not in probing mode, then it must be put into that mode for the LP solve. */
4892 if( !SCIPinProbing(subproblem) )
4893 {
4894 SCIP_CALL( SCIPstartProbing(subproblem) );
4895 }
4896
4897 success = TRUE;
4898 }
4899 else
4900 {
4901 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, infeasible, &success) );
4902 }
4903
4904 /* if setting up the subproblem was successful */
4905 if( success )
4906 {
4907 SCIP_STATUS solvestatus;
4908 SCIP_Real lpobjective;
4909
4910 SCIP_CALL( SCIPbendersSolveSubproblemLP(set->scip, benders, probnumber, &solvestatus, &lpobjective) );
4911
4912 if( solvestatus == SCIP_STATUS_INFEASIBLE )
4913 (*infeasible) = TRUE;
4914 else if( objective != NULL )
4915 (*objective) = lpobjective;
4916 }
4917 else
4918 {
4919 if( objective != NULL )
4920 (*objective) = SCIPinfinity(subproblem);
4921 }
4922 }
4923 }
4924
4925 return SCIP_OKAY;
4926}
4927
4928/** copies the time and memory limit from the master problem to the subproblem */
4929static
4931 SCIP* scip, /**< the SCIP data structure */
4932 SCIP* subproblem /**< the Benders' decomposition subproblem */
4933 )
4934{
4935 SCIP_Real mastertimelimit;
4936 SCIP_Real subtimelimit;
4937 SCIP_Real maxsubtimelimit;
4938 SCIP_Real mastermemorylimit;
4939 SCIP_Real submemorylimit;
4940 SCIP_Real maxsubmemorylimit;
4941
4942 assert(scip != NULL);
4943
4944 /* setting the time limit for the Benders' decomposition subproblems. It is set to 102% of the remaining time. */
4945 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &mastertimelimit) );
4946 maxsubtimelimit = SCIPparamGetRealMax(SCIPgetParam(subproblem, "limits/time"));
4947 subtimelimit = (mastertimelimit - SCIPgetSolvingTime(scip)) * 1.02;
4948 subtimelimit = MIN(subtimelimit, maxsubtimelimit);
4949 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", MAX(0.0, subtimelimit)) );
4950
4951 /* setting the memory limit for the Benders' decomposition subproblems. */
4952 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &mastermemorylimit) );
4953 maxsubmemorylimit = SCIPparamGetRealMax(SCIPgetParam(subproblem, "limits/memory"));
4954 submemorylimit = mastermemorylimit - (SCIPgetMemUsed(scip) + SCIPgetMemExternEstim(scip))/1048576.0;
4955 submemorylimit = MIN(submemorylimit, maxsubmemorylimit);
4956 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", MAX(0.0, submemorylimit)) );
4957
4958 return SCIP_OKAY;
4959}
4960
4961/** stores the original parameters from the subproblem */
4962static
4964 SCIP* subproblem, /**< the SCIP data structure */
4965 SCIP_SUBPROBPARAMS* origparams /**< the original subproblem parameters */
4966 )
4967{
4968 assert(subproblem != NULL);
4969 assert(origparams != NULL);
4970
4971 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/memory", &origparams->limits_memory) );
4972 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/time", &origparams->limits_time) );
4973 SCIP_CALL( SCIPgetBoolParam(subproblem, "conflict/enable", &origparams->conflict_enable) );
4974 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/disablecutoff", &origparams->lp_disablecutoff) );
4975 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/scaling", &origparams->lp_scaling) );
4976 SCIP_CALL( SCIPgetCharParam(subproblem, "lp/initalgorithm", &origparams->lp_initalg) );
4977 SCIP_CALL( SCIPgetCharParam(subproblem, "lp/resolvealgorithm", &origparams->lp_resolvealg) );
4978 SCIP_CALL( SCIPgetBoolParam(subproblem, "lp/alwaysgetduals", &origparams->lp_alwaysgetduals) );
4979 SCIP_CALL( SCIPgetBoolParam(subproblem, "misc/scaleobj", &origparams->misc_scaleobj) );
4980 SCIP_CALL( SCIPgetBoolParam(subproblem, "misc/catchctrlc", &origparams->misc_catchctrlc) );
4981 SCIP_CALL( SCIPgetIntParam(subproblem, "propagating/maxrounds", &origparams->prop_maxrounds) );
4982 SCIP_CALL( SCIPgetIntParam(subproblem, "propagating/maxroundsroot", &origparams->prop_maxroundsroot) );
4983 SCIP_CALL( SCIPgetIntParam(subproblem, "constraints/linear/propfreq", &origparams->cons_linear_propfreq) );
4984
4985 return SCIP_OKAY;
4986}
4987
4988/** sets the parameters for the subproblem */
4989static
4991 SCIP* scip, /**< the SCIP data structure */
4992 SCIP* subproblem /**< the subproblem SCIP instance */
4993 )
4994{
4995 assert(scip != NULL);
4996 assert(subproblem != NULL);
4997
4998 /* copying memory and time limits */
4999 SCIP_CALL( copyMemoryAndTimeLimits(scip, subproblem) );
5000
5001 /* Do we have to disable presolving? If yes, we have to store all presolving parameters. */
5003
5004 /* Disabling heuristics so that the problem is not trivially solved */
5006
5007 /* store parameters that are changed for the generation of the subproblem cuts */
5008 SCIP_CALL( SCIPsetBoolParam(subproblem, "conflict/enable", FALSE) );
5009
5010 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", 1) );
5011 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/scaling", 0) );
5012
5013 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/initalgorithm", 'd') );
5014 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/resolvealgorithm", 'd') );
5015
5016 SCIP_CALL( SCIPsetBoolParam(subproblem, "lp/alwaysgetduals", TRUE) );
5017 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/scaleobj", FALSE) );
5018
5019 /* do not abort subproblem on CTRL-C */
5020 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/catchctrlc", FALSE) );
5021
5022#ifndef SCIP_MOREDEBUG
5023 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_NONE) );
5024#endif
5025
5026 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxrounds", 0) );
5027 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxroundsroot", 0) );
5028
5029 SCIP_CALL( SCIPsetIntParam(subproblem, "constraints/linear/propfreq", -1) );
5030
5031 SCIP_CALL( SCIPsetIntParam(subproblem, "heuristics/alns/freq", -1) );
5032
5033 SCIP_CALL( SCIPsetIntParam(subproblem, "separating/aggregation/freq", -1) );
5034 SCIP_CALL( SCIPsetIntParam(subproblem, "separating/gomory/freq", -1) );
5035
5036 return SCIP_OKAY;
5037}
5038
5039/** resets the original parameters from the subproblem */
5040static
5042 SCIP* subproblem, /**< the SCIP data structure */
5043 SCIP_SUBPROBPARAMS* origparams /**< the original subproblem parameters */
5044 )
5045{
5046 assert(subproblem != NULL);
5047 assert(origparams != NULL);
5048
5049 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", origparams->limits_memory) );
5050 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", origparams->limits_time) );
5051 SCIP_CALL( SCIPsetBoolParam(subproblem, "conflict/enable", origparams->conflict_enable) );
5052 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", origparams->lp_disablecutoff) );
5053 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/scaling", origparams->lp_scaling) );
5054 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/initalgorithm", origparams->lp_initalg) );
5055 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/resolvealgorithm", origparams->lp_resolvealg) );
5056 SCIP_CALL( SCIPsetBoolParam(subproblem, "lp/alwaysgetduals", origparams->lp_alwaysgetduals) );
5057 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/scaleobj", origparams->misc_scaleobj) );
5058 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/catchctrlc", origparams->misc_catchctrlc) );
5059 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxrounds", origparams->prop_maxrounds) );
5060 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxroundsroot", origparams->prop_maxroundsroot) );
5061 SCIP_CALL( SCIPsetIntParam(subproblem, "constraints/linear/propfreq", origparams->cons_linear_propfreq) );
5062
5063 return SCIP_OKAY;
5064}
5066/** returns NLP solver parameters used for solving NLP subproblems */
5068 SCIP_BENDERS* benders /**< Benders' decomposition */
5069 )
5070{
5071 assert(benders != NULL);
5072
5073 return benders->nlpparam;
5074}
5075
5076/** solves the LP of the Benders' decomposition subproblem
5077 *
5078 * This requires that the subproblem is in probing mode.
5079 */
5081 SCIP* scip, /**< the SCIP data structure */
5082 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
5083 int probnumber, /**< the subproblem number */
5084 SCIP_STATUS* solvestatus, /**< status of subproblem solve */
5085 SCIP_Real* objective /**< optimal value of subproblem, if solved to optimality */
5086 )
5087{
5088 SCIP* subproblem;
5089 SCIP_SUBPROBPARAMS* origparams;
5090 SCIP_Bool solvenlp;
5091
5092 assert(benders != NULL);
5093 assert(solvestatus != NULL);
5094 assert(objective != NULL);
5095 assert(SCIPbendersSubproblemIsSetup(benders, probnumber));
5096
5097 /* TODO: This should be solved just as an LP, so as a MIP. There is too much overhead with the MIP.
5098 * Need to change status check for checking the LP. */
5099 subproblem = SCIPbendersSubproblem(benders, probnumber);
5100 assert(subproblem != NULL);
5101
5102 /* only solve the NLP relaxation if the NLP has been constructed and there exists an NLPI. If it is not possible to
5103 * solve the NLP relaxation, then the LP relaxation is used to generate Benders' cuts
5104 */
5105 solvenlp = FALSE;
5106 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0
5108 solvenlp = TRUE;
5109
5110 *objective = SCIPinfinity(subproblem);
5111
5112 assert(SCIPisNLPConstructed(subproblem) || SCIPisLPConstructed(subproblem));
5113 assert(SCIPinProbing(subproblem));
5114
5115 /* allocating memory for the parameter storage */
5116 SCIP_CALL( SCIPallocBlockMemory(subproblem, &origparams) );
5117
5118 /* store the original parameters of the subproblem */
5119 SCIP_CALL( storeOrigSubproblemParams(subproblem, origparams) );
5120
5121 /* setting the subproblem parameters */
5122 SCIP_CALL( setSubproblemParams(scip, subproblem) );
5123
5124 if( solvenlp )
5125 {
5126 SCIP_NLPSOLSTAT nlpsolstat;
5127 SCIP_NLPTERMSTAT nlptermstat;
5128#ifdef SCIP_MOREDEBUG
5129 SCIP_SOL* nlpsol;
5130#endif
5131
5132 SCIP_CALL( SCIPsolveNLPParam(subproblem, benders->nlpparam) );
5133
5134 nlpsolstat = SCIPgetNLPSolstat(subproblem);
5135 nlptermstat = SCIPgetNLPTermstat(subproblem);
5136 SCIPdebugMsg(scip, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
5137
5138 if( nlptermstat == SCIP_NLPTERMSTAT_OKAY && (nlpsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE) )
5139 {
5140 /* trust infeasible only if terminated "okay" */
5141 (*solvestatus) = SCIP_STATUS_INFEASIBLE;
5142 }
5143 else if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT
5144 || nlpsolstat == SCIP_NLPSOLSTAT_FEASIBLE )
5145 {
5146#ifdef SCIP_MOREDEBUG
5147 SCIP_CALL( SCIPcreateNLPSol(subproblem, &nlpsol, NULL) );
5148 SCIP_CALL( SCIPprintSol(subproblem, nlpsol, NULL, FALSE) );
5149 SCIP_CALL( SCIPfreeSol(subproblem, &nlpsol) );
5150#endif
5151
5152 (*solvestatus) = SCIP_STATUS_OPTIMAL;
5153 (*objective) = SCIPretransformObj(subproblem, SCIPgetNLPObjval(subproblem));
5154 }
5155 else if( nlpsolstat == SCIP_NLPSOLSTAT_UNBOUNDED )
5156 {
5157 (*solvestatus) = SCIP_STATUS_UNBOUNDED;
5158 SCIPerrorMessage("The NLP of Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
5159 probnumber);
5160 SCIPABORT();
5161 }
5162 else if( nlptermstat == SCIP_NLPTERMSTAT_TIMELIMIT )
5163 {
5164 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
5165 }
5166 else if( nlptermstat == SCIP_NLPTERMSTAT_ITERLIMIT)
5167 {
5168 /* this is an approximation in lack of a better fitting SCIP_STATUS */
5169 SCIPwarningMessage(scip, "The NLP solver stopped due to an iteration limit for Benders' decomposition subproblem %d. Consider increasing benders/%s/nlpiterlimit.\n", probnumber, SCIPbendersGetName(benders));
5170 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
5171 }
5172 else if( nlptermstat == SCIP_NLPTERMSTAT_INTERRUPT )
5173 {
5174 (*solvestatus) = SCIP_STATUS_USERINTERRUPT;
5175 }
5176 else
5177 {
5178 SCIPerrorMessage("Invalid solution status: %d. Termination status: %d. Solving the NLP relaxation of Benders' decomposition subproblem %d.\n",
5179 nlpsolstat, nlptermstat, probnumber);
5180 SCIPABORT();
5181 }
5182 }
5183 else
5184 {
5187
5188 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
5189
5190 switch( SCIPgetLPSolstat(subproblem) )
5191 {
5193 {
5194 (*solvestatus) = SCIP_STATUS_INFEASIBLE;
5195 break;
5196 }
5197
5199 {
5200 (*solvestatus) = SCIP_STATUS_OPTIMAL;
5201 (*objective) = SCIPgetSolOrigObj(subproblem, NULL)*(int)SCIPgetObjsense(scip);
5202 break;
5203 }
5204
5206 {
5207 (*solvestatus) = SCIP_STATUS_UNBOUNDED;
5208 SCIPerrorMessage("The LP of Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
5209 probnumber);
5210 SCIPABORT();
5211 break;
5212 }
5213
5217 {
5218 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_TIMELIMIT )
5219 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
5220 else
5221 (*solvestatus) = SCIP_STATUS_UNKNOWN;
5222
5223 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, " Benders' decomposition: Error solving LP "
5224 "relaxation of subproblem %d. No cut will be generated for this subproblem.\n", probnumber);
5225 break;
5226 }
5227
5230 default:
5231 {
5232 SCIPerrorMessage("Invalid status: %d. Solving the LP relaxation of Benders' decomposition subproblem %d.\n",
5233 SCIPgetLPSolstat(subproblem), probnumber);
5234 SCIPABORT();
5235 break;
5236 }
5237 }
5238 }
5239
5240 /* resetting the subproblem parameters */
5241 SCIP_CALL( resetOrigSubproblemParams(subproblem, origparams) );
5242
5243 /* freeing the parameter storage */
5244 SCIPfreeBlockMemory(subproblem, &origparams);
5245
5246 return SCIP_OKAY;
5247}
5249/** solves the Benders' decomposition subproblem */
5251 SCIP* scip, /**< the SCIP data structure */
5252 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
5253 int probnumber, /**< the subproblem number */
5254 SCIP_STATUS* solvestatus, /**< status of subproblem solve */
5255 SCIP_Bool solvecip /**< directly solve the CIP subproblem */
5256 )
5257{
5258 SCIP* subproblem;
5259 SCIP_SUBPROBPARAMS* origparams;
5260
5261 assert(benders != NULL);
5262 assert(solvestatus != NULL);
5263
5264 subproblem = SCIPbendersSubproblem(benders, probnumber);
5265 assert(subproblem != NULL);
5266
5267 /* allocating memory for the parameter storage */
5268 SCIP_CALL( SCIPallocBlockMemory(subproblem, &origparams) );
5269
5270 /* store the original parameters of the subproblem */
5271 SCIP_CALL( storeOrigSubproblemParams(subproblem, origparams) );
5272
5273 /* If the solve has been stopped for the subproblem, then we need to restart it to complete the solve. The subproblem
5274 * is stopped when it is a MIP so that LP cuts and IP cuts can be generated. */
5275 if( SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING )
5276 {
5277 /* the subproblem should be in probing mode. Otherwise, the event handler did not work correctly */
5278 assert( SCIPinProbing(subproblem) );
5279
5280 /* the probing mode needs to be stopped so that the MIP can be solved */
5281 SCIP_CALL( SCIPendProbing(subproblem) );
5282
5283 /* the problem was interrupted in the event handler, so SCIP needs to be informed that the problem is to be restarted */
5284 SCIP_CALL( SCIPrestartSolve(subproblem) );
5285 }
5286 else if( solvecip )
5287 {
5288 /* if the MIP will be solved directly, then the probing mode needs to be skipped.
5289 * This is achieved by setting the solvecip flag in the event handler data to TRUE
5290 */
5291 SCIP_EVENTHDLR* eventhdlr;
5292 SCIP_EVENTHDLRDATA* eventhdlrdata;
5293
5294 eventhdlr = SCIPfindEventhdlr(subproblem, MIPNODEFOCUS_EVENTHDLR_NAME);
5295 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
5296
5297 eventhdlrdata->solvecip = TRUE;
5298 }
5299 else
5300 {
5301 /* if the problem is not in probing mode, then we need to solve the LP. That requires all methods that will
5302 * modify the structure of the problem need to be deactivated */
5303
5304 /* setting the subproblem parameters */
5305 SCIP_CALL( setSubproblemParams(scip, subproblem) );
5306
5307#ifdef SCIP_EVENMOREDEBUG
5308 SCIP_CALL( SCIPsetBoolParam(subproblem, "display/lpinfo", TRUE) );
5309#endif
5310 }
5311
5312#ifdef SCIP_MOREDEBUG
5313 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_FULL) );
5314 SCIP_CALL( SCIPsetIntParam(subproblem, "display/freq", 1) );
5315#endif
5316
5317 SCIP_CALL( SCIPsolve(subproblem) );
5318
5319 *solvestatus = SCIPgetStatus(subproblem);
5320
5321 if( *solvestatus != SCIP_STATUS_OPTIMAL && *solvestatus != SCIP_STATUS_UNBOUNDED
5322 && *solvestatus != SCIP_STATUS_INFEASIBLE && *solvestatus != SCIP_STATUS_USERINTERRUPT
5323 && *solvestatus != SCIP_STATUS_BESTSOLLIMIT && *solvestatus != SCIP_STATUS_TIMELIMIT
5324 && *solvestatus != SCIP_STATUS_MEMLIMIT )
5325 {
5326 SCIPerrorMessage("Invalid status: %d. Solving the CIP of Benders' decomposition subproblem %d.\n",
5327 *solvestatus, probnumber);
5328 SCIPABORT();
5329 }
5330
5331 /* resetting the subproblem parameters */
5332 SCIP_CALL( resetOrigSubproblemParams(subproblem, origparams) );
5333
5334 /* freeing the parameter storage */
5335 SCIPfreeBlockMemory(subproblem, &origparams);
5336
5337 return SCIP_OKAY;
5338}
5340/** frees the subproblems */
5342 SCIP_BENDERS* benders, /**< Benders' decomposition */
5343 SCIP_SET* set, /**< global SCIP settings */
5344 int probnumber /**< the subproblem number */
5345 )
5346{
5347 assert(benders != NULL);
5348 assert(benders->bendersfreesub != NULL
5349 || (benders->bendersfreesub == NULL && benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL));
5350 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
5351
5352 if( benders->bendersfreesub != NULL )
5353 {
5354 SCIP_CALL( benders->bendersfreesub(set->scip, benders, probnumber) );
5355 }
5356 else
5357 {
5358 /* the subproblem is only freed if it is not independent */
5359 if( subproblemIsActive(benders, probnumber) )
5360 {
5361 SCIP* subproblem = SCIPbendersSubproblem(benders, probnumber);
5362
5364 {
5365 /* ending probing mode to reset the current node. The probing mode will be restarted at the next solve */
5366 if( SCIPinProbing(subproblem) )
5367 {
5368 SCIP_CALL( SCIPendProbing(subproblem) );
5369 }
5370 }
5371 else
5372 {
5373 /* if the subproblems were solved as part of an enforcement stage, then they will still be in probing mode. The
5374 * probing mode must first be finished and then the problem can be freed */
5375 if( SCIPgetStage(subproblem) >= SCIP_STAGE_TRANSFORMED && SCIPinProbing(subproblem) )
5376 {
5377 SCIP_CALL( SCIPendProbing(subproblem) );
5378 }
5379
5380 SCIP_CALL( SCIPfreeTransform(subproblem) );
5381 }
5382 }
5383 }
5384
5385 /* setting the setup flag for the subproblem to FALSE */
5386 SCIPbendersSetSubproblemIsSetup(benders, probnumber, FALSE);
5387 return SCIP_OKAY;
5388}
5390/** compares the subproblem objective value with the auxiliary variable value for optimality */
5392 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
5393 SCIP_SET* set, /**< global SCIP settings */
5394 SCIP_SOL* sol, /**< primal CIP solution */
5395 int probnumber /**< the subproblem number */
5396 )
5397{
5398 SCIP_Real auxiliaryvarval;
5399 SCIP_Bool optimal;
5400
5401 assert(benders != NULL);
5402 assert(set != NULL);
5403 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
5404
5405 optimal = FALSE;
5406
5407 auxiliaryvarval = SCIPbendersGetAuxiliaryVarVal(benders, set, sol, probnumber);
5408
5409 SCIPsetDebugMsg(set, "Subproblem %d - Auxiliary Variable: %g Subproblem Objective: %g Reldiff: %g Soltol: %g\n",
5410 probnumber, auxiliaryvarval, SCIPbendersGetSubproblemObjval(benders, probnumber),
5411 SCIPrelDiff(SCIPbendersGetSubproblemObjval(benders, probnumber), auxiliaryvarval), benders->solutiontol);
5412
5413 if( SCIPrelDiff(SCIPbendersGetSubproblemObjval(benders, probnumber), auxiliaryvarval) < benders->solutiontol )
5414 optimal = TRUE;
5415
5416 return optimal;
5417}
5419/** returns the value of the auxiliary variable value in a master problem solution */
5421 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
5422 SCIP_SET* set, /**< global SCIP settings */
5423 SCIP_SOL* sol, /**< primal CIP solution */
5424 int probnumber /**< the subproblem number */
5425 )
5426{
5427 SCIP_VAR* auxiliaryvar;
5428
5429 assert(benders != NULL);
5430 assert(set != NULL);
5431
5432 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
5433 assert(auxiliaryvar != NULL);
5434
5435 return SCIPgetSolVal(set->scip, sol, auxiliaryvar);
5436}
5437
5438/** Solves an independent subproblem to identify its lower bound. The lower bound is then used to update the bound on
5439 * the auxiliary variable.
5440 */
5442 SCIP_BENDERS* benders, /**< Benders' decomposition */
5443 SCIP_SET* set, /**< global SCIP settings */
5444 int probnumber, /**< the subproblem to be evaluated */
5445 SCIP_Real* lowerbound, /**< the lowerbound for the subproblem */
5446 SCIP_Bool* infeasible /**< was the subproblem found to be infeasible? */
5447 )
5448{
5449 SCIP* subproblem;
5450 SCIP_Real dualbound;
5451 SCIP_Real memorylimit;
5452 SCIP_Real timelimit;
5453 SCIP_Longint totalnodes;
5454 int disablecutoff;
5455 int verblevel;
5458
5459 assert(benders != NULL);
5460 assert(set != NULL);
5461
5462 if( benders->benderssolvesub != NULL || benders->benderssolvesubconvex != NULL )
5463 {
5464 (*lowerbound) = SCIPvarGetLbGlobal(SCIPbendersGetAuxiliaryVar(benders, probnumber));
5465 (*infeasible) = FALSE;
5466
5467 SCIPinfoMessage(set->scip, NULL, "Benders' decomposition: a bendersSolvesub or bendersSolvesubconvex has been "
5468 "implemented. SCIPbendersComputeSubproblemLowerbound can not be executed.\n");
5469 SCIPinfoMessage(set->scip, NULL, "Set the auxiliary variable lower bound by calling "
5470 "SCIPbendersUpdateSubproblemLowerbound in bendersCreatesub. The auxiliary variable %d will remain as %g\n",
5471 probnumber, (*lowerbound));
5472
5473 return SCIP_OKAY;
5474 }
5475 else
5476 {
5477 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Computing a lower bound for"
5478 " subproblem %d\n", probnumber);
5479 }
5480
5481 /* getting the subproblem to evaluate */
5482 subproblem = SCIPbendersSubproblem(benders, probnumber);
5483
5484 (*lowerbound) = -SCIPinfinity(subproblem);
5485 (*infeasible) = FALSE;
5486
5487 SCIP_CALL( SCIPgetIntParam(subproblem, "display/verblevel", &verblevel) );
5488 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_NONE) );
5489#ifdef SCIP_MOREDEBUG
5490 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_HIGH) );
5491#endif
5492
5493 /* copying memory and time limits */
5494 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/time", &timelimit) );
5495 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/memory", &memorylimit) );
5496 SCIP_CALL( copyMemoryAndTimeLimits(set->scip, subproblem) );
5497
5498 /* if the subproblem is independent, then the default SCIP settings are used. Otherwise, only the root node is solved
5499 * to compute a lower bound on the subproblem
5500 */
5501 SCIP_CALL( SCIPgetLongintParam(subproblem, "limits/totalnodes", &totalnodes) );
5502 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/disablecutoff", &disablecutoff) );
5503 if( !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
5504 {
5505 SCIP_CALL( SCIPsetLongintParam(subproblem, "limits/totalnodes", 1LL) );
5506 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", 1) );
5507 }
5508
5509 /* if the subproblem not independent and is convex, then the probing LP is solved. Otherwise, the MIP is solved */
5510 dualbound = -SCIPinfinity(subproblem);
5512 {
5513 SCIP_Bool solvenlp = FALSE;
5514
5515 assert(SCIPisLPConstructed(subproblem) || SCIPisNLPConstructed(subproblem));
5516
5517 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0
5519 solvenlp = TRUE;
5520
5521 SCIP_CALL( SCIPstartProbing(subproblem) );
5522 if( solvenlp )
5523 {
5524 SCIP_NLPSOLSTAT nlpsolstat;
5525 SCIP_NLPTERMSTAT nlptermstat;
5526
5527 SCIP_CALL( SCIPsolveNLPParam(subproblem, benders->nlpparam) );
5528
5529 nlpsolstat = SCIPgetNLPSolstat(subproblem);
5530 nlptermstat = SCIPgetNLPTermstat(subproblem);
5531 SCIPdebugMsg(set->scip, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
5532
5533 if( nlptermstat == SCIP_NLPTERMSTAT_OKAY && (nlpsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE) )
5534 {
5535 /* trust infeasible only if terminated "okay" */
5536 (*infeasible) = TRUE;
5537 }
5538 else if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT )
5539 {
5540 dualbound = SCIPretransformObj(subproblem, SCIPgetNLPObjval(subproblem));
5541 }
5542 }
5543 else
5544 {
5545 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
5546
5547 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_INFEASIBLE )
5548 (*infeasible) = TRUE;
5549 else if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_OPTIMAL )
5550 dualbound = SCIPgetSolOrigObj(subproblem, NULL)*(int)SCIPgetObjsense(set->scip);
5551 }
5552 }
5553 else
5554 {
5555 SCIP_EVENTHDLRDATA* eventhdlrdata;
5556
5557 /* if the subproblem is not convex, then event handlers have been added to interrupt the solve. These must be
5558 * disabled
5559 */
5561 eventhdlrdata->solvecip = TRUE;
5562
5563 SCIP_CALL( SCIPsolve(subproblem) );
5564
5565 if( SCIPgetStatus(subproblem) == SCIP_STATUS_INFEASIBLE )
5566 (*infeasible) = TRUE;
5567 else
5568 dualbound = SCIPgetDualbound(subproblem);
5569 }
5570
5571 /* getting the lower bound value */
5572 (*lowerbound) = dualbound;
5573
5574 if( !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
5575 {
5576 SCIP_CALL( SCIPsetLongintParam(subproblem, "limits/totalnodes", totalnodes) );
5577 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", disablecutoff) );
5578 }
5579 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", verblevel) );
5580 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", memorylimit) );
5581 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", timelimit) );
5582
5583 /* the subproblem must be freed so that it is reset for the subsequent Benders' decomposition solves. If the
5584 * subproblems are independent, they are not freed. SCIPfreeBendersSubproblem must still be called, but in this
5585 * function the independent subproblems are not freed. However, they will still be freed at the end of the
5586 * solving process for the master problem.
5587 */
5588 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, probnumber) );
5589
5590 return SCIP_OKAY;
5591}
5592
5593/** Merges a subproblem into the master problem. This process just adds a copy of the subproblem variables and
5594 * constraints to the master problem, but keeps the subproblem stored in the Benders' decomposition data structure. The reason for
5595 * keeping the subproblem available is for when it is queried for solutions after the problem is solved.
5596 *
5597 * Once the subproblem is merged into the master problem, then the subproblem is flagged as disabled. This means that
5598 * it will not be solved in the subsequent subproblem solving loops.
5599 *
5600 * The associated auxiliary variables are kept in the master problem. The objective function of the merged subproblem
5601 * is added as an underestimator constraint.
5602 */
5604 SCIP_BENDERS* benders, /**< Benders' decomposition */
5605 SCIP_SET* set, /**< global SCIP settings */
5606 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of subproblem variables corresponding
5607 * to the newly created master variables, or NULL */
5608 SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of subproblem constraints to the
5609 * corresponding newly created constraints, or NULL */
5610 int probnumber /**< the number of the subproblem that will be merged into the master problem*/
5611 )
5612{
5613 SCIP* subproblem;
5614 SCIP_HASHMAP* localvarmap;
5615 SCIP_HASHMAP* localconsmap;
5616 SCIP_VAR** vars;
5617 SCIP_VAR* auxiliaryvar;
5618 SCIP_CONS** conss;
5619 SCIP_CONS* objcons;
5620 int nvars;
5621 int nconss;
5622 int i;
5623 SCIP_Bool uselocalvarmap;
5624 SCIP_Bool uselocalconsmap;
5625 char varname[SCIP_MAXSTRLEN];
5626 char consname[SCIP_MAXSTRLEN];
5627 const char* origvarname;
5628
5629 assert(benders != NULL);
5630 assert(set != NULL);
5631 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
5632
5633 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_HIGH, NULL, " Benders' decomposition: Infeasibility of subproblem %d can't "
5634 "be resolved. Subproblem %d is being merged into the master problem.\n", probnumber, probnumber);
5635
5636 /* freeing the subproblem because it will be flagged as independent. Since the subproblem is flagged as independent,
5637 * it will no longer be solved or freed within the solving loop.
5638 */
5639 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, probnumber) );
5640
5641 subproblem = SCIPbendersSubproblem(benders, probnumber);
5642
5643 uselocalvarmap = (varmap == NULL);
5644 uselocalconsmap = (consmap == NULL);
5645
5646 if( uselocalvarmap )
5647 {
5648 /* create the variable mapping hash map */
5649 SCIP_CALL( SCIPhashmapCreate(&localvarmap, SCIPblkmem(set->scip), SCIPgetNVars(subproblem)) );
5650 }
5651 else
5652 localvarmap = varmap;
5653
5654 if( uselocalconsmap )
5655 {
5656 /* create the constraint mapping hash map */
5657 SCIP_CALL( SCIPhashmapCreate(&localconsmap, SCIPblkmem(set->scip), SCIPgetNConss(subproblem)) );
5658 }
5659 else
5660 localconsmap = consmap;
5661
5662 /* retrieving the subproblem variable to build a subproblem mapping */
5663 vars = SCIPgetVars(subproblem);
5664 nvars = SCIPgetNVars(subproblem);
5665
5666 /* creating the objective function constraint that will be added to the master problem */
5667 /* setting the name of the transferred cut */
5668 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "objectivecons_%d", probnumber );
5669 SCIP_CALL( SCIPcreateConsBasicLinear(set->scip, &objcons, consname, 0, NULL, NULL, -SCIPsetInfinity(set), 0.0) );
5670 SCIP_CALL( SCIPsetConsRemovable(set->scip, objcons, TRUE) );
5671
5672 for( i = 0; i < nvars; i++ )
5673 {
5674 SCIP_VAR* mastervar = NULL;
5675 SCIP_Bool releasevar = FALSE;
5676
5677 SCIP_CALL( SCIPgetBendersMasterVar(set->scip, benders, vars[i], &mastervar) );
5678
5679 /* if the master problem variable is not NULL, then there is a corresponding variable in the master problem for
5680 * the given subproblem variable. In this case, the variable is added to the hashmap.
5681 */
5682 if( mastervar == NULL )
5683 {
5684 SCIP_VAR* origvar;
5685 SCIP_Real scalar;
5686 SCIP_Real constant;
5687
5688 /* This is following the same process as in createVariableMappings. The original variable is used to map
5689 * between the subproblem and the master problem
5690 */
5691 origvar = vars[i];
5692 scalar = 1.0;
5693 constant = 0.0;
5694 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
5695
5696 /* retrieving the var name */
5697 origvarname = SCIPvarGetName(origvar);
5698 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s", origvarname);
5699
5700 /* creating and adding the variable to the Benders' decomposition master problem */
5701 SCIP_CALL( SCIPcreateVarBasic(set->scip, &mastervar, varname, SCIPvarGetLbOriginal(origvar),
5702 SCIPvarGetUbOriginal(origvar), 0.0, SCIPvarGetType(origvar)) );
5703
5704 /* adding the variable to the master problem */
5705 SCIP_CALL( SCIPaddVar(set->scip, mastervar) );
5706
5707 /* adds the variable to the objective function constraint */
5708 SCIP_CALL( SCIPaddCoefLinear(set->scip, objcons, mastervar, SCIPvarGetObj(origvar)) );
5709
5710 /* the variable must be released */
5711 releasevar = TRUE;
5712 }
5713
5714 /* creating the mapping betwen the subproblem var and the master var for the constraint copying */
5715 SCIP_CALL( SCIPhashmapInsert(localvarmap, vars[i], mastervar) );
5716
5717 /* releasing the variable */
5718 if( releasevar )
5719 {
5720 SCIP_CALL( SCIPreleaseVar(set->scip, &mastervar) );
5721 }
5722 }
5723
5724 /* getting the constraints from the subproblem that will be added to the master problem */
5725 conss = SCIPgetConss(subproblem);
5726 nconss = SCIPgetNConss(subproblem);
5727
5728 /* getting a copy of all constraints and adding it to the master problem */
5729 for( i = 0; i < nconss; i++ )
5730 {
5731 SCIP_CONS* targetcons;
5732 SCIP_Bool initial;
5734
5735 /* NOTE: adding all subproblem constraints appears to cause an error when resolving the LP, which results in the
5736 * current incumbent being reported as optimal. To avoid this, only half of the subproblem constraints are added
5737 * the master problem. The remaining half are marked as lazy and are separated as required.
5738 */
5739 initial = (i < nconss/2);
5740
5741 SCIP_CALL( SCIPgetConsCopy(subproblem, set->scip, conss[i], &targetcons, SCIPconsGetHdlr(conss[i]),
5742 localvarmap, localconsmap, NULL, initial, SCIPconsIsSeparated(conss[i]),
5745 FALSE, TRUE, &valid) );
5746 assert(SCIPconsIsInitial(conss[i]));
5747 assert(valid);
5748
5749 SCIP_CALL( SCIPaddCons(set->scip, targetcons) );
5750
5751 SCIP_CALL( SCIPreleaseCons(set->scip, &targetcons) );
5752 }
5753
5754 /* freeing the hashmaps */
5755 if( uselocalvarmap )
5756 {
5757 /* free hash map */
5758 SCIPhashmapFree(&localvarmap);
5759 }
5760
5761 if( uselocalconsmap )
5762 {
5763 /* free hash map */
5764 SCIPhashmapFree(&localconsmap);
5765 }
5766
5767 /* adding the auxiliary variable to the objective constraint */
5768 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
5769 SCIP_CALL( SCIPaddCoefLinear(set->scip, objcons, auxiliaryvar, -1.0) );
5770
5771 /* adding the objective function constraint to the master problem */
5772 SCIP_CALL( SCIPaddCons(set->scip, objcons) );
5773
5774 SCIP_CALL( SCIPreleaseCons(set->scip, &objcons) );
5775
5776 /* the merged subproblem is no longer solved. This is indicated by setting the subproblem as disabled. The
5777 * subproblem still exists, but it is not solved in the solving loop.
5778 */
5779 SCIPbendersSetSubproblemEnabled(benders, probnumber, FALSE);
5780
5781 return SCIP_OKAY;
5782}
5783
5784/** Returns the corresponding master or subproblem variable for the given variable.
5785 * This provides a call back for the variable mapping between the master and subproblems. */
5787 SCIP_BENDERS* benders, /**< Benders' decomposition */
5788 SCIP_SET* set, /**< global SCIP settings */
5789 SCIP_VAR* var, /**< the variable for which the corresponding variable is desired */
5790 SCIP_VAR** mappedvar, /**< the variable that is mapped to var */
5791 int probnumber /**< the problem number for the desired variable, -1 for the master problem */
5792 )
5793{
5794 assert(benders != NULL);
5795 assert(set != NULL);
5796 assert(var != NULL);
5797 assert(mappedvar != NULL);
5798 assert(benders->bendersgetvar != NULL);
5799
5800 (*mappedvar) = NULL;
5801
5802 /* if the variable name matches the auxiliary variable, then the master variable is returned as NULL */
5803 if( strstr(SCIPvarGetName(var), AUXILIARYVAR_NAME) != NULL )
5804 return SCIP_OKAY;
5805
5806 SCIP_CALL( benders->bendersgetvar(set->scip, benders, var, mappedvar, probnumber) );
5807
5808 return SCIP_OKAY;
5809}
5811/** gets user data of Benders' decomposition */
5813 SCIP_BENDERS* benders /**< Benders' decomposition */
5814 )
5815{
5816 assert(benders != NULL);
5817
5818 return benders->bendersdata;
5819}
5821/** sets user data of Benders' decomposition; user has to free old data in advance! */
5823 SCIP_BENDERS* benders, /**< Benders' decomposition */
5824 SCIP_BENDERSDATA* bendersdata /**< new Benders' decomposition user data */
5825 )
5826{
5827 assert(benders != NULL);
5828
5829 benders->bendersdata = bendersdata;
5830}
5832/** sets copy callback of Benders' decomposition */
5834 SCIP_BENDERS* benders, /**< Benders' decomposition */
5835 SCIP_DECL_BENDERSCOPY ((*benderscopy)) /**< copy callback of Benders' decomposition */
5836 )
5837{
5838 assert(benders != NULL);
5839
5840 benders->benderscopy = benderscopy;
5841}
5843/** sets destructor callback of Benders' decomposition */
5845 SCIP_BENDERS* benders, /**< Benders' decomposition */
5846 SCIP_DECL_BENDERSFREE ((*bendersfree)) /**< destructor of Benders' decomposition */
5847 )
5848{
5849 assert(benders != NULL);
5850
5851 benders->bendersfree = bendersfree;
5852}
5854/** sets initialization callback of Benders' decomposition */
5856 SCIP_BENDERS* benders, /**< Benders' decomposition */
5857 SCIP_DECL_BENDERSINIT((*bendersinit)) /**< initialize the Benders' decomposition */
5858 )
5859{
5860 assert(benders != NULL);
5861
5862 benders->bendersinit = bendersinit;
5863}
5865/** sets deinitialization callback of Benders' decomposition */
5867 SCIP_BENDERS* benders, /**< Benders' decomposition */
5868 SCIP_DECL_BENDERSEXIT((*bendersexit)) /**< deinitialize the Benders' decomposition */
5869 )
5870{
5871 assert(benders != NULL);
5872
5873 benders->bendersexit = bendersexit;
5874}
5876/** sets presolving initialization callback of Benders' decomposition */
5878 SCIP_BENDERS* benders, /**< Benders' decomposition */
5879 SCIP_DECL_BENDERSINITPRE((*bendersinitpre))/**< initialize presolving for Benders' decomposition */
5880 )
5881{
5882 assert(benders != NULL);
5883
5884 benders->bendersinitpre = bendersinitpre;
5885}
5887/** sets presolving deinitialization callback of Benders' decomposition */
5889 SCIP_BENDERS* benders, /**< Benders' decomposition */
5890 SCIP_DECL_BENDERSEXITPRE((*bendersexitpre))/**< deinitialize presolving for Benders' decomposition */
5891 )
5892{
5893 assert(benders != NULL);
5894
5895 benders->bendersexitpre = bendersexitpre;
5896}
5898/** sets solving process initialization callback of Benders' decomposition */
5900 SCIP_BENDERS* benders, /**< Benders' decomposition */
5901 SCIP_DECL_BENDERSINITSOL((*bendersinitsol))/**< solving process initialization callback of Benders' decomposition */
5902 )
5903{
5904 assert(benders != NULL);
5905
5906 benders->bendersinitsol = bendersinitsol;
5907}
5909/** sets solving process deinitialization callback of Benders' decomposition */
5911 SCIP_BENDERS* benders, /**< Benders' decomposition */
5912 SCIP_DECL_BENDERSEXITSOL((*bendersexitsol))/**< solving process deinitialization callback of Benders' decomposition */
5913 )
5914{
5915 assert(benders != NULL);
5916
5917 benders->bendersexitsol = bendersexitsol;
5918}
5920/** sets the pre subproblem solve callback of Benders' decomposition */
5922 SCIP_BENDERS* benders, /**< Benders' decomposition */
5923 SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve))/**< called prior to the subproblem solving loop */
5924 )
5925{
5926 assert(benders != NULL);
5927
5928 benders->benderspresubsolve = benderspresubsolve;
5929}
5931/** sets convex solve callback of Benders' decomposition */
5933 SCIP_BENDERS* benders, /**< Benders' decomposition */
5934 SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex))/**< solving method for the convex Benders' decomposition subproblem */
5935 )
5936{
5937 assert(benders != NULL);
5938
5939 benders->benderssolvesubconvex = benderssolvesubconvex;
5940}
5942/** sets solve callback of Benders' decomposition */
5944 SCIP_BENDERS* benders, /**< Benders' decomposition */
5945 SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub))/**< solving method for a Benders' decomposition subproblem */
5946 )
5947{
5948 assert(benders != NULL);
5949
5950 benders->benderssolvesub = benderssolvesub;
5951}
5953/** sets post-solve callback of Benders' decomposition */
5955 SCIP_BENDERS* benders, /**< Benders' decomposition */
5956 SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve))/**< solving process deinitialization callback of Benders' decomposition */
5957 )
5958{
5959 assert(benders != NULL);
5960
5961 benders->benderspostsolve = benderspostsolve;
5962}
5964/** sets post-solve callback of Benders' decomposition */
5966 SCIP_BENDERS* benders, /**< Benders' decomposition */
5967 SCIP_DECL_SORTPTRCOMP((*benderssubcomp)) /**< a comparator for defining the solving order of the subproblems */
5968 )
5969{
5970 assert(benders != NULL);
5971
5972 benders->benderssubcomp = benderssubcomp;
5973}
5975/** sets free subproblem callback of Benders' decomposition */
5977 SCIP_BENDERS* benders, /**< Benders' decomposition */
5978 SCIP_DECL_BENDERSFREESUB((*bendersfreesub))/**< the freeing callback for the subproblem */
5979 )
5980{
5981 assert(benders != NULL);
5982
5983 benders->bendersfreesub = bendersfreesub;
5984}
5986/** gets name of Benders' decomposition */
5987const char* SCIPbendersGetName(
5988 SCIP_BENDERS* benders /**< Benders' decomposition */
5989 )
5990{
5991 assert(benders != NULL);
5992
5993 return benders->name;
5994}
5996/** gets description of Benders' decomposition */
5997const char* SCIPbendersGetDesc(
5998 SCIP_BENDERS* benders /**< Benders' decomposition */
5999 )
6000{
6001 assert(benders != NULL);
6002
6003 return benders->desc;
6004}
6006/** gets priority of Benders' decomposition */
6008 SCIP_BENDERS* benders /**< Benders' decomposition */
6009 )
6010{
6011 assert(benders != NULL);
6012
6013 return benders->priority;
6014}
6016/** sets priority of Benders' decomposition */
6018 SCIP_BENDERS* benders, /**< Benders' decomposition */
6019 SCIP_SET* set, /**< global SCIP settings */
6020 int priority /**< new priority of the Benders' decomposition */
6021 )
6022{
6023 assert(benders != NULL);
6024 assert(set != NULL);
6025
6026 benders->priority = priority;
6027 set->benderssorted = FALSE;
6028}
6030/** gets the number of subproblems for the Benders' decomposition */
6032 SCIP_BENDERS* benders /**< the Benders' decomposition data structure */
6033 )
6034{
6035 assert(benders != NULL);
6036
6037 return benders->nsubproblems;
6038}
6040/** returns the SCIP instance for a given subproblem */
6042 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
6043 int probnumber /**< the subproblem number */
6044 )
6045{
6046 assert(benders != NULL);
6047 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
6048
6049 return benders->subproblems[probnumber];
6050}
6052/** gets the number of times, the Benders' decomposition was called and tried to find a variable with negative reduced costs */
6054 SCIP_BENDERS* benders /**< Benders' decomposition */
6055 )
6056{
6057 assert(benders != NULL);
6058
6059 return benders->ncalls;
6060}
6062/** gets the number of optimality cuts found by the collection of Benders' decomposition subproblems */
6064 SCIP_BENDERS* benders /**< Benders' decomposition */
6065 )
6066{
6067 assert(benders != NULL);
6068
6069 return benders->ncutsfound;
6070}
6072/** gets the number of cuts found from the strengthening round */
6074 SCIP_BENDERS* benders /**< Benders' decomposition */
6075 )
6076{
6077 assert(benders != NULL);
6078
6079 return benders->nstrengthencuts;
6080}
6082/** gets the number of calls to the strengthening round */
6084 SCIP_BENDERS* benders /**< Benders' decomposition */
6085 )
6086{
6087 assert(benders != NULL);
6088
6089 return benders->nstrengthencalls;
6090}
6092/** gets the number of calls to the strengthening round that fail */
6094 SCIP_BENDERS* benders /**< Benders' decomposition */
6095 )
6096{
6097 assert(benders != NULL);
6098
6099 return benders->nstrengthenfails;
6100}
6102/** gets time in seconds used in this Benders' decomposition for setting up for next stages */
6104 SCIP_BENDERS* benders /**< Benders' decomposition */
6105 )
6106{
6107 assert(benders != NULL);
6108
6109 return SCIPclockGetTime(benders->setuptime);
6110}
6112/** gets time in seconds used in this Benders' decomposition */
6114 SCIP_BENDERS* benders /**< Benders' decomposition */
6115 )
6116{
6117 assert(benders != NULL);
6118
6119 return SCIPclockGetTime(benders->bendersclock);
6120}
6122/** enables or disables all clocks of the Benders' decomposition, depending on the value of the flag */
6124 SCIP_BENDERS* benders, /**< the Benders' decomposition for which all clocks should be enabled or disabled */
6125 SCIP_Bool enable /**< should the clocks of the Benders' decomposition be enabled? */
6126 )
6127{
6128 assert(benders != NULL);
6129
6130 SCIPclockEnableOrDisable(benders->setuptime, enable);
6131 SCIPclockEnableOrDisable(benders->bendersclock, enable);
6132}
6134/** is Benders' decomposition initialized? */
6136 SCIP_BENDERS* benders /**< Benders' decomposition */
6137 )
6138{
6139 assert(benders != NULL);
6140
6141 return benders->initialized;
6142}
6144/** Are Benders' cuts generated from the LP solutions? */
6146 SCIP_BENDERS* benders /**< Benders' decomposition */
6147 )
6148{
6149 assert(benders != NULL);
6150
6151 return benders->cutlp;
6152}
6154/** Are Benders' cuts generated from the pseudo solutions? */
6156 SCIP_BENDERS* benders /**< Benders' decomposition */
6157 )
6158{
6159 assert(benders != NULL);
6160
6161 return benders->cutpseudo;
6162}
6164/** Are Benders' cuts generated from the relaxation solutions? */
6166 SCIP_BENDERS* benders /**< Benders' decomposition */
6167 )
6168{
6169 assert(benders != NULL);
6170
6171 return benders->cutrelax;
6172}
6174/** should this Benders' use the auxiliary variables from the highest priority Benders' */
6176 SCIP_BENDERS* benders /**< Benders' decomposition */
6177 )
6178{
6179 assert(benders != NULL);
6180
6181 return benders->shareauxvars;
6182}
6183
6184/** adds a subproblem to the Benders' decomposition data. If a custom subproblem solving method is used, then the
6185 * subproblem pointer can be set to NULL
6186 */
6188 SCIP_BENDERS* benders, /**< Benders' decomposition */
6189 SCIP* subproblem /**< subproblem to be added to the data storage, can be NULL */
6190 )
6191{
6192 assert(benders != NULL);
6193 assert(benders->naddedsubprobs + 1 <= benders->nsubproblems);
6194
6195 /* if the subproblem pointer is NULL, then the subproblem solving callback functions must be set. */
6196 if( subproblem == NULL && (!benders->benderssolvesubconvex || !benders->benderssolvesub) )
6197 {
6198 SCIPerrorMessage("The subproblem can only be set to NULL if both bendersSolvesubconvex%s and bendersSolvesub%s "
6199 "are defined.\n", benders->name, benders->name);
6200 return SCIP_ERROR;
6201 }
6202
6203 benders->subproblems[benders->naddedsubprobs] = subproblem;
6204
6205 benders->naddedsubprobs++;
6206
6207 return SCIP_OKAY;
6208}
6210/** removes the subproblems from the Benders' decomposition data */
6212 SCIP_BENDERS* benders /**< Benders' decomposition */
6213 )
6214{
6215 assert(benders != NULL);
6216 assert(benders->subproblems != NULL);
6217
6218 BMSclearMemoryArray(&benders->subproblems, benders->naddedsubprobs);
6219 benders->naddedsubprobs = 0;
6220}
6222/** returns the master auxiliary variable that is used the subproblem objective function */
6224 SCIP_BENDERS* benders /**< Benders' decomposition */
6225 )
6226{
6227 assert(benders != NULL);
6228
6229 return benders->masterauxvar;
6230}
6232/** returns the auxiliary variable for the given subproblem */
6234 SCIP_BENDERS* benders, /**< Benders' decomposition */
6235 int probnumber /**< the subproblem number */
6236 )
6237{
6238 assert(benders != NULL);
6239 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6240
6241 return benders->auxiliaryvars[probnumber];
6242}
6244/** returns all auxiliary variables */
6246 SCIP_BENDERS* benders /**< Benders' decomposition */
6247 )
6248{
6249 assert(benders != NULL);
6250
6251 return benders->auxiliaryvars;
6252}
6254/** returns the subproblem master variables for the given subproblem */
6256 SCIP_BENDERS* benders, /**< Benders' decomposition */
6257 int probnumber /**< the subproblem number */
6258 )
6259{
6260 assert(benders != NULL);
6261 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6262
6263 return benders->submastervars[probnumber];
6264}
6266/** returns the number of subproblem master variables for the given subproblem */
6268 SCIP_BENDERS* benders, /**< Benders' decomposition */
6269 int probnumber /**< the subproblem number */
6270 )
6271{
6272 assert(benders != NULL);
6273 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6274
6275 return benders->nsubmastervars[probnumber];
6276}
6278/** returns the subproblem master variable data for the given subproblem */
6280 SCIP_BENDERS* benders, /**< Benders' decomposition */
6281 int probnumber, /**< the subproblem number */
6282 SCIP_VAR*** vars, /**< pointer to store the master variables, or NULL */
6283 int* nvars, /**< the number of master problem variables, or NULL */
6284 int* nbinvars, /**< the number of binary master problem variables, or NULL */
6285 int* nintvars /**< the number of integer master problem variables, or NULL */
6286 )
6287{
6288 assert(benders != NULL);
6289 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6290
6291 if( vars != NULL )
6292 (*vars) = benders->submastervars[probnumber];
6293
6294 if( nvars != NULL )
6295 (*nvars) = benders->nsubmastervars[probnumber];
6296
6297 if( nbinvars != NULL )
6298 (*nbinvars) = benders->nsubmasterbinvars[probnumber];
6299
6300 if( nintvars != NULL )
6301 (*nintvars) = benders->nsubmasterintvars[probnumber];
6302}
6304/** stores the objective function value of the subproblem for use in cut generation */
6306 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
6307 int probnumber, /**< the subproblem number */
6308 SCIP_Real objval /**< the objective function value for the subproblem */
6309 )
6310{
6311 assert(benders != NULL);
6312 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6313
6314 /* updating the best objval */
6315 if( objval < benders->bestsubprobobjval[probnumber] )
6316 benders->bestsubprobobjval[probnumber] = objval;
6317
6318 benders->subprobobjval[probnumber] = objval;
6319}
6321/** returns the objective function value of the subproblem for use in cut generation */
6323 SCIP_BENDERS* benders, /**< Benders' decomposition */
6324 int probnumber /**< the subproblem number */
6325 )
6326{
6327 assert(benders != NULL);
6328 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6329
6330 return benders->subprobobjval[probnumber];
6331}
6333/** returns whether the solution has non-zero slack variables */
6335 SCIP_BENDERS* benders, /**< Benders' decomposition */
6336 SCIP_Bool* activeslack /**< flag to indicate whether a slack variable is active */
6337 )
6338{
6339 SCIP* subproblem;
6340 SCIP_SOL* sol;
6341 SCIP_VAR** vars;
6342 int nsubproblems;
6343 int nvars;
6344 int ncontvars;
6345 int i;
6346 int j;
6347 SCIP_Bool freesol = FALSE;
6348
6349 assert(benders != NULL);
6350 assert(activeslack != NULL);
6351
6352 (*activeslack) = FALSE;
6353
6354 /* if the slack variables have not been added, then we can immediately state that no slack variables are active */
6355 if( !benders->feasibilityphase )
6356 {
6357 return SCIP_OKAY;
6358 }
6359
6360 nsubproblems = SCIPbendersGetNSubproblems(benders);
6361
6362 /* checking all subproblems for active slack variables */
6363 for( i = 0; i < nsubproblems && !(*activeslack); i++ )
6364 {
6365 subproblem = SCIPbendersSubproblem(benders, i);
6366
6367 /* if the subproblem is convex and an NLP, then we need to create the NLP solution. Otherwise, the solution can be
6368 * retrieved from the LP or CIP.
6369 */
6371 {
6372 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0 )
6373 {
6374 SCIP_CALL( SCIPcreateNLPSol(subproblem, &sol, NULL) );
6375 }
6376 else
6377 {
6378 SCIP_CALL( SCIPcreateCurrentSol(subproblem, &sol, NULL) );
6379 }
6380 freesol = TRUE;
6381 }
6382 else
6383 sol = SCIPgetBestSol(subproblem);
6384
6385 /* getting the variable data. Only the continuous variables are important. */
6386 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, &ncontvars) );
6387
6388 /* checking all slack variables for non-zero solution values */
6389 for( j = nvars - 1; j >= nvars - ncontvars; j-- )
6390 {
6391 if( strstr(SCIPvarGetName(vars[j]), SLACKVAR_NAME) != NULL )
6392 {
6393 if( SCIPisPositive(subproblem, SCIPgetSolVal(subproblem, sol, vars[j])) )
6394 {
6395 (*activeslack) = TRUE;
6396 break;
6397 }
6398 }
6399 }
6400
6401 /* freeing the LP and NLP solutions */
6402 if( freesol )
6403 {
6404 SCIP_CALL( SCIPfreeSol(subproblem, &sol) );
6405 }
6406 }
6407
6408 return SCIP_OKAY;
6409}
6410
6411/** sets the subproblem type
6412 *
6413 * The subproblem types are:
6414 * - Convex constraints with continuous variables
6415 * - Convex constraints with discrete variables
6416 * - Non-convex constraints with continuous variables
6417 * - Non-convex constraints with discrete variables
6418 */
6420 SCIP_BENDERS* benders, /**< Benders' decomposition */
6421 int probnumber, /**< the subproblem number */
6422 SCIP_BENDERSSUBTYPE subprobtype /**< the subproblem type */
6423 )
6424{
6425 assert(benders != NULL);
6426 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6427
6428 if( subprobtype == SCIP_BENDERSSUBTYPE_CONVEXCONT
6429 && benders->subprobtype[probnumber] != SCIP_BENDERSSUBTYPE_CONVEXCONT )
6430 benders->nconvexsubprobs++;
6431 else if( subprobtype != SCIP_BENDERSSUBTYPE_CONVEXCONT
6432 && benders->subprobtype[probnumber] == SCIP_BENDERSSUBTYPE_CONVEXCONT )
6433 benders->nconvexsubprobs--;
6434
6435 benders->subprobtype[probnumber] = subprobtype;
6436
6437 assert(benders->nconvexsubprobs >= 0 && benders->nconvexsubprobs <= benders->nsubproblems);
6438}
6439
6440/** returns the type of the subproblem
6441 *
6442 * This type is used to determine whether the duals of the problem can be used to generate cuts
6443 */
6445 SCIP_BENDERS* benders, /**< Benders' decomposition */
6446 int probnumber /**< the subproblem number */
6447 )
6448{
6449 assert(benders != NULL);
6450 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6451
6452 return benders->subprobtype[probnumber];
6453}
6454
6455/** sets the flag indicating whether a subproblem is convex
6456 *
6457 * It is possible that this can change during the solving process. One example is when the three-phase method is
6458 * employed, where the first phase solves the convex relaxation of both the master and subproblems, the second phase
6459 * reintroduces the integrality constraints to the master problem and the third phase then reintroduces integrality
6460 * constraints to the subproblems.
6461 */
6463 SCIP_BENDERS* benders, /**< Benders' decomposition */
6464 int probnumber, /**< the subproblem number */
6465 SCIP_Bool isconvex /**< flag to indicate whether the subproblem is convex */
6466 )
6467{
6468 assert(benders != NULL);
6469 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6470
6471 if( isconvex && !benders->subprobisconvex[probnumber] )
6472 benders->nconvexsubprobs++;
6473 else if( !isconvex && benders->subprobisconvex[probnumber] )
6474 benders->nconvexsubprobs--;
6475
6476 benders->subprobisconvex[probnumber] = isconvex;
6477
6478 assert(benders->nconvexsubprobs >= 0 && benders->nconvexsubprobs <= benders->nsubproblems);
6479}
6480
6481/** returns whether the subproblem is convex
6482 *
6483 * This means that the dual solution can be used to generate cuts.
6484 */
6486 SCIP_BENDERS* benders, /**< Benders' decomposition */
6487 int probnumber /**< the subproblem number */
6488 )
6489{
6490 assert(benders != NULL);
6491 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6492
6493 return benders->subprobisconvex[probnumber];
6494}
6496/** returns the number of subproblems that are convex */
6498 SCIP_BENDERS* benders /**< Benders' decomposition */
6499 )
6500{
6501 assert(benders != NULL);
6502
6503 return benders->nconvexsubprobs;
6504}
6506/** sets the flag indicating whether a subproblem contains non-linear constraints */
6508 SCIP_BENDERS* benders, /**< Benders' decomposition */
6509 int probnumber, /**< the subproblem number */
6510 SCIP_Bool isnonlinear /**< flag to indicate whether the subproblem contains non-linear constraints */
6511 )
6512{
6513 assert(benders != NULL);
6514 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6515
6516 if( isnonlinear && !benders->subprobisnonlinear[probnumber] )
6517 benders->nnonlinearsubprobs++;
6518 else if( !isnonlinear && benders->subprobisnonlinear[probnumber] )
6519 benders->nnonlinearsubprobs--;
6520
6521 benders->subprobisnonlinear[probnumber] = isnonlinear;
6522
6523 assert(benders->nnonlinearsubprobs >= 0 && benders->nnonlinearsubprobs <= benders->nsubproblems);
6524}
6526/** returns whether the subproblem contains non-linear constraints */
6528 SCIP_BENDERS* benders, /**< Benders' decomposition */
6529 int probnumber /**< the subproblem number */
6530 )
6531{
6532 assert(benders != NULL);
6533 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6534
6535 return benders->subprobisnonlinear[probnumber];
6536}
6538/** returns the number of subproblems that contain non-linear constraints */
6540 SCIP_BENDERS* benders /**< Benders' decomposition */
6541 )
6542{
6543 assert(benders != NULL);
6544
6545 return benders->nnonlinearsubprobs;
6546}
6548/** sets the flag indicating whether the master problem contains non-linear constraints */
6550 SCIP_BENDERS* benders, /**< Benders' decomposition */
6551 SCIP_Bool isnonlinear /**< flag to indicate whether the subproblem contains non-linear constraints */
6552 )
6553{
6554 assert(benders != NULL);
6555
6556 benders->masterisnonlinear = isnonlinear;
6557}
6559/** returns whether the master problem contains non-linear constraints */
6561 SCIP_BENDERS* benders /**< Benders' decomposition */
6562 )
6563{
6564 assert(benders != NULL);
6565
6566 return benders->masterisnonlinear;
6567}
6569/** returns the flag indicating that Benders' decomposition is in a cut strengthening round */
6571 SCIP_BENDERS* benders /**< Benders' decomposition */
6572 )
6573{
6574 assert(benders != NULL);
6575
6576 return benders->strengthenround;
6577}
6578
6579/** sets the flag to indicate that at least one subproblem is always infeasible
6580 * NOTE: this is without any variable fixing being performed
6581 */
6583 SCIP_BENDERS* benders, /**< Benders' decomposition */
6584 SCIP_SET* set /**< global SCIP settings */
6585 )
6586{
6587 assert(benders != NULL);
6588 assert(set != NULL);
6589
6590 if( SCIPgetDepth(set->scip) <= 0 )
6591 benders->subprobsinfeasible = TRUE;
6592}
6593
6594/** returns whether at least one of the subproblems has been identified as infeasible.
6595 *
6596 * NOTE: this is without any variable fixing being performed
6597 */
6599 SCIP_BENDERS* benders /**< Benders' decomposition */
6600 )
6601{
6602 assert(benders != NULL);
6603
6604 return benders->subprobsinfeasible;
6605}
6607/** changes all of the master problem variables in the given subproblem to continuous */
6609 SCIP_BENDERS* benders, /**< Benders' decomposition */
6610 SCIP_SET* set, /**< global SCIP settings */
6611 int probnumber /**< the subproblem number */
6612 )
6613{
6614 SCIP* subproblem;
6615 SCIP_VAR** vars;
6616 int nbinvars;
6617 int nintvars;
6618 int nimplvars;
6619 int chgvarscount;
6620 int origintvars;
6621 int i;
6622 SCIP_Bool infeasible;
6623
6624 assert(benders != NULL);
6625 assert(set != NULL);
6626 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6627
6628 subproblem = SCIPbendersSubproblem(benders, probnumber);
6629 assert(subproblem != NULL);
6630
6631 /* only set the master problem variable to continuous if they have not already been changed. */
6632 if( !SCIPbendersGetMastervarsCont(benders, probnumber) )
6633 {
6634 SCIP_VAR* mastervar;
6635
6636 /* retrieving the variable data */
6637 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, NULL, &nbinvars, &nintvars, &nimplvars, NULL) );
6638
6639 origintvars = nbinvars + nintvars + nimplvars;
6640
6641 chgvarscount = 0;
6642
6643 /* looping over all integer variables to change the master variables to continuous */
6644 i = 0;
6645 while( i < nbinvars + nintvars + nimplvars )
6646 {
6647 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
6648
6649 if( SCIPvarIsIntegral(vars[i]) && mastervar != NULL )
6650 {
6651 /* remove integrality of the subproblem variable corresponding to mastervar */
6652 SCIP_CALL( SCIPchgVarType(subproblem, vars[i], SCIP_VARTYPE_CONTINUOUS, &infeasible) );
6653 assert(!infeasible);
6654 SCIP_CALL( SCIPchgVarImplType(subproblem, vars[i], SCIP_IMPLINTTYPE_NONE, &infeasible) );
6655 assert(!infeasible);
6656
6657 chgvarscount++;
6658 SCIP_CALL( SCIPgetVarsData(subproblem, NULL, NULL, &nbinvars, &nintvars, &nimplvars, NULL) );
6659 }
6660 else
6661 i++;
6662 }
6663
6664 /* if all of the integer variables have been changed to continuous, then the subproblem could now be a convex
6665 * problem. This must be checked and if TRUE, then the LP subproblem is initialised and then put into probing
6666 * mode
6667 */
6668 if( chgvarscount > 0 && chgvarscount == origintvars )
6669 {
6670 /* checking the convexity of the subproblem */
6671 SCIP_CALL( checkSubproblemConvexity(benders, set, probnumber) );
6672
6673 /* if the subproblem has convex constraints and continuous variables, then it is initialised and put into
6674 * probing mode
6675 */
6677 {
6678 SCIP_CALL( initialiseLPSubproblem(benders, set, probnumber, &infeasible) );
6679
6680 /* if the initialisation process indicates that the LP is infeasible, then the complete problem is
6681 * infeasible. The subprobsinfeasible flag is set so that SCIP can be informed at the correct point
6682 * during the solving process.
6683 */
6684 if( infeasible )
6686 }
6687 }
6688
6689 SCIP_CALL( SCIPbendersSetMastervarsCont(benders, probnumber, TRUE) );
6690 }
6691
6692 return SCIP_OKAY;
6693}
6695/** sets the subproblem setup flag */
6697 SCIP_BENDERS* benders, /**< Benders' decomposition */
6698 int probnumber, /**< the subproblem number */
6699 SCIP_Bool issetup /**< flag to indicate whether the subproblem has been setup */
6700 )
6701{
6702 assert(benders != NULL);
6703 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6704
6705 benders->subprobsetup[probnumber] = issetup;
6706}
6708/** returns the subproblem setup flag */
6710 SCIP_BENDERS* benders, /**< Benders' decomposition */
6711 int probnumber /**< the subproblem number */
6712 )
6713{
6714 assert(benders != NULL);
6715 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6716
6717 return benders->subprobsetup[probnumber];
6718}
6720/** sets the independent subproblem flag */
6722 SCIP_BENDERS* benders, /**< Benders' decomposition */
6723 int probnumber, /**< the subproblem number */
6724 SCIP_Bool isindep /**< flag to indicate whether the subproblem is independent */
6725 )
6726{
6727 assert(benders != NULL);
6728 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6729
6730 /* if the user has defined solving or freeing functions, then it is not possible to declare a subproblem as
6731 * independent. This is because declaring a subproblem as independent changes the solving loop, so it would change
6732 * the expected behaviour of the user defined plugin. If a user calls this function, then an error will be returned.
6733 */
6734 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL || benders->bendersfreesub != NULL )
6735 {
6736 SCIPerrorMessage("The user has defined either bendersSolvesubconvex%s, bendersSolvesub%s or bendersFreesub%s. "
6737 "Thus, it is not possible to declare the independence of a subproblem.\n", benders->name, benders->name,
6738 benders->name);
6739 SCIPABORT();
6740 }
6741 else
6742 {
6743 SCIP_Bool activesubprob;
6744
6745 /* if the active status of the subproblem changes, then we must update the activesubprobs counter */
6746 activesubprob = subproblemIsActive(benders, probnumber);
6747
6748 benders->indepsubprob[probnumber] = isindep;
6749
6750 /* updating the activesubprobs counter */
6751 if( activesubprob && !subproblemIsActive(benders, probnumber) )
6752 benders->nactivesubprobs--;
6753 else if( !activesubprob && subproblemIsActive(benders, probnumber) )
6754 benders->nactivesubprobs++;
6755
6756 assert(benders->nactivesubprobs >= 0 && benders->nactivesubprobs <= SCIPbendersGetNSubproblems(benders));
6757 }
6758}
6760/** returns whether the subproblem is independent */
6762 SCIP_BENDERS* benders, /**< Benders' decomposition */
6763 int probnumber /**< the subproblem number */
6764 )
6765{
6766 assert(benders != NULL);
6767 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6768
6769 return benders->indepsubprob[probnumber];
6770}
6771
6772/** Sets whether the subproblem is enabled or disabled. A subproblem is disabled if it has been merged into the master
6773 * problem.
6774 */
6776 SCIP_BENDERS* benders, /**< Benders' decomposition */
6777 int probnumber, /**< the subproblem number */
6778 SCIP_Bool enabled /**< flag to indicate whether the subproblem is enabled */
6779 )
6780{
6781 SCIP_Bool activesubprob;
6782
6783 assert(benders != NULL);
6784 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6785
6786 /* if the active status of the subproblem changes, then we must update the activesubprobs counter */
6787 activesubprob = subproblemIsActive(benders, probnumber);
6788
6789 benders->subprobenabled[probnumber] = enabled;
6790
6791 /* updating the activesubprobs counter */
6792 if( activesubprob && !subproblemIsActive(benders, probnumber) )
6793 benders->nactivesubprobs--;
6794 else if( !activesubprob && subproblemIsActive(benders, probnumber) )
6795 benders->nactivesubprobs++;
6796
6797 assert(benders->nactivesubprobs >= 0 && benders->nactivesubprobs <= SCIPbendersGetNSubproblems(benders));
6798}
6800/** returns whether the subproblem is enabled, i.e. the subproblem is still solved in the solving loop. */
6802 SCIP_BENDERS* benders, /**< Benders' decomposition */
6803 int probnumber /**< the subproblem number */
6804 )
6805{
6806 assert(benders != NULL);
6807 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6808
6809 return benders->subprobenabled[probnumber];
6810}
6812/** sets a flag to indicate whether the master variables are all set to continuous */
6814 SCIP_BENDERS* benders, /**< Benders' decomposition */
6815 int probnumber, /**< the subproblem number */
6816 SCIP_Bool arecont /**< flag to indicate whether the master problem variables are continuous */
6817 )
6818{
6819 assert(benders != NULL);
6820 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6821
6822 /* if the master variables were all continuous and now are not, then the subproblem must exit probing mode and be
6823 * changed to non-LP subproblem */
6824 if( benders->mastervarscont[probnumber] && !arecont )
6825 {
6826 SCIP_BENDERSSUBTYPE subtype;
6827
6828 if( SCIPinProbing(SCIPbendersSubproblem(benders, probnumber)) )
6829 {
6830 SCIP_CALL( SCIPendProbing(SCIPbendersSubproblem(benders, probnumber)) );
6831 }
6832
6833 subtype = SCIPbendersGetSubproblemType(benders, probnumber);
6835
6836 if( subtype == SCIP_BENDERSSUBTYPE_CONVEXCONT )
6838 else if( subtype == SCIP_BENDERSSUBTYPE_NONCONVEXCONT )
6840 }
6841
6842 benders->mastervarscont[probnumber] = arecont;
6843
6844 return SCIP_OKAY;
6845}
6847/** returns whether the master variables are all set to continuous */
6849 SCIP_BENDERS* benders, /**< Benders' decomposition */
6850 int probnumber /**< the subproblem number */
6851 )
6852{
6853 assert(benders != NULL);
6854 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6855
6856 return benders->mastervarscont[probnumber];
6857}
6858
6859/** sets the objective type for the aggregation of the Benders' decomposition subproblem objectives. This is either the
6860 * summation of the objective values or a minimax of the objective values (such as for a makespan objective)
6861 */
6863 SCIP_BENDERS* benders, /**< Benders' decomposition */
6864 SCIP_BENDERSOBJTYPE objectivetype /**< the objective type */
6865 )
6866{
6867 assert(benders != NULL);
6868
6869 benders->objectivetype = objectivetype;
6870}
6872/** returns the objective type for the aggregation of the Benders' decomposition subproblem objectives */
6874 SCIP_BENDERS* benders /**< Benders' decomposition */
6875 )
6876{
6877 assert(benders != NULL);
6878
6879 return benders->objectivetype;
6880}
6882/** returns the number of cuts that have been transferred from sub SCIPs to the master SCIP */
6884 SCIP_BENDERS* benders /**< the Benders' decomposition data structure */
6885 )
6886{
6887 assert(benders != NULL);
6888
6889 return benders->ntransferred;
6890}
6891
6892/** updates the lower bound for the subproblem. If the lower bound is not greater than the previously stored lowerbound,
6893 * then no update occurs.
6894 */
6896 SCIP_BENDERS* benders, /**< Benders' decomposition */
6897 int probnumber, /**< the subproblem number */
6898 SCIP_Real lowerbound /**< the lower bound */
6899 )
6900{
6901 assert(benders != NULL);
6902 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6903
6904 if( EPSGE(lowerbound, benders->subproblowerbound[probnumber], 1e-06) )
6905 benders->subproblowerbound[probnumber] = lowerbound;
6906 else
6907 {
6908 SCIPdebugMessage("The lowerbound %g for subproblem %d is less than the currently stored lower bound %g\n",
6909 lowerbound, probnumber, benders->subproblowerbound[probnumber]);
6910 }
6911}
6913/** returns the stored lower bound for the given subproblem */
6915 SCIP_BENDERS* benders, /**< Benders' decomposition */
6916 int probnumber /**< the subproblem number */
6917 )
6918{
6919 assert(benders != NULL);
6920 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6921
6922 return benders->subproblowerbound[probnumber];
6923}
6925/** returns the number of cuts that have been added for storage */
6927 SCIP_BENDERS* benders /**< Benders' decomposition */
6928 )
6929{
6930 assert(benders != NULL);
6931
6932 return benders->nstoredcuts;
6933}
6935/** returns the cuts that have been stored for transfer */
6937 SCIP_BENDERS* benders, /**< Benders' decomposition */
6938 int cutidx, /**< the index for the cut data that is requested */
6939 SCIP_VAR*** vars, /**< the variables that have non-zero coefficients in the cut */
6940 SCIP_Real** vals, /**< the coefficients of the variables in the cut */
6941 SCIP_Real* lhs, /**< the left hand side of the cut */
6942 SCIP_Real* rhs, /**< the right hand side of the cut */
6943 int* nvars /**< the number of variables with non-zero coefficients in the cut */
6944 )
6945{
6946 assert(benders != NULL);
6947 assert(vars != NULL);
6948 assert(vals != NULL);
6949 assert(lhs != NULL);
6950 assert(rhs != NULL);
6951 assert(nvars != NULL);
6952 assert(cutidx >= 0 && cutidx < benders->nstoredcuts);
6953
6954 (*vars) = benders->storedcuts[cutidx]->vars;
6955 (*vals) = benders->storedcuts[cutidx]->vals;
6956 (*lhs) = benders->storedcuts[cutidx]->lhs;
6957 (*rhs) = benders->storedcuts[cutidx]->rhs;
6958 (*nvars) = benders->storedcuts[cutidx]->nvars;
6959
6960 return SCIP_OKAY;
6961}
6962
6963/** returns the original problem data for the cuts that have been added by the Benders' cut plugin. The stored
6964 * variables and values will populate the input vars and vals arrays. Thus, memory must be allocated for the vars and
6965 * vals arrays
6966 */
6968 SCIP_BENDERS* benders, /**< Benders' decomposition cut */
6969 int cutidx, /**< the index for the cut data that is requested */
6970 SCIP_VAR*** vars, /**< the variables that have non-zero coefficients in the cut */
6971 SCIP_Real** vals, /**< the coefficients of the variables in the cut */
6972 SCIP_Real* lhs, /**< the left hand side of the cut */
6973 SCIP_Real* rhs, /**< the right hand side of the cut */
6974 int* nvars, /**< the number of variables with non-zero coefficients in the cut */
6975 int varssize /**< the available slots in the array */
6976 )
6977{
6978 SCIP_VAR* origvar;
6979 SCIP_Real scalar;
6980 SCIP_Real constant;
6981 int i;
6982
6983 assert(benders != NULL);
6984 assert(vars != NULL);
6985 assert(vals != NULL);
6986 assert(lhs != NULL);
6987 assert(rhs != NULL);
6988 assert(nvars != NULL);
6989 assert(cutidx >= 0 && cutidx < benders->nstoredcuts);
6990
6991 (*lhs) = benders->storedcuts[cutidx]->lhs;
6992 (*rhs) = benders->storedcuts[cutidx]->rhs;
6993 (*nvars) = benders->storedcuts[cutidx]->nvars;
6994
6995 /* if there are enough slots, then store the cut variables and values */
6996 if( varssize >= *nvars )
6997 {
6998 for( i = 0; i < *nvars; i++ )
6999 {
7000 /* getting the original variable for the transformed variable */
7001 origvar = benders->storedcuts[cutidx]->vars[i];
7002 scalar = 1.0;
7003 constant = 0.0;
7004 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
7005
7006 (*vars)[i] = origvar;
7007 (*vals)[i] = benders->storedcuts[cutidx]->vals[i];
7008 }
7009 }
7010
7011 return SCIP_OKAY;
7012}
7014/** adds the data for the generated cuts to the Benders' cut storage */
7016 SCIP_BENDERS* benders, /**< Benders' decomposition cut */
7017 SCIP_SET* set, /**< global SCIP settings */
7018 SCIP_VAR** vars, /**< the variables that have non-zero coefficients in the cut */
7019 SCIP_Real* vals, /**< the coefficients of the variables in the cut */
7020 SCIP_Real lhs, /**< the left hand side of the cut */
7021 SCIP_Real rhs, /**< the right hand side of the cut */
7022 int nvars /**< the number of variables with non-zero coefficients in the cut */
7023 )
7024{
7025 SCIP_BENDERSCUTCUT* cut;
7026
7027 assert(benders != NULL);
7028 assert(set != NULL);
7029 assert(vars != NULL);
7030 assert(vals != NULL);
7031
7032 /* allocating the block memory for the cut storage */
7033 SCIP_CALL( SCIPallocBlockMemory(set->scip, &cut) );
7034
7035 /* storing the cut data */
7037 SCIP_CALL( SCIPduplicateBlockMemoryArray(set->scip, &cut->vals, vals, nvars) );
7038 cut->lhs = lhs;
7039 cut->rhs = rhs;
7040 cut->nvars = nvars;
7041
7042 /* ensuring the required memory is available for the stored cuts array */
7043 if( benders->storedcutssize < benders->nstoredcuts + 1 )
7044 {
7045 int newsize;
7046
7047 newsize = SCIPsetCalcMemGrowSize(set, benders->nstoredcuts + 1);
7049 benders->storedcutssize, newsize) );
7050
7051 benders->storedcutssize = newsize;
7052 }
7053 assert(benders->storedcutssize >= benders->nstoredcuts + 1);
7054
7055 /* adding the cuts to the Benders' cut storage */
7056 benders->storedcuts[benders->nstoredcuts] = cut;
7057 benders->nstoredcuts++;
7058
7059 return SCIP_OKAY;
7060}
7062/** sets the sorted flags in the Benders' decomposition */
7064 SCIP_BENDERS* benders, /**< Benders' decomposition structure */
7065 SCIP_Bool sorted /**< the value to set the sorted flag to */
7066 )
7067{
7068 assert(benders != NULL);
7069
7070 benders->benderscutssorted = sorted;
7071 benders->benderscutsnamessorted = sorted;
7072}
7074/** inserts a Benders' cut into the Benders' cuts list */
7076 SCIP_BENDERS* benders, /**< Benders' decomposition structure */
7077 SCIP_SET* set, /**< global SCIP settings */
7078 SCIP_BENDERSCUT* benderscut /**< Benders' cut */
7079 )
7080{
7081 assert(benders != NULL);
7082 assert(benderscut != NULL);
7083
7084 if( benders->nbenderscuts >= benders->benderscutssize )
7085 {
7088 }
7089 assert(benders->nbenderscuts < benders->benderscutssize);
7090
7091 benders->benderscuts[benders->nbenderscuts] = benderscut;
7092 benders->nbenderscuts++;
7093 benders->benderscutssorted = FALSE;
7094
7095 return SCIP_OKAY;
7096}
7098/** returns the Benders' cut of the given name, or NULL if not existing */
7100 SCIP_BENDERS* benders, /**< Benders' decomposition */
7101 const char* name /**< name of Benderscut' decomposition */
7102 )
7103{
7104 int i;
7105
7106 assert(benders != NULL);
7107 assert(name != NULL);
7108
7109 for( i = 0; i < benders->nbenderscuts; i++ )
7110 {
7111 if( strcmp(SCIPbenderscutGetName(benders->benderscuts[i]), name) == 0 )
7112 return benders->benderscuts[i];
7113 }
7114
7115 return NULL;
7116}
7117
7118/** returns the array of currently available Benders' cuts; active Benders' decomposition are in the first slots of
7119 * the array
7120 */
7122 SCIP_BENDERS* benders /**< Benders' decomposition */
7123 )
7124{
7125 assert(benders != NULL);
7126
7127 if( !benders->benderscutssorted )
7128 {
7129 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutComp, benders->nbenderscuts);
7130 benders->benderscutssorted = TRUE;
7131 benders->benderscutsnamessorted = FALSE;
7132 }
7133
7134 return benders->benderscuts;
7135}
7137/** returns the number of currently available Benders' cuts */
7139 SCIP_BENDERS* benders /**< Benders' decomposition */
7140 )
7141{
7142 assert(benders != NULL);
7143
7144 return benders->nbenderscuts;
7145}
7147/** sets the priority of a Benders' decomposition */
7149 SCIP_BENDERS* benders, /**< Benders' decomposition */
7150 SCIP_BENDERSCUT* benderscut, /**< Benders' cut */
7151 int priority /**< new priority of the Benders' decomposition */
7152 )
7153{
7154 assert(benders != NULL);
7155 assert(benderscut != NULL);
7156
7157 benderscut->priority = priority;
7158 benders->benderscutssorted = FALSE;
7159
7160 return SCIP_OKAY;
7161}
7163/** sorts Benders' decomposition cuts by priorities */
7165 SCIP_BENDERS* benders /**< Benders' decomposition */
7166 )
7167{
7168 assert(benders != NULL);
7169
7170 if( !benders->benderscutssorted )
7171 {
7172 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutComp, benders->nbenderscuts);
7173 benders->benderscutssorted = TRUE;
7174 benders->benderscutsnamessorted = FALSE;
7175 }
7176}
7178/** sorts Benders' decomposition cuts by name */
7180 SCIP_BENDERS* benders /**< Benders' decomposition */
7181 )
7182{
7183 assert(benders != NULL);
7184
7185 if( !benders->benderscutsnamessorted )
7186 {
7187 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutCompName, benders->nbenderscuts);
7188 benders->benderscutssorted = FALSE;
7189 benders->benderscutsnamessorted = TRUE;
7190 }
7191}
SCIP_RETCODE SCIPbenderscutExit(SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
Definition benderscut.c:268
SCIP_RETCODE SCIPbenderscutFree(SCIP_BENDERSCUT **benderscut, SCIP_SET *set)
Definition benderscut.c:203
SCIP_RETCODE SCIPbenderscutInitsol(SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
Definition benderscut.c:298
SCIP_RETCODE SCIPbenderscutExitsol(SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
Definition benderscut.c:322
SCIP_RETCODE SCIPbenderscutExec(SCIP_BENDERSCUT *benderscut, SCIP_SET *set, SCIP_BENDERS *benders, SCIP_SOL *sol, int probnumber, SCIP_BENDERSENFOTYPE type, SCIP_RESULT *result)
Definition benderscut.c:346
SCIP_RETCODE SCIPbenderscutCopyInclude(SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
Definition benderscut.c:86
SCIP_RETCODE SCIPbenderscutInit(SCIP_BENDERSCUT *benderscut, SCIP_SET *set)
Definition benderscut.c:229
internal methods for Benders' decomposition cuts
void SCIPclockStop(SCIP_CLOCK *clck, SCIP_SET *set)
Definition clock.c:360
void SCIPclockEnableOrDisable(SCIP_CLOCK *clck, SCIP_Bool enable)
Definition clock.c:260
void SCIPclockStart(SCIP_CLOCK *clck, SCIP_SET *set)
Definition clock.c:290
SCIP_Real SCIPclockGetTime(SCIP_CLOCK *clck)
Definition clock.c:438
void SCIPclockReset(SCIP_CLOCK *clck)
Definition clock.c:209
void SCIPclockFree(SCIP_CLOCK **clck)
Definition clock.c:185
SCIP_RETCODE SCIPclockCreate(SCIP_CLOCK **clck, SCIP_CLOCKTYPE clocktype)
Definition clock.c:170
internal methods for clocks and timing issues
Constraint handler for linear constraints in their most general form, .
constraint handler for nonlinear constraints specified by algebraic expressions
internal methods for decompositions and the decomposition store
common defines and data types used in all packages of SCIP
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define EPSGE(x, y, eps)
Definition def.h:196
#define SCIP_Longint
Definition def.h:150
#define SCIP_MAXTREEDEPTH
Definition def.h:306
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define SCIP_ALLOC(x)
Definition def.h:375
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIPABORT()
Definition def.h:336
#define SCIP_CALL(x)
Definition def.h:364
#define SCIP_CALL_FINALLY(x, y)
Definition def.h:406
SCIP_RETCODE SCIPaddLinearVarNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
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_EXPR * SCIPgetExprNonlinear(SCIP_CONS *cons)
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
SCIP_EXPRCURV SCIPgetCurvatureNonlinear(SCIP_CONS *cons)
SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
int SCIPgetSubscipDepth(SCIP *scip)
Definition scip_copy.c:2589
SCIP_RETCODE SCIPgetConsCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_CONS *sourcecons, SCIP_CONS **targetcons, SCIP_CONSHDLR *sourceconshdlr, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, const char *name, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
Definition scip_copy.c:1581
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_RETCODE SCIPfree(SCIP **scip)
SCIP_STATUS SCIPgetStatus(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition scip_prob.c:1907
const char * SCIPgetProbName(SCIP *scip)
Definition scip_prob.c:1242
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition scip_prob.c:2115
int SCIPgetNOrigConss(SCIP *scip)
Definition scip_prob.c:3712
SCIP_CONS ** SCIPgetConss(SCIP *scip)
Definition scip_prob.c:3666
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3274
int SCIPgetNConss(SCIP *scip)
Definition scip_prob.c:3620
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
SCIP_CONS ** SCIPgetOrigConss(SCIP *scip)
Definition scip_prob.c:3739
SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
Definition scip_prob.c:1400
SCIP_Bool SCIPisObjIntegral(SCIP *scip)
Definition scip_prob.c:1801
SCIP_VAR * SCIPfindVar(SCIP *scip, const char *name)
Definition scip_prob.c:3189
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
Definition misc.c:3613
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3284
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition misc.c:3143
int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
Definition misc.c:3584
SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
Definition misc.c:3592
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
#define SCIPdebugMsg
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
SCIP_RETCODE SCIPhasExprCurvature(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRCURV curv, SCIP_Bool *success, SCIP_HASHMAP *assumevarfixed)
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition misc.c:11162
SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
Definition scip_param.c:250
SCIP_PARAM * SCIPgetParam(SCIP *scip, const char *name)
Definition scip_param.c:234
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition scip_param.c:545
SCIP_RETCODE SCIPsetHeuristics(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
Definition scip_param.c:930
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition scip_param.c:487
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition scip_param.c:307
SCIP_RETCODE SCIPsetPresolving(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
Definition scip_param.c:956
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition scip_param.c:661
SCIP_Bool SCIPgetSubscipsOff(SCIP *scip)
SCIP_RETCODE SCIPgetLongintParam(SCIP *scip, const char *name, SCIP_Longint *value)
Definition scip_param.c:288
SCIP_RETCODE SCIPgetIntParam(SCIP *scip, const char *name, int *value)
Definition scip_param.c:269
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition scip_param.c:429
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition scip_param.c:603
SCIP_RETCODE SCIPgetCharParam(SCIP *scip, const char *name, char *value)
Definition scip_param.c:326
SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)),)
Definition misc.c:1297
void SCIPpqueueFree(SCIP_PQUEUE **pqueue)
Definition misc.c:1324
SCIP_RETCODE SCIPpqueueInsert(SCIP_PQUEUE *pqueue, void *elem)
Definition misc.c:1396
int SCIPpqueueNElems(SCIP_PQUEUE *pqueue)
Definition misc.c:1529
void * SCIPpqueueRemove(SCIP_PQUEUE *pqueue)
Definition misc.c:1495
SCIP_BENDERSOBJTYPE SCIPbendersGetObjectiveType(SCIP_BENDERS *benders)
Definition benders.c:6871
SCIP_Real SCIPbendersGetSetupTime(SCIP_BENDERS *benders)
Definition benders.c:6101
void SCIPbendersSetSubproblemObjval(SCIP_BENDERS *benders, int probnumber, SCIP_Real objval)
Definition benders.c:6303
SCIP_RETCODE SCIPbendersSolSlackVarsActive(SCIP_BENDERS *benders, SCIP_Bool *activeslack)
Definition benders.c:6332
SCIP_Bool SCIPbendersCutRelaxation(SCIP_BENDERS *benders)
Definition benders.c:6163
int SCIPbendersGetNTransferredCuts(SCIP_BENDERS *benders)
Definition benders.c:6881
SCIP_Bool SCIPbendersSubproblemIsConvex(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6483
int SCIPbendersGetNStrengthenFails(SCIP_BENDERS *benders)
Definition benders.c:6091
int SCIPgetBendersNSubproblems(SCIP *scip, SCIP_BENDERS *benders)
SCIP_RETCODE SCIPbendersGetStoredCutOrigData(SCIP_BENDERS *benders, int cutidx, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, SCIP_Real *rhs, int *nvars, int varssize)
Definition benders.c:6965
SCIP_BENDERS ** SCIPgetBenders(SCIP *scip)
void SCIPbendersSetSubproblemIsNonlinear(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isnonlinear)
Definition benders.c:6505
void SCIPbendersSetMasterIsNonlinear(SCIP_BENDERS *benders, SCIP_Bool isnonlinear)
Definition benders.c:6547
SCIP_BENDERS * SCIPfindBenders(SCIP *scip, const char *name)
void SCIPbendersSetData(SCIP_BENDERS *benders, SCIP_BENDERSDATA *bendersdata)
Definition benders.c:5820
SCIP_Bool SCIPbendersOnlyCheckConvexRelax(SCIP_BENDERS *benders, SCIP_Bool subscipsoff)
Definition benders.c:3319
SCIP_Bool SCIPbendersSubproblemIsNonlinear(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6525
int SCIPbendersGetPriority(SCIP_BENDERS *benders)
Definition benders.c:6005
SCIP_VAR * SCIPbendersGetAuxiliaryVar(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6231
SCIP_BENDERSCUT * SCIPfindBenderscut(SCIP_BENDERS *benders, const char *name)
Definition benders.c:7097
const char * SCIPbendersGetDesc(SCIP_BENDERS *benders)
Definition benders.c:5995
int SCIPbendersGetNConvexSubproblems(SCIP_BENDERS *benders)
Definition benders.c:6495
SCIP_BENDERSSUBTYPE SCIPbendersGetSubproblemType(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6442
SCIP_VAR ** SCIPbendersGetSubproblemMasterVars(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6253
SCIP_RETCODE SCIPbendersSolveSubproblemCIP(SCIP *scip, SCIP_BENDERS *benders, int probnumber, SCIP_STATUS *solvestatus, SCIP_Bool solvecip)
Definition benders.c:5248
int SCIPbendersGetNNonlinearSubproblems(SCIP_BENDERS *benders)
Definition benders.c:6537
void SCIPsetBendersPriority(SCIP *scip, SCIP_BENDERS *benders, int priority)
SCIP_NLPPARAM SCIPbendersGetNLPParam(SCIP_BENDERS *benders)
Definition benders.c:5065
SCIP_Bool SCIPbendersSubproblemIsEnabled(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6799
SCIP_RETCODE SCIPgetBendersMasterVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar)
int SCIPbendersGetNStrengthenCalls(SCIP_BENDERS *benders)
Definition benders.c:6081
SCIP_RETCODE SCIPgetBendersSubproblemVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar, int probnumber)
int SCIPbendersGetNStoredCuts(SCIP_BENDERS *benders)
Definition benders.c:6924
SCIP_RETCODE SCIPbendersSolveSubproblemLP(SCIP *scip, SCIP_BENDERS *benders, int probnumber, SCIP_STATUS *solvestatus, SCIP_Real *objective)
Definition benders.c:5078
int SCIPbendersGetNBenderscuts(SCIP_BENDERS *benders)
Definition benders.c:7136
void SCIPbendersSetSubproblemIsConvex(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isconvex)
Definition benders.c:6460
SCIP_Bool SCIPbendersIsActive(SCIP_BENDERS *benders)
Definition benders.c:3006
SCIP_Bool SCIPbendersSubproblemsAreInfeasible(SCIP_BENDERS *benders)
Definition benders.c:6596
void SCIPbendersSetSubproblemIsSetup(SCIP_BENDERS *benders, int probnumber, SCIP_Bool issetup)
Definition benders.c:6694
SCIP_BENDERSDATA * SCIPbendersGetData(SCIP_BENDERS *benders)
Definition benders.c:5810
const char * SCIPbendersGetName(SCIP_BENDERS *benders)
Definition benders.c:5985
SCIP_Bool SCIPbendersCutPseudo(SCIP_BENDERS *benders)
Definition benders.c:6153
SCIP_VAR ** SCIPbendersGetAuxiliaryVars(SCIP_BENDERS *benders)
Definition benders.c:6243
int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
Definition benders.c:6029
void SCIPbendersSetSubproblemType(SCIP_BENDERS *benders, int probnumber, SCIP_BENDERSSUBTYPE subprobtype)
Definition benders.c:6417
int SCIPbendersGetNStrengthenCutsFound(SCIP_BENDERS *benders)
Definition benders.c:6071
void SCIPbendersUpdateSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber, SCIP_Real lowerbound)
Definition benders.c:6893
SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6039
void SCIPbendersGetSubproblemMasterVarsData(SCIP_BENDERS *benders, int probnumber, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars)
Definition benders.c:6277
SCIP_Bool SCIPbendersMasterIsNonlinear(SCIP_BENDERS *benders)
Definition benders.c:6558
SCIP_RETCODE SCIPbendersGetStoredCutData(SCIP_BENDERS *benders, int cutidx, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, SCIP_Real *rhs, int *nvars)
Definition benders.c:6934
int SCIPbendersGetNCalls(SCIP_BENDERS *benders)
Definition benders.c:6051
SCIP_Bool SCIPbendersIsInitialized(SCIP_BENDERS *benders)
Definition benders.c:6133
int SCIPbendersGetNCutsFound(SCIP_BENDERS *benders)
Definition benders.c:6061
SCIP_Bool SCIPbendersShareAuxVars(SCIP_BENDERS *benders)
Definition benders.c:6173
SCIP_Bool SCIPbendersCutLP(SCIP_BENDERS *benders)
Definition benders.c:6143
SCIP_RETCODE SCIPbendersSetBenderscutPriority(SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, int priority)
Definition benders.c:7146
SCIP_Real SCIPbendersGetTime(SCIP_BENDERS *benders)
Definition benders.c:6111
SCIP_Bool SCIPbendersSubproblemIsIndependent(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6759
SCIP_RETCODE SCIPsolveBendersSubproblems(SCIP *scip, SCIP_BENDERS *benders, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool *infeasible, SCIP_Bool *auxviol, SCIP_BENDERSENFOTYPE type, SCIP_Bool checkint)
SCIP_BENDERSCUT ** SCIPbendersGetBenderscuts(SCIP_BENDERS *benders)
Definition benders.c:7119
SCIP_VAR * SCIPbenderGetMasterAuxiliaryVar(SCIP_BENDERS *benders)
Definition benders.c:6221
SCIP_Real SCIPbendersGetSubproblemObjval(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6320
void SCIPbendersSetSubproblemIsIndependent(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isindep)
Definition benders.c:6719
SCIP_Bool SCIPbendersInStrengthenRound(SCIP_BENDERS *benders)
Definition benders.c:6568
SCIP_Bool SCIPbendersSubproblemIsSetup(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6707
SCIP_Real SCIPbendersGetSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6912
int SCIPbendersGetNSubproblemMasterVars(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6265
SCIP_Bool SCIPbenderscutIsLPCut(SCIP_BENDERSCUT *benderscut)
Definition benderscut.c:583
const char * SCIPbenderscutGetName(SCIP_BENDERSCUT *benderscut)
Definition benderscut.c:492
SCIP_Longint SCIPbenderscutGetNFound(SCIP_BENDERSCUT *benderscut)
Definition benderscut.c:543
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4320
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8652
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8562
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8592
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8582
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8612
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable)
Definition scip_cons.c:1474
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8642
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8572
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1138
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8662
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition scip_cut.c:336
SCIP_RETCODE SCIPsetEventhdlrFree(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
Definition scip_event.c:157
SCIP_RETCODE SCIPsetEventhdlrInitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
Definition scip_event.c:199
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition scip_event.c:111
SCIP_RETCODE SCIPsetEventhdlrExit(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
Definition scip_event.c:185
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition scip_event.c:241
SCIP_RETCODE SCIPsetEventhdlrExitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
Definition scip_event.c:213
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition event.c:396
SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
Definition event.c:406
void SCIPeventhdlrSetData(SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition event.c:416
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:293
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:333
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1742
SCIP_Bool SCIPinDive(SCIP *scip)
Definition scip_lp.c:2740
SCIP_RETCODE SCIPconstructLP(SCIP *scip, SCIP_Bool *cutoff)
Definition scip_lp.c:130
SCIP_Bool SCIPisLPConstructed(SCIP *scip)
Definition scip_lp.c:105
SCIP_RETCODE SCIPcomputeLPRelIntPoint(SCIP *scip, SCIP_Bool relaxrows, SCIP_Bool inclobjcutoff, SCIP_Real timelimit, int iterlimit, SCIP_SOL **point)
Definition scip_lp.c:1103
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition scip_lp.c:174
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition scip_mem.c:126
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition scip_mem.c:100
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:97
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
int SCIPgetNNlpis(SCIP *scip)
Definition scip_nlpi.c:205
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition scip_nlp.c:110
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition scip_nlp.c:574
SCIP_Real SCIPgetNLPObjval(SCIP *scip)
Definition scip_nlp.c:645
SCIP_RETCODE SCIPsolveNLPParam(SCIP *scip, SCIP_NLPPARAM param)
Definition scip_nlp.c:545
SCIP_NLPTERMSTAT SCIPgetNLPTermstat(SCIP *scip)
Definition scip_nlp.c:596
SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
SCIP_RETCODE SCIPchgVarObjProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
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 SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition scip_sol.c:2986
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition scip_sol.c:882
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition scip_sol.c:2351
SCIP_RETCODE SCIPcreateCurrentSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition scip_sol.c:747
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition scip_sol.c:662
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition scip_sol.c:606
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:1504
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:1890
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1569
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:2003
SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
Definition scip_sol.c:2134
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
SCIP_RETCODE SCIPinterruptSolve(SCIP *scip)
SCIP_RETCODE SCIPsolve(SCIP *scip)
SCIP_Real SCIPgetPrimalbound(SCIP *scip)
SCIP_Real SCIPgetDualbound(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition scip_tree.c:91
SCIP_RETCODE SCIPvarGetOrigvarSum(SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition var.c:18365
SCIP_RETCODE SCIPchgVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition scip_var.c:5697
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition var.c:4443
SCIP_Real SCIPvarGetLbOriginal(SCIP_VAR *var)
Definition var.c:24052
SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition scip_var.c:5875
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23932
SCIP_RETCODE SCIPchgVarImplType(SCIP *scip, SCIP_VAR *var, SCIP_IMPLINTTYPE impltype, SCIP_Bool *infeasible)
Definition scip_var.c:10218
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23485
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition scip_var.c:5118
SCIP_RETCODE SCIPcreateVarImpl(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_IMPLINTTYPE impltype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition scip_var.c:225
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_Real SCIPvarGetUbOriginal(SCIP_VAR *var)
Definition var.c:24095
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition scip_var.c:10113
void SCIPvarSetData(SCIP_VAR *var, SCIP_VARDATA *vardata)
Definition var.c:23329
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition scip_var.c:184
SCIP_VAR * SCIPvarGetTransVar(SCIP_VAR *var)
Definition var.c:23704
SCIP_RETCODE SCIPchgVarObj(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
Definition scip_var.c:5372
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1853
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
return SCIP_OKAY
SCIPfreeSol(scip, &heurdata->sol))
SCIPcreateSol(scip, &heurdata->sol, heur))
SCIP_Bool lperror
SCIPendProbing(scip))
SCIP_Bool cutoff
SCIP_Real objval
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_VAR ** vars
internal methods for LP management
static const char * paramname[]
Definition lpi_msk.c:5172
#define BMSfreeMemory(ptr)
Definition memory.h:145
#define BMSreallocMemoryArray(ptr, num)
Definition memory.h:127
#define BMSduplicateMemoryArray(ptr, source, num)
Definition memory.h:143
#define BMSclearMemory(ptr)
Definition memory.h:129
#define BMSallocMemoryArray(ptr, num)
Definition memory.h:123
#define BMSfreeMemoryArray(ptr)
Definition memory.h:147
#define BMSallocBlockMemoryArray(mem, ptr, num)
Definition memory.h:454
#define BMSfreeBlockMemoryArray(mem, ptr, num)
Definition memory.h:467
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition memory.h:458
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
#define BMSallocClearMemoryArray(ptr, num)
Definition memory.h:125
struct BMS_BlkMem BMS_BLKMEM
Definition memory.h:437
#define BMSfreeMemoryArrayNull(ptr)
Definition memory.h:148
#define BMSallocMemory(ptr)
Definition memory.h:118
void SCIPmessagePrintVerbInfo(SCIP_MESSAGEHDLR *messagehdlr, SCIP_VERBLEVEL verblevel, SCIP_VERBLEVEL msgverblevel, const char *formatstr,...)
Definition message.c:678
SCIP_Real SCIPconsGetLhs(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
SCIP_RETCODE SCIPconsAddCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_Real SCIPconsGetRhs(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
Definition misc_linear.c:48
SCIP_PARAMDATA * SCIPparamGetData(SCIP_PARAM *param)
Definition paramset.c:676
int SCIPparamGetInt(SCIP_PARAM *param)
Definition paramset.c:731
SCIP_Real SCIPparamGetRealMax(SCIP_PARAM *param)
Definition paramset.c:850
internal methods for handling parameter settings
internal methods for storing priced variables
internal methods for storing and manipulating the main problem
public methods for Benders' decomposition
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebugMessage
Definition pub_message.h:96
public data structures and miscellaneous methods
SCIP callable library.
default SCIP plugins
SCIP_RETCODE SCIPsetAddIntParam(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, 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 set.c:3235
SCIP_Bool SCIPsetGetSubscipsOff(SCIP_SET *set)
Definition set.c:7709
SCIP_RETCODE SCIPsetAddCharParam(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition set.c:3307
SCIP_Real SCIPsetCeil(SCIP_SET *set, SCIP_Real val)
Definition set.c:6734
SCIP_RETCODE SCIPsetAddBoolParam(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition set.c:3213
SCIP_Bool SCIPsetIsLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition set.c:6583
SCIP_RETCODE SCIPsetAddRealParam(SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, 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 set.c:3283
SCIP_BENDERS * SCIPsetFindBenders(SCIP_SET *set, const char *name)
Definition set.c:4061
SCIP_STAGE SCIPsetGetStage(SCIP_SET *set)
Definition set.c:3203
SCIP_Real SCIPsetInfinity(SCIP_SET *set)
Definition set.c:6386
SCIP_Bool SCIPsetIsInfinity(SCIP_SET *set, SCIP_Real val)
Definition set.c:6521
SCIP_RETCODE SCIPsetGetRealParam(SCIP_SET *set, const char *name, SCIP_Real *value)
Definition set.c:3416
SCIP_Bool SCIPsetIsGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition set.c:6603
SCIP_EVENTHDLR * SCIPsetFindEventhdlr(SCIP_SET *set, const char *name)
Definition set.c:5017
int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
Definition set.c:6086
internal methods for global SCIP settings
#define SCIPsetDebugMsg
Definition set.h:1811
SCIP_RETCODE SCIPbendersGetVar(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_VAR *var, SCIP_VAR **mappedvar, int probnumber)
Definition benders.c:5784
void SCIPbendersSetInitsol(SCIP_BENDERS *benders,)
Definition benders.c:5897
static void createSolveSubproblemIndexList(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSENFOTYPE type, int **solveidx, int *nsolveidx)
Definition benders.c:3355
#define SCIP_DEFAULT_LNSMAXCALLSROOT
Definition benders.c:61
#define AUXILIARYVAR_NAME
Definition benders.c:84
#define SCIP_DEFAULT_STRENGTHENPERTURB
Definition benders.c:68
SCIP_Bool SCIPbendersSubproblemIsOptimal(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber)
Definition benders.c:5389
#define NODESOLVED_EVENTHDLR_NAME
Definition benders.c:98
#define SCIP_DEFAULT_LNSMAXDEPTH
Definition benders.c:59
void SCIPbendersSetObjectiveType(SCIP_BENDERS *benders, SCIP_BENDERSOBJTYPE objectivetype)
Definition benders.c:6860
SCIP_RETCODE SCIPbendersActivate(SCIP_BENDERS *benders, SCIP_SET *set, int nsubproblems)
Definition benders.c:2808
SCIP_RETCODE SCIPbendersComputeSubproblemLowerbound(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber, SCIP_Real *lowerbound, SCIP_Bool *infeasible)
Definition benders.c:5439
void SCIPbendersSetCopy(SCIP_BENDERS *benders,)
Definition benders.c:5831
void SCIPbendersRemoveSubproblems(SCIP_BENDERS *benders)
Definition benders.c:6209
static SCIP_RETCODE executeUserDefinedSolvesub(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_BENDERSSOLVELOOP solveloop, SCIP_Bool *infeasible, SCIP_Real *objective, SCIP_RESULT *result)
Definition benders.c:4419
static SCIP_RETCODE initsolEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTTYPE eventtype)
Definition benders.c:134
static SCIP_RETCODE storeSubproblemMasterVars(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
Definition benders.c:1517
static SCIP_RETCODE performInteriorSolCutStrengthening(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, SCIP_BENDERSENFOTYPE type, SCIP_Bool checkint, SCIP_Bool perturbsol, SCIP_Bool *auxviol, SCIP_Bool *infeasible, SCIP_Bool *skipsolve, SCIP_RESULT *result)
Definition benders.c:3160
#define SCIP_DEFAULT_STRENGTHENENABLED
Definition benders.c:69
#define SCIP_DEFAULT_UPDATEAUXVARBOUND
Definition benders.c:63
#define SCIP_DEFAULT_LNSMAXCALLS
Definition benders.c:60
#define SCIP_DEFAULT_SLACKVARCOEF
Definition benders.c:75
SCIP_RETCODE SCIPbendersFreeSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
Definition benders.c:5339
#define SCIP_DEFAULT_LNSCHECK
Definition benders.c:58
#define BENDERS_MAXPSEUDOSOLS
Definition benders.c:80
void SCIPbendersSetPriority(SCIP_BENDERS *benders, SCIP_SET *set, int priority)
Definition benders.c:6015
static SCIP_Bool subproblemIsActive(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:3344
static SCIP_RETCODE addSlackVars(SCIP *scip, SCIP_BENDERS *benders, SCIP_CONS *cons, SCIP_CONSHDLR **linearconshdlrs, SCIP_CONSHDLR *nlconshdlr, int nlinearconshdlrs)
Definition benders.c:1555
SCIP_RETCODE SCIPbendersExit(SCIP_BENDERS *benders, SCIP_SET *set)
Definition benders.c:2469
SCIP_RETCODE SCIPbendersChgMastervarsToCont(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
Definition benders.c:6606
#define SCIP_DEFAULT_NLPITERLIMIT
Definition benders.c:78
void SCIPbendersSortBenderscuts(SCIP_BENDERS *benders)
Definition benders.c:7162
SCIP_RETCODE SCIPbendersSetupSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_BENDERSENFOTYPE type)
Definition benders.c:4659
static SCIP_RETCODE setAndUpdateCorePoint(SCIP *scip, SCIP_BENDERS *benders)
Definition benders.c:3074
#define SCIP_DEFAULT_STRENGTHENMULT
Definition benders.c:66
static SCIP_RETCODE createSubproblems(SCIP_BENDERS *benders, SCIP_SET *set)
Definition benders.c:2018
SCIP_RETCODE SCIPbendersSetMastervarsCont(SCIP_BENDERS *benders, int probnumber, SCIP_Bool arecont)
Definition benders.c:6811
static SCIP_RETCODE freeEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr)
Definition benders.c:198
#define SCIP_DEFAULT_STRENGTHENINTPOINT
Definition benders.c:70
void SCIPbendersSetSubproblemsAreInfeasible(SCIP_BENDERS *benders, SCIP_SET *set)
Definition benders.c:6580
void SCIPbendersSortBenderscutsName(SCIP_BENDERS *benders)
Definition benders.c:7177
static SCIP_RETCODE resetOrigSubproblemParams(SCIP *subproblem, SCIP_SUBPROBPARAMS *origparams)
Definition benders.c:5039
#define SCIP_DEFAULT_CHECKCONSCONVEXITY
Definition benders.c:77
SCIP_RETCODE SCIPbendersCreate(SCIP_BENDERS **benders, SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, const char *name, const char *desc, int priority, SCIP_Bool cutlp, SCIP_Bool cutpseudo, SCIP_Bool cutrelax, SCIP_Bool shareauxvars, SCIP_DECL_BENDERSCOPY((*benderscopy)), SCIP_DECL_BENDERSFREE((*bendersfree)), SCIP_DECL_BENDERSINIT((*bendersinit)), SCIP_DECL_BENDERSEXIT((*bendersexit)), SCIP_DECL_BENDERSINITPRE((*bendersinitpre)), SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)), SCIP_DECL_BENDERSINITSOL((*bendersinitsol)), SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)), SCIP_DECL_BENDERSGETVAR((*bendersgetvar)), SCIP_DECL_BENDERSCREATESUB((*benderscreatesub)), SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)), SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)), SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)), SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)), SCIP_DECL_BENDERSFREESUB((*bendersfreesub)), SCIP_BENDERSDATA *bendersdata)
Definition benders.c:1356
static SCIP_RETCODE addSlackVarsToConstraints(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
Definition benders.c:1667
static SCIP_RETCODE updateAuxiliaryVarLowerbound(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_RESULT *result)
Definition benders.c:3017
#define SCIP_DEFAULT_MAXSLACKVARCOEF
Definition benders.c:76
static SCIP_RETCODE exitEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr)
Definition benders.c:178
static SCIP_RETCODE solveBendersSubproblems(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, SCIP_BENDERSENFOTYPE type, SCIP_BENDERSSOLVELOOP solveloop, SCIP_Bool checkint, int *nverified, int *solveidx, int nsolveidx, SCIP_Bool **subprobsolved, SCIP_BENDERSSUBSTATUS **substatus, SCIP_Bool *infeasible, SCIP_Bool *optimal, SCIP_Bool *stopped)
Definition benders.c:3444
static SCIP_RETCODE storeSubproblemMasterVar(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_VAR *var, int probnumber)
Definition benders.c:1479
SCIP_RETCODE SCIPbendersCopyInclude(SCIP_BENDERS *benders, SCIP_SET *sourceset, SCIP_SET *targetset, SCIP_HASHMAP *varmap, SCIP_Bool threadsafe, SCIP_Bool *valid)
Definition benders.c:1073
void SCIPbendersSetFreesub(SCIP_BENDERS *benders,)
Definition benders.c:5974
static SCIP_RETCODE createAndAddTransferredCut(SCIP *sourcescip, SCIP_BENDERS *benders, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, int nvars)
Definition benders.c:2305
SCIP_RETCODE SCIPbendersMergeSubproblemIntoMaster(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, int probnumber)
Definition benders.c:5601
#define BENDERS_MASTERVARARRAYSIZE
Definition benders.c:81
static SCIP_RETCODE doBendersCreate(SCIP_BENDERS **benders, SCIP_SET *set, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, const char *name, const char *desc, int priority, SCIP_Bool cutlp, SCIP_Bool cutpseudo, SCIP_Bool cutrelax, SCIP_Bool shareauxvars, SCIP_DECL_BENDERSCOPY((*benderscopy)), SCIP_DECL_BENDERSFREE((*bendersfree)), SCIP_DECL_BENDERSINIT((*bendersinit)), SCIP_DECL_BENDERSEXIT((*bendersexit)), SCIP_DECL_BENDERSINITPRE((*bendersinitpre)), SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)), SCIP_DECL_BENDERSINITSOL((*bendersinitsol)), SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)), SCIP_DECL_BENDERSGETVAR((*bendersgetvar)), SCIP_DECL_BENDERSCREATESUB((*benderscreatesub)), SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)), SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)), SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)), SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)), SCIP_DECL_BENDERSFREESUB((*bendersfreesub)), SCIP_BENDERSDATA *bendersdata)
Definition benders.c:1144
#define UPPERBOUND_EVENTHDLR_DESC
Definition benders.c:96
static SCIP_RETCODE initialiseSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber, SCIP_Bool *infeasible, SCIP_Bool *success)
Definition benders.c:1717
void SCIPbendersSetExitsol(SCIP_BENDERS *benders,)
Definition benders.c:5908
#define SCIP_DEFAULT_AUXVARSIMPLINT
Definition benders.c:64
static SCIP_RETCODE copyMemoryAndTimeLimits(SCIP *scip, SCIP *subproblem)
Definition benders.c:4928
static SCIP_RETCODE transferBendersCuts(SCIP *sourcescip, SCIP *subscip, SCIP_BENDERS *benders)
Definition benders.c:2423
void SCIPbendersSetBenderscutsSorted(SCIP_BENDERS *benders, SCIP_Bool sorted)
Definition benders.c:7061
#define UPPERBOUND_EVENTHDLR_NAME
Definition benders.c:95
static SCIP_RETCODE assignAuxiliaryVariables(SCIP *scip, SCIP_BENDERS *benders)
Definition benders.c:908
#define NODEFOCUS_EVENTHDLR_DESC
Definition benders.c:90
void SCIPbendersSetExitpre(SCIP_BENDERS *benders,)
Definition benders.c:5886
SCIP_RETCODE SCIPbendersFree(SCIP_BENDERS **benders, SCIP_SET *set)
Definition benders.c:1435
void SCIPbendersSetSolvesub(SCIP_BENDERS *benders,)
Definition benders.c:5941
#define SLACKVAR_NAME
Definition benders.c:85
SCIP_RETCODE SCIPbendersInitsol(SCIP_BENDERS *benders, SCIP_SET *set)
Definition benders.c:2719
SCIP_RETCODE SCIPbendersExecSubproblemSolve(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_BENDERSSOLVELOOP solveloop, SCIP_Bool enhancement, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_BENDERSENFOTYPE type)
Definition benders.c:4490
#define MIPNODEFOCUS_EVENTHDLR_DESC
Definition benders.c:93
static SCIP_RETCODE releaseVarMappingHashmapVars(SCIP *scip, SCIP_BENDERS *benders)
Definition benders.c:1401
static SCIP_RETCODE addAuxiliaryVariablesToMaster(SCIP *scip, SCIP_BENDERS *benders)
Definition benders.c:691
void SCIPbendersSetPostsolve(SCIP_BENDERS *benders,)
Definition benders.c:5952
#define SCIP_DEFAULT_NOIMPROVELIMIT
Definition benders.c:67
static SCIP_RETCODE setSubproblemParams(SCIP *scip, SCIP *subproblem)
Definition benders.c:4988
#define NLINEARCONSHDLRS
Definition benders.c:86
SCIP_RETCODE SCIPbendersDeactivate(SCIP_BENDERS *benders, SCIP_SET *set)
Definition benders.c:2908
void SCIPbendersSetSubproblemComp(SCIP_BENDERS *benders,)
Definition benders.c:5963
SCIP_RETCODE SCIPbendersStoreCut(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, int nvars)
Definition benders.c:7013
SCIP_RETCODE SCIPbendersAddSubproblem(SCIP_BENDERS *benders, SCIP *subproblem)
Definition benders.c:6185
#define SCIP_DEFAULT_TRANSFERCUTS
Definition benders.c:56
void SCIPbendersSetPresubsolve(SCIP_BENDERS *benders,)
Definition benders.c:5919
SCIP_Real SCIPbendersGetAuxiliaryVarVal(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber)
Definition benders.c:5418
SCIP_RETCODE SCIPbendersExec(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool *infeasible, SCIP_Bool *auxviol, SCIP_BENDERSENFOTYPE type, SCIP_Bool checkint)
Definition benders.c:3882
SCIP_Bool SCIPbendersGetMastervarsCont(SCIP_BENDERS *benders, int probnumber)
Definition benders.c:6846
static SCIP_RETCODE exitsolEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTTYPE eventtype)
Definition benders.c:154
static SCIP_RETCODE updateEventhdlrUpperbound(SCIP_BENDERS *benders, int probnumber, SCIP_Real upperbound)
Definition benders.c:472
static SCIP_RETCODE storeOrigSubproblemParams(SCIP *subproblem, SCIP_SUBPROBPARAMS *origparams)
Definition benders.c:4961
#define MIPNODEFOCUS_EVENTHDLR_NAME
Definition benders.c:92
#define SCIP_DEFAULT_SUBPROBFRAC
Definition benders.c:62
void SCIPbendersSetExit(SCIP_BENDERS *benders,)
Definition benders.c:5864
#define SCIP_DEFAULT_EXECFEASPHASE
Definition benders.c:74
void SCIPbendersSetInitpre(SCIP_BENDERS *benders,)
Definition benders.c:5875
#define NODEFOCUS_EVENTHDLR_NAME
Definition benders.c:89
SCIP_RETCODE SCIPbendersInitpre(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_STAT *stat)
Definition benders.c:2635
void SCIPbendersEnableOrDisableClocks(SCIP_BENDERS *benders, SCIP_Bool enable)
Definition benders.c:6121
static void findAuxiliaryVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR **targetvar, int subscipdepth, int probnumber)
Definition benders.c:858
static SCIP_RETCODE updateSubproblemStatQueue(SCIP_BENDERS *benders, int *solveidx, int nsolveidx, SCIP_Bool updatestat)
Definition benders.c:3395
static SCIP_RETCODE checkSubproblemConvexity(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
Definition benders.c:1810
static SCIP_RETCODE updateSubproblemLowerbound(SCIP *masterprob, SCIP_BENDERS *benders)
Definition benders.c:501
static SCIP_RETCODE generateBendersCuts(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_BENDERSENFOTYPE type, SCIP_BENDERSSOLVELOOP solveloop, SCIP_Bool checkint, SCIP_Bool *subprobsolved, SCIP_BENDERSSUBSTATUS *substatus, int *solveidx, int nsolveidx, int *mergecands, int *npriomergecands, int *nmergecands, int *nsolveloops)
Definition benders.c:3684
#define SCIP_DEFAULT_CUTCHECK
Definition benders.c:65
#define SCIP_DEFAULT_CUTSASCONSS
Definition benders.c:57
static SCIP_RETCODE initEventhandlerData(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition benders.c:116
void SCIPbendersSetSubproblemEnabled(SCIP_BENDERS *benders, int probnumber, SCIP_Bool enabled)
Definition benders.c:6773
void SCIPbendersSetSolvesubconvex(SCIP_BENDERS *benders,)
Definition benders.c:5930
SCIP_RETCODE SCIPbendersIncludeBenderscut(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSCUT *benderscut)
Definition benders.c:7073
SCIP_RETCODE SCIPbendersExitpre(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_STAT *stat)
Definition benders.c:2693
static int numSubproblemsToCheck(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSENFOTYPE type)
Definition benders.c:3329
SCIP_RETCODE SCIPbendersExitsol(SCIP_BENDERS *benders, SCIP_SET *set)
Definition benders.c:2752
SCIP_RETCODE SCIPbendersSolveSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_Bool *infeasible, SCIP_Bool solvecip, SCIP_Real *objective)
Definition benders.c:4819
static void resetSubproblemObjectiveValue(SCIP_BENDERS *benders, SCIP_SET *set)
Definition benders.c:978
#define BENDERS_ARRAYSIZE
Definition benders.c:82
static SCIP_RETCODE initialiseLPSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber, SCIP_Bool *infeasible)
Definition benders.c:1760
static SCIP_RETCODE createMasterVarMapping(SCIP_BENDERS *benders, SCIP_SET *sourceset, SCIP_HASHMAP *varmap)
Definition benders.c:1033
#define NODESOLVED_EVENTHDLR_DESC
Definition benders.c:99
void SCIPbendersSetInit(SCIP_BENDERS *benders,)
Definition benders.c:5853
static SCIP_RETCODE checkSubproblemIndependence(SCIP *scip, SCIP_BENDERS *benders)
Definition benders.c:2581
void SCIPbendersSetFree(SCIP_BENDERS *benders,)
Definition benders.c:5842
SCIP_RETCODE SCIPbendersInit(SCIP_BENDERS *benders, SCIP_SET *set)
Definition benders.c:2225
internal methods for Benders' decomposition
int * submastervarssize
SCIP_Bool subprobsinfeasible
SCIP_NLPPARAM nlpparam
SCIP_Bool * subprobisconvex
SCIP ** subproblems
SCIP_Bool * subprobenabled
SCIP_Bool transfercuts
SCIP_BENDERSDATA * bendersdata
SCIP_Bool threadsafe
SCIP_SUBPROBLEMSOLVESTAT ** solvestat
SCIP_Real slackvarcoef
SCIP_Bool cutlp
SCIP_Bool lnscheck
SCIP_BENDERSOBJTYPE objectivetype
SCIP_Bool strengthenround
SCIP_Bool cutpseudo
SCIP_Bool freesubprobs
SCIP_CONS ** auxiliaryvarcons
SCIP_Bool * mastervarscont
SCIP_VAR ** auxiliaryvars
SCIP_Real prevlowerbound
SCIP_Bool * subprobsetup
SCIP_Real * subprobobjval
SCIP_Bool active
SCIP_HASHMAP * mastervarsmap
SCIP_Real perturbeps
SCIP_PQUEUE * subprobqueue
SCIP_VAR *** submastervars
SCIP_Bool execfeasphase
SCIP_Real * bestsubprobobjval
SCIP_Bool benderscutssorted
SCIP_Real maxslackvarcoef
SCIP_Bool initialized
SCIP_Bool cutsasconss
SCIP_BENDERSSUBTYPE * subprobtype
SCIP_Real convexmult
SCIP_Bool shareauxvars
SCIP_Longint prevnlpiter
SCIP_Bool * subprobisnonlinear
SCIP_Bool * indepsubprob
SCIP_Bool cutcheck
SCIP_Bool strengthenenabled
SCIP_Bool iscopy
SCIP_Bool benderscutsnamessorted
SCIP_Bool masterisnonlinear
SCIP_BENDERSCUTCUT ** storedcuts
SCIP_Real subprobfrac
SCIP_Bool feasibilityphase
SCIP_BENDERSCUT ** benderscuts
SCIP_CLOCK * setuptime
SCIP_CLOCK * bendersclock
SCIP_Bool cutrelax
SCIP_Bool subprobscreated
SCIP_Bool updateauxvarbound
SCIP_SOL * corepoint
SCIP_Bool checkconsconvexity
int * nsubmasterbinvars
SCIP_SOL * initcorepoint
SCIP_NODE * prevnode
SCIP_Bool auxvarsimplint
SCIP_Real solutiontol
int * nsubmasterintvars
SCIP_VAR * masterauxvar
SCIP_Real * subproblowerbound
SCIP * scip
Definition struct_set.h:77
SCIP_Bool benders_copybenders
Definition struct_set.h:513
data structures required for Benders' decomposition
struct SCIP_SubproblemParams SCIP_SUBPROBPARAMS
struct SCIP_BenderscutCut SCIP_BENDERSCUTCUT
datastructures for Benders' decomposition cuts techniques
#define SCIP_DECL_BENDERSFREESUB(x)
#define SCIP_DECL_BENDERSCREATESUB(x)
struct SCIP_Benders SCIP_BENDERS
#define SCIP_DECL_BENDERSCOPY(x)
@ SCIP_BENDERSENFOTYPE_LP
@ SCIP_BENDERSENFOTYPE_CHECK
@ SCIP_BENDERSENFOTYPE_PSEUDO
#define SCIP_DECL_BENDERSSOLVESUB(x)
enum SCIP_BendersObjectiveType SCIP_BENDERSOBJTYPE
#define SCIP_DECL_BENDERSEXITPRE(x)
@ SCIP_BENDERSSUBSTATUS_AUXVIOL
@ SCIP_BENDERSSUBSTATUS_UNKNOWN
@ SCIP_BENDERSSUBSTATUS_INFEAS
@ SCIP_BENDERSSUBSTATUS_OPTIMAL
#define SCIP_DECL_BENDERSSOLVESUBCONVEX(x)
#define SCIP_DECL_BENDERSINIT(x)
#define SCIP_DECL_BENDERSFREE(x)
#define SCIP_DECL_BENDERSEXITSOL(x)
@ SCIP_BENDERSOBJTYPE_SUM
@ SCIP_BENDERSOBJTYPE_MAX
#define SCIP_DECL_BENDERSPRESUBSOLVE(x)
struct SCIP_SubproblemSolveStat SCIP_SUBPROBLEMSOLVESTAT
@ SCIP_BENDERSSUBTYPE_NONCONVEXDIS
@ SCIP_BENDERSSUBTYPE_CONVEXCONT
@ SCIP_BENDERSSUBTYPE_NONCONVEXCONT
@ SCIP_BENDERSSUBTYPE_CONVEXDIS
@ SCIP_BENDERSSUBTYPE_UNKNOWN
enum SCIP_BendersSubType SCIP_BENDERSSUBTYPE
@ SCIP_BENDERSSOLVELOOP_CIP
@ SCIP_BENDERSSOLVELOOP_CONVEX
@ SCIP_BENDERSSOLVELOOP_USERCONVEX
@ SCIP_BENDERSSOLVELOOP_USERCIP
enum SCIP_BendersSolveLoop SCIP_BENDERSSOLVELOOP
enum SCIP_BendersEnfoType SCIP_BENDERSENFOTYPE
#define SCIP_DECL_BENDERSGETVAR(x)
enum SCIP_BendersSubStatus SCIP_BENDERSSUBSTATUS
#define SCIP_DECL_BENDERSPOSTSOLVE(x)
#define SCIP_DECL_BENDERSINITPRE(x)
#define SCIP_DECL_BENDERSEXIT(x)
#define SCIP_DECL_BENDERSINITSOL(x)
struct SCIP_BendersData SCIP_BENDERSDATA
struct SCIP_Benderscut SCIP_BENDERSCUT
@ SCIP_CLOCKTYPE_DEFAULT
Definition type_clock.h:43
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
struct SCIP_Eventhdlr SCIP_EVENTHDLR
Definition type_event.h:159
#define SCIP_DECL_EVENTINITSOL(x)
Definition type_event.h:224
#define SCIP_DECL_EVENTEXIT(x)
Definition type_event.h:213
#define SCIP_EVENTTYPE_NODEFOCUSED
Definition type_event.h:93
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition type_event.h:160
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:259
#define SCIP_EVENTTYPE_NODESOLVED
Definition type_event.h:138
#define SCIP_EVENTTYPE_BESTSOLFOUND
Definition type_event.h:106
#define SCIP_DECL_EVENTFREE(x)
Definition type_event.h:197
uint64_t SCIP_EVENTTYPE
Definition type_event.h:156
#define SCIP_DECL_EVENTEXITSOL(x)
Definition type_event.h:235
SCIP_EXPRCURV
Definition type_expr.h:61
@ SCIP_EXPRCURV_CONVEX
Definition type_expr.h:63
@ SCIP_EXPRCURV_CONCAVE
Definition type_expr.h:64
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_LPSOLSTAT_ERROR
Definition type_lp.h:50
@ SCIP_LPSOLSTAT_NOTSOLVED
Definition type_lp.h:43
@ SCIP_LPSOLSTAT_OPTIMAL
Definition type_lp.h:44
@ SCIP_LPSOLSTAT_TIMELIMIT
Definition type_lp.h:49
@ SCIP_LPSOLSTAT_UNBOUNDEDRAY
Definition type_lp.h:46
@ SCIP_LPSOLSTAT_INFEASIBLE
Definition type_lp.h:45
@ SCIP_LPSOLSTAT_OBJLIMIT
Definition type_lp.h:47
@ SCIP_LPSOLSTAT_ITERLIMIT
Definition type_lp.h:48
struct SCIP_Messagehdlr SCIP_MESSAGEHDLR
@ SCIP_VERBLEVEL_NONE
@ SCIP_VERBLEVEL_MINIMAL
@ SCIP_VERBLEVEL_HIGH
@ SCIP_VERBLEVEL_FULL
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:189
struct SCIP_HashMapEntry SCIP_HASHMAPENTRY
Definition type_misc.h:100
#define SCIP_NLPPARAM_DEFAULT(scip)
Definition type_nlpi.h:126
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition type_nlpi.h:168
@ SCIP_NLPTERMSTAT_OKAY
Definition type_nlpi.h:173
@ SCIP_NLPTERMSTAT_TIMELIMIT
Definition type_nlpi.h:174
@ SCIP_NLPTERMSTAT_ITERLIMIT
Definition type_nlpi.h:175
@ SCIP_NLPTERMSTAT_INTERRUPT
Definition type_nlpi.h:177
@ SCIP_NLPSOLSTAT_UNBOUNDED
Definition type_nlpi.h:165
@ SCIP_NLPSOLSTAT_GLOBINFEASIBLE
Definition type_nlpi.h:164
@ SCIP_NLPSOLSTAT_LOCINFEASIBLE
Definition type_nlpi.h:163
@ SCIP_NLPSOLSTAT_FEASIBLE
Definition type_nlpi.h:162
@ SCIP_NLPSOLSTAT_LOCOPT
Definition type_nlpi.h:161
@ SCIP_NLPSOLSTAT_GLOBOPT
Definition type_nlpi.h:160
struct SCIP_NlpParam SCIP_NLPPARAM
Definition type_nlpi.h:81
enum SCIP_NlpTermStat SCIP_NLPTERMSTAT
Definition type_nlpi.h:184
@ SCIP_PARAMSETTING_OFF
struct SCIP_ParamData SCIP_PARAMDATA
#define SCIP_DECL_PARAMCHGD(x)
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_CONSADDED
Definition type_result.h:52
@ SCIP_UNBOUNDED
Definition type_result.h:47
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SOLVELP
Definition type_result.h:55
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDRESULT
@ SCIP_INVALIDCALL
@ SCIP_ERROR
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Set SCIP_SET
Definition type_set.h:71
@ SCIP_STAGE_PROBLEM
Definition type_set.h:45
@ SCIP_STAGE_SOLVED
Definition type_set.h:54
@ SCIP_STAGE_TRANSFORMED
Definition type_set.h:47
@ SCIP_STAGE_INITSOLVE
Definition type_set.h:52
@ SCIP_STAGE_INIT
Definition type_set.h:44
@ SCIP_STAGE_SOLVING
Definition type_set.h:53
@ SCIP_STAGE_PRESOLVED
Definition type_set.h:51
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
@ SCIP_STATUS_OPTIMAL
Definition type_stat.h:43
@ SCIP_STATUS_BESTSOLLIMIT
Definition type_stat.h:60
@ SCIP_STATUS_UNBOUNDED
Definition type_stat.h:45
@ SCIP_STATUS_UNKNOWN
Definition type_stat.h:42
@ SCIP_STATUS_USERINTERRUPT
Definition type_stat.h:47
@ SCIP_STATUS_TIMELIMIT
Definition type_stat.h:54
@ SCIP_STATUS_INFEASIBLE
Definition type_stat.h:44
@ SCIP_STATUS_MEMLIMIT
Definition type_stat.h:55
enum SCIP_Status SCIP_STATUS
Definition type_stat.h:64
struct SCIP_Stat SCIP_STAT
Definition type_stat.h:66
struct SCIP_VarData SCIP_VARDATA
Definition type_var.h:167
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
enum SCIP_ImplintType SCIP_IMPLINTTYPE
Definition type_var.h:117
@ SCIP_IMPLINTTYPE_NONE
Definition type_var.h:90
@ SCIP_IMPLINTTYPE_WEAK
Definition type_var.h:91
@ SCIP_VARTYPE_INTEGER
Definition type_var.h:65
@ SCIP_VARTYPE_CONTINUOUS
Definition type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_VARSTATUS_FIXED
Definition type_var.h:54
@ SCIP_VARSTATUS_COLUMN
Definition type_var.h:53
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141