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