Scippy

SCIP

Solving Constraint Integer Programs

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-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file 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);
312 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
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);
336 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
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);
349 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
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);
362 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
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);
375 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), MIPNODEFOCUS_EVENTHDLR_NAME) == 0);
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;
500 SCIP_Bool lperror;
501 SCIP_Bool cutoff;
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 {
820 assert(benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM);
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;
1411 var = (SCIP_VAR*) SCIPhashmapEntryGetImage(entry);
1412
1413 SCIP_CALL( SCIPreleaseVar(scip, &var) );
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( BMSreallocBlockMemoryArray(SCIPblkmem(set->scip), &benders->submastervars[probnumber],
1485 benders->submastervarssize[probnumber], newsize) );
1486
1487 benders->submastervarssize[probnumber] = newsize;
1488 }
1489
1490 benders->submastervars[probnumber][benders->nsubmastervars[probnumber]] = var;
1491 benders->nsubmastervars[probnumber]++;
1492
1493 /* capturing the variable, so that it is not released before */
1494
1495 /* getting the variable type and updating the statistics */
1497 benders->nsubmasterbinvars[probnumber]++;
1498 else if( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER )
1499 benders->nsubmasterintvars[probnumber]++;
1500
1501 return SCIP_OKAY;
1502}
1504static
1506 SCIP_BENDERS* benders, /**< Benders' decomposition */
1507 SCIP_SET* set, /**< global SCIP settings */
1508 int probnumber /**< the subproblem number */
1509 )
1510{
1511 SCIP* subproblem;
1512 SCIP_VAR** vars;
1513 SCIP_VAR* mastervar;
1514 int nvars;
1515 int i;
1516
1517 assert(benders != NULL);
1518 assert(set != NULL);
1519 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
1520
1521 subproblem = SCIPbendersSubproblem(benders, probnumber);
1522
1523 /* getting the variables of the subproblem to store the master problem variables */
1524 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, NULL) );
1525
1526 for( i = 0; i < nvars; i++ )
1527 {
1528 /* retrieving the master problem variable */
1529 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
1530
1531 /* if mastervar is not NULL, then the subproblem variable has a corresponding master problem variable */
1532 if( mastervar != NULL )
1533 {
1534 SCIP_CALL( storeSubproblemMasterVar(benders, set, mastervar, probnumber) );
1535 }
1536 }
1537
1538 return SCIP_OKAY;
1539}
1540
1541/* adds a slack variable to the given constraint */
1542static
1544 SCIP* scip, /**< the SCIP data structure */
1545 SCIP_BENDERS* benders, /**< Benders' decomposition */
1546 SCIP_CONS* cons, /**< constraint to which the slack variable(s) is added to */
1547 SCIP_CONSHDLR** linearconshdlrs, /**< an array storing the linear constraint handlers */
1548 SCIP_CONSHDLR* nlconshdlr, /**< pointer to the nonlinear constraint handler */
1549 int nlinearconshdlrs /**< the number of linear constraint handlers */
1550 )
1551{
1552 SCIP_CONSHDLR* conshdlr;
1553 SCIP_VAR* var;
1554 SCIP_Real rhs;
1555 SCIP_Real lhs;
1556 SCIP_Real objcoef;
1557 int i;
1558 SCIP_Bool linearcons;
1559 SCIP_Bool success;
1560 char name[SCIP_MAXSTRLEN];
1561
1562 conshdlr = SCIPconsGetHdlr(cons);
1563
1564 /* assume that the constraint is not linear, then we check whether it is linear */
1565 linearcons = FALSE;
1566
1567 /* checking whether the constraint is a linear constraint. If so, we add a coefficient to the constraint */
1568 for( i = 0; i < nlinearconshdlrs; ++i )
1569 {
1570 if( conshdlr == linearconshdlrs[i] )
1571 {
1572 linearcons = TRUE;
1573 break;
1574 }
1575 }
1576
1577 if( !linearcons && conshdlr != nlconshdlr )
1578 {
1579 SCIPwarningMessage(scip, "The subproblem includes constraint <%s>. "
1580 "This is not supported and the slack variable will not be added to the constraint. Feasibility cuts may be invalid.\n",
1581 SCIPconshdlrGetName(conshdlr));
1582 }
1583
1584 if( linearcons )
1585 {
1586 rhs = SCIPconsGetRhs(scip, cons, &success);
1587 assert(success);
1588 lhs = SCIPconsGetLhs(scip, cons, &success);
1589 assert(success);
1590 }
1591 else
1592 {
1593 rhs = SCIPgetRhsNonlinear(cons);
1594 lhs = SCIPgetLhsNonlinear(cons);
1595 }
1596
1597 /* getting the objective coefficient for the slack variables */
1598 objcoef = benders->slackvarcoef;
1599
1600 /* if the right hand side is finite, then we need to add a slack variable with a negative coefficient */
1601 if( !SCIPisInfinity(scip, rhs) )
1602 {
1603 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%s_neg", SLACKVAR_NAME, SCIPconsGetName(cons) );
1604
1606
1607 /* adding the slack variable to the subproblem */
1608 SCIP_CALL( SCIPaddVar(scip, var) );
1609
1610 /* adds the slack variable to the constraint */
1611 if( linearcons )
1612 {
1613 SCIP_CALL( SCIPconsAddCoef(scip, cons, var, -1.0) );
1614 }
1615 else
1616 {
1617 SCIP_CALL( SCIPaddLinearVarNonlinear(scip, cons, var, -1.0) );
1618 }
1619
1620 /* releasing the variable */
1621 SCIP_CALL( SCIPreleaseVar(scip, &var) );
1622 }
1623
1624 /* if the left hand side if finite, then we need to add a slack variable with a positive coefficient */
1625 if( !SCIPisInfinity(scip, -lhs) )
1626 {
1627 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%s_pos", SLACKVAR_NAME, SCIPconsGetName(cons) );
1628
1630
1631 /* adding the slack variable to the subproblem */
1632 SCIP_CALL( SCIPaddVar(scip, var) );
1633
1634 /* adds the slack variable to the constraint */
1635 if( linearcons )
1636 {
1637 SCIP_CALL( SCIPconsAddCoef(scip, cons, var, 1.0) );
1638 }
1639 else
1640 {
1641 SCIP_CALL( SCIPaddLinearVarNonlinear(scip, cons, var, 1.0) );
1642 }
1643
1644 /* releasing the variable */
1645 SCIP_CALL( SCIPreleaseVar(scip, &var) );
1646 }
1647
1648 return SCIP_OKAY;
1649}
1650
1651/** adds the slack variables to each of the constraints for the generation of feasibility cuts for the given non-linear
1652 * subproblem
1654static
1656 SCIP_BENDERS* benders, /**< Benders' decomposition */
1657 SCIP_SET* set, /**< global SCIP settings */
1658 int probnumber /**< the subproblem number */
1659 )
1660{
1661 SCIP* subproblem;
1662 SCIP_CONSHDLR* linearconshdlrs[NLINEARCONSHDLRS];
1663 SCIP_CONSHDLR* nlconshdlr;
1664 SCIP_CONS* cons;
1665 int i;
1666
1667 assert(benders != NULL);
1668 assert(set != NULL);
1669 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
1670
1671 subproblem = SCIPbendersSubproblem(benders, probnumber);
1672
1673 /* get pointers to linear constraints handlers, so can avoid string comparisons */
1674 linearconshdlrs[0] = SCIPfindConshdlr(subproblem, "knapsack");
1675 linearconshdlrs[1] = SCIPfindConshdlr(subproblem, "linear");
1676 linearconshdlrs[2] = SCIPfindConshdlr(subproblem, "logicor");
1677 linearconshdlrs[3] = SCIPfindConshdlr(subproblem, "setppc");
1678 linearconshdlrs[4] = SCIPfindConshdlr(subproblem, "varbound");
1679
1680 nlconshdlr = SCIPfindConshdlr(subproblem, "nonlinear");
1681
1682 for( i = 0; i < SCIPgetNOrigConss(subproblem); ++i )
1683 {
1684 cons = SCIPgetOrigConss(subproblem)[i];
1685
1686 /* adding the slack variables to the constraint */
1687 SCIP_CALL( addSlackVars(subproblem, benders, cons, linearconshdlrs, nlconshdlr, NLINEARCONSHDLRS) );
1688 }
1689
1690 return SCIP_OKAY;
1691}
1692
1693/** initialises a MIP subproblem by putting the problem into SCIP_STAGE_SOLVING. This is achieved by calling SCIPsolve
1694 * and then interrupting the solve in a node focus event handler.
1695 * The LP subproblem is also initialised using this method; however, a different event handler is added. This event
1696 * handler will put the LP subproblem into probing mode.
1697 * The MIP solving function is called to initialise the subproblem because this function calls SCIPsolve with the
1698 * appropriate parameter settings for Benders' decomposition.
1700static
1702 SCIP_BENDERS* benders, /**< Benders' decomposition */
1703 SCIP_SET* set, /**< global SCIP settings */
1704 int probnumber, /**< the subproblem number */
1705 SCIP_Bool* infeasible, /**< pointer to store whether the lp is detected as infeasible */
1706 SCIP_Bool* success /**< was the initialisation process successful */
1707 )
1708{
1709 SCIP* subproblem;
1710 SCIP_STATUS solvestatus;
1711
1712 assert(benders != NULL);
1713 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
1714 assert(success != NULL);
1715
1716 (*success) = FALSE;
1717 (*infeasible) = FALSE;
1718
1719 subproblem = SCIPbendersSubproblem(benders, probnumber);
1720 assert(subproblem != NULL);
1721
1722 /* Getting the problem into the right SCIP stage for solving */
1723 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, FALSE) );
1724
1725 /* Constructing the LP that can be solved in later iterations */
1726 if( solvestatus != SCIP_STATUS_BESTSOLLIMIT && solvestatus != SCIP_STATUS_TIMELIMIT
1727 && solvestatus != SCIP_STATUS_MEMLIMIT )
1728 {
1729 assert(SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING);
1730
1731 SCIP_CALL( SCIPconstructLP(subproblem, infeasible) );
1732
1733 (*success) = !(*infeasible);
1734 }
1735
1736 return SCIP_OKAY;
1737}
1738
1739
1740/** initialises an LP subproblem by putting the problem into probing mode. The probing mode is invoked in a node focus
1741 * event handler. This event handler is added just prior to calling the initialise subproblem function.
1743static
1745 SCIP_BENDERS* benders, /**< Benders' decomposition */
1746 SCIP_SET* set, /**< global SCIP settings */
1747 int probnumber, /**< the subproblem number */
1748 SCIP_Bool* infeasible /**< pointer to store whether the lp is detected as infeasible */
1749 )
1750{
1751 SCIP* subproblem;
1752 SCIP_EVENTHDLR* eventhdlr;
1753 SCIP_EVENTHDLRDATA* eventhdlrdata;
1754 SCIP_Bool success;
1755
1756 assert(benders != NULL);
1757 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
1758 assert(infeasible != NULL);
1759
1760 subproblem = SCIPbendersSubproblem(benders, probnumber);
1761 assert(subproblem != NULL);
1762
1763 /* include event handler into SCIP */
1764 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata) );
1765
1766 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata) );
1767
1769 eventExecBendersNodefocus, eventhdlrdata) );
1770 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersNodefocus) );
1771 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersNodefocus) );
1772 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersNodefocus) );
1773 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersNodefocus) );
1774 assert(eventhdlr != NULL);
1775
1776 /* calling an initial solve to put the problem into probing mode */
1777 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, infeasible, &success) );
1778
1779 return SCIP_OKAY; /*lint !e438*/
1780}
1781
1782/** checks whether the convex relaxation of the subproblem is sufficient to solve the original problem to optimality
1783 *
1784 * We check whether we can conclude that the CIP is actually an LP or a convex NLP.
1785 * To do this, we check that all variables are of continuous type and that every constraint is either handled by known
1786 * linear constraint handler (knapsack, linear, logicor, setppc, varbound) or the nonlinear constraint handler.
1787 * In the latter case, we also check whether the nonlinear constraint is convex.
1788 * Further, nonlinear constraints are only considered if an NLP solver interface is available, i.e., and NLP could
1789 * be solved.
1790 * If constraints are present that cannot be identified as linear or convex nonlinear, then we assume that the
1791 * problem is not convex, thus solving its LP or NLP relaxation will not be sufficient.
1793static
1795 SCIP_BENDERS* benders, /**< Benders' decomposition */
1796 SCIP_SET* set, /**< global SCIP settings */
1797 int probnumber /**< the subproblem number, or -1 for the master problem */
1798 )
1799{
1800 SCIP* subproblem;
1801 SCIP_CONSHDLR* conshdlr;
1802 SCIP_CONS* cons;
1803 SCIP_HASHMAP* assumevarfixed;
1804 SCIP_VAR** vars;
1805 int nvars;
1806 int nbinvars;
1807 int nintvars;
1808 int nimplintvars;
1809 int i;
1810 int j;
1811 SCIP_Bool convexcons;
1812 SCIP_Bool discretevar;
1813 SCIP_Bool isnonlinear;
1814 SCIP_CONSHDLR* linearconshdlrs[NLINEARCONSHDLRS];
1815 SCIP_CONSHDLR* nlconshdlr = NULL;
1816
1817 assert(benders != NULL);
1818 assert(set != NULL);
1819 assert(probnumber >= -1 && probnumber < SCIPbendersGetNSubproblems(benders));
1820
1821 assumevarfixed = NULL;
1822 if( probnumber >= 0 )
1823 subproblem = SCIPbendersSubproblem(benders, probnumber);
1824 else
1825 subproblem = set->scip;
1826
1827 assert(subproblem != NULL);
1828
1829 convexcons = FALSE;
1830 discretevar = FALSE;
1831 isnonlinear = FALSE;
1832
1833 /* getting the number of integer and binary variables to determine the problem type */
1834 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, &nbinvars, &nintvars, &nimplintvars, NULL) );
1835
1836 /* if there are any binary, integer or implicit integer variables, then the subproblems is marked as non-convex */
1837 if( nbinvars != 0 || nintvars != 0 || nimplintvars != 0 )
1838 {
1839 discretevar = TRUE;
1840 }
1841
1842 /* get pointers to linear constraints handlers, so can avoid string comparisons */
1843 linearconshdlrs[0] = SCIPfindConshdlr(subproblem, "knapsack");
1844 linearconshdlrs[1] = SCIPfindConshdlr(subproblem, "linear");
1845 linearconshdlrs[2] = SCIPfindConshdlr(subproblem, "logicor");
1846 linearconshdlrs[3] = SCIPfindConshdlr(subproblem, "setppc");
1847 linearconshdlrs[4] = SCIPfindConshdlr(subproblem, "varbound");
1848
1849 /* Get pointer to the nonlinear constraint handler if we also have an NLP solver to solve NLPs.
1850 * If there is no NLP solver, but there are (convex) nonlinear constraints, then the LP relaxation of subproblems
1851 * will (currently) not be sufficient to solve subproblems to optimality. Thus, we also take the presence of convex
1852 * nonlinear constraints as signal for having to solve the CIP eventually, thus, by abuse of notation,
1853 * return not-convex here. In summary, we do not need to have a special look onto non-linear constraints
1854 * if no NLP solver is present, and can treat them as any other constraint that is not of linear type.
1855 */
1856 if( SCIPgetNNlpis(subproblem) > 0 )
1857 {
1858 nlconshdlr = SCIPfindConshdlr(subproblem, "nonlinear");
1859 }
1860
1861 /* if the nonlinear constraint handler exists, then we create a hashmap of variables that can be assumed to be fixed.
1862 * These variables correspond to the copies of the master variables in the subproblem
1863 */
1864 if( probnumber >= 0 && nlconshdlr != NULL )
1865 {
1866 SCIP_VAR* mappedvar;
1867
1868 SCIP_CALL( SCIPhashmapCreate(&assumevarfixed, SCIPblkmem(set->scip), SCIPgetNVars(subproblem)) );
1869
1870 /* finding the subproblem variables that correspond to master variables */
1871 for( i = 0; i < nvars; i++ )
1872 {
1873 /* getting the corresponding master problem variable for the given variable */
1874 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mappedvar, -1) );
1875
1876 /* if the mapped variable is not NULL, then it must be stored as a possible fixed variable */
1877 if( mappedvar != NULL )
1878 {
1879 SCIP_CALL( SCIPhashmapInsert(assumevarfixed, vars[i], vars[i]) );
1880 }
1881 }
1882 }
1883
1884 for( i = 0; i < SCIPgetNOrigConss(subproblem); ++i )
1885 {
1886 cons = SCIPgetOrigConss(subproblem)[i];
1887 conshdlr = SCIPconsGetHdlr(cons);
1888
1889 for( j = 0; j < NLINEARCONSHDLRS; ++j )
1890 if( conshdlr == linearconshdlrs[j] )
1891 break;
1892
1893 /* if linear constraint, then we are good */
1894 if( j < NLINEARCONSHDLRS )
1895 {
1896#ifdef SCIP_MOREDEBUG
1897 SCIPdebugMsg(subproblem, "subproblem <%s>: constraint <%s> is linear\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
1898#endif
1899 continue;
1900 }
1901
1902 /* if cons_nonlinear (and nlconshdlr != NULL), then check whether convex */
1903 if( conshdlr == nlconshdlr )
1904 {
1905 SCIP_Bool isconvex;
1906 SCIP_EXPRCURV curv;
1907 SCIP_Bool havelhs;
1908 SCIP_Bool haverhs;
1909
1910 isnonlinear = TRUE;
1911
1912 havelhs = !SCIPisInfinity(subproblem, -SCIPgetLhsNonlinear(cons));
1913 haverhs = !SCIPisInfinity(subproblem, SCIPgetRhsNonlinear(cons));
1914 if( havelhs && haverhs )
1915 {
1916 isconvex = FALSE;
1917 }
1918 else
1919 {
1920 /* look at curvature stored in cons, though at this stage this will be unknown a.a. */
1921 curv = SCIPgetCurvatureNonlinear(cons);
1922 isconvex = ((!havelhs || (curv & SCIP_EXPRCURV_CONCAVE) == SCIP_EXPRCURV_CONCAVE)) &&
1923 ((!haverhs || (curv & SCIP_EXPRCURV_CONVEX) == SCIP_EXPRCURV_CONVEX));
1924
1925 if( !isconvex )
1926 {
1927 /* if not found convex, compute curvature via nlhdlr_convex and decide again */
1928
1929 /* make sure activities are up to date. SCIPhasExprCurvature currently assumes that this is already the case */
1931
1932 SCIP_CALL( SCIPhasExprCurvature(subproblem, SCIPgetExprNonlinear(cons), havelhs ? SCIP_EXPRCURV_CONCAVE : SCIP_EXPRCURV_CONVEX, &isconvex, assumevarfixed) );
1933 }
1934 }
1935
1936 if( isconvex )
1937 {
1938#ifdef SCIP_MOREDEBUG
1939 SCIPdebugMsg(subproblem, "subproblem <%s>: nonlinear constraint <%s> is convex\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
1940#endif
1941 continue;
1942 }
1943 else
1944 {
1945#ifdef SCIP_MOREDEBUG
1946 SCIPdebugMsg(subproblem, "subproblem <%s>: nonlinear constraint <%s> not convex\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
1947#endif
1948 goto TERMINATE;
1949 }
1950 }
1951
1952#ifdef SCIP_MOREDEBUG
1953 SCIPdebugMsg(subproblem, "subproblem <%s>: potentially nonconvex constraint <%s>\n", SCIPgetProbName(subproblem), SCIPconsGetName(cons));
1954#endif
1955 goto TERMINATE;
1956 }
1957
1958 /* if we made it until here, then all constraints are known and convex */
1959 convexcons = TRUE;
1960
1961TERMINATE:
1962 /* setting the flag for the convexity of the subproblem. If convexity doesn't need to be checked, then it is assumed
1963 * that the subproblems are convex. However, if there are discrete variables, then the problem must be set as
1964 * non-convex. The discrete master variables will be changed to continuous, but this will happen at the first call to
1965 * SCIPbendersSetupSubproblem
1966 */
1967 if( probnumber >= 0 )
1968 {
1969 convexcons = convexcons || !benders->checkconsconvexity;
1970
1971 if( convexcons && !discretevar )
1973 else if( convexcons && discretevar )
1975 else if( !convexcons && !discretevar )
1977 else if( !convexcons && discretevar )
1979 else
1980 SCIPABORT();
1981
1982 /* setting the non-linear subproblem flag */
1983 SCIPbendersSetSubproblemIsNonlinear(benders, probnumber, isnonlinear);
1984
1985 SCIPsetDebugMsg(set, "subproblem <%s> has been found to be of type %d\n", SCIPgetProbName(subproblem),
1986 SCIPbendersGetSubproblemType(benders, probnumber));
1987 }
1988 else
1989 {
1990 SCIPbendersSetMasterIsNonlinear(benders, isnonlinear);
1991 }
1992
1993 /* releasing the fixed variable hashmap */
1994 if( assumevarfixed != NULL )
1995 SCIPhashmapFree(&assumevarfixed);
1996
1997 return SCIP_OKAY;
1998}
1999
2000/** creates the subproblems and registers it with the Benders' decomposition struct */
2001static
2003 SCIP_BENDERS* benders, /**< Benders' decomposition */
2004 SCIP_SET* set /**< global SCIP settings */
2005 )
2006{
2007 SCIP* subproblem;
2008 SCIP_EVENTHDLR* eventhdlr;
2009 SCIP_VAR* mastervar;
2010 SCIP_VAR** vars;
2011 int nvars;
2012 int nsubproblems;
2013 int i;
2014 int j;
2015
2016 assert(benders != NULL);
2017 assert(set != NULL);
2018
2019 /* if the subproblems have already been created, then they will not be created again. This is the case if the
2020 * transformed problem has been freed and then retransformed. The subproblems should only be created when the problem
2021 * is first transformed. */
2022 if( benders->subprobscreated )
2023 return SCIP_OKAY;
2024
2025 nsubproblems = SCIPbendersGetNSubproblems(benders);
2026
2027 /* creating all subproblems */
2028 for( i = 0; i < nsubproblems; i++ )
2029 {
2030 /* calling the create subproblem call back method */
2031 SCIP_CALL( benders->benderscreatesub(set->scip, benders, i) );
2032
2033 subproblem = SCIPbendersSubproblem(benders, i);
2034
2035 /* the subproblem SCIP instance could be set to NULL. This is because user defined subproblem solving methods
2036 * could be used that don't solve a SCIP instance. Thus, the following setup of the subproblem SCIP instance is
2037 * not required.
2038 *
2039 * NOTE: since the subproblems are supplied as NULL pointers, the internal convexity check can not be performed.
2040 * The user needs to explicitly specify the subproblem type.
2041 */
2042 if( subproblem != NULL )
2043 {
2044 /* stores the master problem variables that are in the subproblem. This is helpful for all instances where the
2045 * master problem variable needs to extracted from the subproblem
2046 */
2047 SCIP_CALL( storeSubproblemMasterVars(benders, set, i) );
2048
2049 /* setting global limits for the subproblems. This overwrites the limits set by the user */
2050 SCIP_CALL( SCIPsetIntParam(subproblem, "limits/maxorigsol", 0) );
2051
2052 /* getting the number of integer and binary variables to determine the problem type */
2053 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, NULL) );
2054
2055 /* The objective function coefficients of the master problem are set to zero. This is necessary for the Benders'
2056 * decomposition algorithm, since the cut methods and the objective function check assumes that the objective
2057 * coefficients of the master problem variables are zero.
2058 *
2059 * This only occurs if the Benders' decomposition is not a copy. It is assumed that the correct objective
2060 * coefficients are given during the first subproblem creation.
2061 *
2062 * If the subproblems were copied, then the master variables will be checked to ensure that they have a zero
2063 * objective value.
2064 */
2065 if( !benders->iscopy || benders->threadsafe )
2066 {
2067 SCIP_Bool objchanged = FALSE;
2068
2069 assert(SCIPgetStage(subproblem) == SCIP_STAGE_PROBLEM);
2070 for( j = 0; j < nvars; j++ )
2071 {
2072 /* retrieving the master problem variable */
2073 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[j], &mastervar, -1) );
2074
2075 /* if mastervar is not NULL, then the subproblem variable has a corresponding master problem variable */
2076 if( mastervar != NULL && SCIPvarGetObj(vars[j]) != 0.0 )
2077 {
2078 SCIPverbMessage(subproblem, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Changing the objective "
2079 "coefficient of copy of master problem variable <%s> in subproblem %d to zero.\n",
2080 SCIPvarGetName(mastervar), i);
2081 /* changing the subproblem variable objective coefficient to zero */
2082 SCIP_CALL( SCIPchgVarObj(subproblem, vars[j], 0.0) );
2083
2084 objchanged = TRUE;
2085 }
2086 }
2087
2088 if( objchanged )
2089 {
2090 SCIPverbMessage(subproblem, SCIP_VERBLEVEL_HIGH, NULL, "Benders' decomposition: Objective coefficients of "
2091 "copy of master problem variables in a subproblem have been changed to zero.\n");
2092 }
2093 }
2094
2095 /* changing all of the master problem variable to continuous. */
2097
2098 /* checking the convexity of the subproblem. The convexity of the subproblem indicates whether the convex
2099 * relaxation is a valid relaxation for the problem
2100 */
2101 SCIP_CALL( checkSubproblemConvexity(benders, set, i) );
2102
2103 /* if the problem is convex and has nonlinear constraints, then slack variables must be added to each of the
2104 * constraints
2105 */
2106 if( benders->execfeasphase ||
2108 && SCIPbendersSubproblemIsNonlinear(benders, i)) )
2109 {
2110 /* the slack variables are only added to the subproblem once. If the initialisation methods are called from a
2111 * copy, then the slack variables are not re-added. Alternatively, if the copy must be threadsafe, then the
2112 * subproblems are created from scratch again, so the slack variables need to be added.
2113 */
2114 if( !benders->iscopy || benders->threadsafe )
2115 {
2116 SCIP_CALL( addSlackVarsToConstraints(benders, set, i) );
2117 }
2118
2119 /* setting the flag to indicate that slack variables have been added to the subproblem constraints. This is only
2120 * set if the slack variables have been added at the request of the user.
2121 */
2122 if( benders->execfeasphase )
2123 benders->feasibilityphase = TRUE;
2124 }
2125
2126 /* after checking the subproblem for convexity, if the subproblem has convex constraints and continuous variables,
2127 * then the problem is entered into probing mode. Otherwise, it is initialised as a CIP
2128 */
2130 {
2131 /* if the user has not implemented a solve subproblem callback, then the subproblem solves are performed
2132 * internally. To be more efficient the subproblem is put into probing mode. */
2133 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
2134 && SCIPgetStage(subproblem) <= SCIP_STAGE_PROBLEM )
2135 {
2136 SCIP_Bool infeasible;
2137 SCIP_CALL( initialiseLPSubproblem(benders, set, i, &infeasible) );
2138
2139 /* if the initialisation process indicates that the LP is infeasible, then the complete problem is
2140 * infeasible. The subprobsinfeasible flag is set so that SCIP can be informed at the correct point
2141 * during the solving process.
2142 */
2143 if( infeasible )
2145 }
2146 }
2147 else
2148 {
2149 SCIP_EVENTHDLRDATA* eventhdlrdata_mipnodefocus;
2150 SCIP_EVENTHDLRDATA* eventhdlrdata_upperbound;
2151
2152 /* because the subproblems could be reused in the copy, the event handler is not created again. If the
2153 * threadsafe is TRUE, then it is assumed that the subproblems are not reused.
2154 * NOTE: This currently works with the benders_default implementation. It may not be very general. */
2155 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
2156 && (!benders->iscopy || benders->threadsafe) )
2157 {
2158 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata_mipnodefocus) );
2159 SCIP_CALL( SCIPallocBlockMemory(subproblem, &eventhdlrdata_upperbound) );
2160
2161 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata_mipnodefocus) );
2162 SCIP_CALL( initEventhandlerData(subproblem, eventhdlrdata_upperbound) );
2163
2164 /* include the first LP solved event handler into the subproblem */
2166 MIPNODEFOCUS_EVENTHDLR_DESC, eventExecBendersMipnodefocus, eventhdlrdata_mipnodefocus) );
2167 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersMipnodefocus) );
2168 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersMipnodefocus) );
2169 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersMipnodefocus) );
2170 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersMipnodefocus) );
2171 assert(eventhdlr != NULL);
2172
2173 /* include the upper bound interrupt event handler into the subproblem */
2175 UPPERBOUND_EVENTHDLR_DESC, eventExecBendersUpperbound, eventhdlrdata_upperbound) );
2176 SCIP_CALL( SCIPsetEventhdlrInitsol(subproblem, eventhdlr, eventInitsolBendersUpperbound) );
2177 SCIP_CALL( SCIPsetEventhdlrExitsol(subproblem, eventhdlr, eventExitsolBendersUpperbound) );
2178 SCIP_CALL( SCIPsetEventhdlrExit(subproblem, eventhdlr, eventExitBendersUpperbound) );
2179 SCIP_CALL( SCIPsetEventhdlrFree(subproblem, eventhdlr, eventFreeBendersUpperbound) );
2180 assert(eventhdlr != NULL);
2181 }
2182 }
2183 }
2184 else
2185 {
2186 /* a user must specify the subproblem type if they are not supplying a SCIP instance. */
2188 {
2189 SCIPerrorMessage("If the subproblem is set to NULL, then the subproblem type must be specified.\n");
2190 SCIPerrorMessage("In the subproblem creation callback, call SCIPbendersSetSubproblemType with the appropriate problem type.\n");
2191
2192 return SCIP_ERROR;
2193 }
2194 }
2195 }
2196
2197 /* checking the convexity of the master problem. This information is useful for the cut generation methods, such as
2198 * non-good and integer cuts
2199 */
2200 SCIP_CALL( checkSubproblemConvexity(benders, set, -1) );
2201
2202 benders->subprobscreated = TRUE;
2203
2204 return SCIP_OKAY;
2205}
2206
2208/** initializes Benders' decomposition */
2210 SCIP_BENDERS* benders, /**< Benders' decomposition */
2211 SCIP_SET* set /**< global SCIP settings */
2212 )
2213{
2214 int i;
2215
2216 assert(benders != NULL);
2217 assert(set != NULL);
2218
2219 if( benders->initialized )
2220 {
2221 SCIPerrorMessage("Benders' decomposition <%s> already initialized\n", benders->name);
2222 return SCIP_INVALIDCALL;
2223 }
2224
2225 if( set->misc_resetstat )
2226 {
2227 SCIPclockReset(benders->setuptime);
2228 SCIPclockReset(benders->bendersclock);
2229
2230 benders->ncalls = 0;
2231 benders->ncutsfound = 0;
2232 benders->ntransferred = 0;
2233 }
2234
2235 /* start timing */
2236 SCIPclockStart(benders->setuptime, set);
2237
2238 if( benders->bendersinit != NULL )
2239 {
2240 SCIP_CALL( benders->bendersinit(set->scip, benders) );
2241 }
2242
2243 benders->initialized = TRUE;
2244
2245 /* if the Benders' decomposition is a copy, then the auxiliary variables already exist. So they are registered with
2246 * the Benders' decomposition struct during the init stage. If the Benders' decomposition is not a copy, then the
2247 * auxiliary variables need to be created, which occurs in the initpre stage
2248 */
2249 if( benders->iscopy )
2250 {
2251 /* the copied auxiliary variables must be assigned to the target Benders' decomposition */
2252 SCIP_CALL( assignAuxiliaryVariables(set->scip, benders) );
2253 }
2254
2255 /* creates the subproblems and sets up the probing mode for LP subproblems. This function calls the benderscreatesub
2256 * callback. */
2257 SCIP_CALL( createSubproblems(benders, set) );
2258
2259 /* storing the solution tolerance set by the SCIP parameters */
2260 SCIP_CALL( SCIPsetGetRealParam(set, "benders/solutiontol", &benders->solutiontol) );
2261
2262 /* allocating memory for the stored constraints array */
2263 if( benders->storedcutssize == 0 )
2264 {
2267 benders->nstoredcuts = 0;
2268 }
2269
2270 /* initialising the Benders' cuts */
2272 for( i = 0; i < benders->nbenderscuts; i++ )
2273 {
2275 }
2276
2277 /* stop timing */
2278 SCIPclockStop(benders->setuptime, set);
2279
2280 return SCIP_OKAY;
2281}
2282
2283
2284/** Transfers Benders' cuts that were generated while solving a sub-SCIP to the original SCIP instance. This involves
2285 * creating a constraint/cut that is equivalent to the generated cut in the sub-SCIP. This new constraint/cut is then
2286 * added to the original SCIP instance.
2288static
2290 SCIP* sourcescip, /**< the source SCIP from when the Benders' decomposition was copied */
2291 SCIP_BENDERS* benders, /**< the Benders' decomposition structure of the sub SCIP */
2292 SCIP_VAR** vars, /**< the variables from the source constraint */
2293 SCIP_Real* vals, /**< the coefficients of the variables in the source constriant */
2294 SCIP_Real lhs, /**< the LHS of the source constraint */
2295 SCIP_Real rhs, /**< the RHS of the source constraint */
2296 int nvars /**< the number of variables in the source constraint */
2297 )
2298{
2299 SCIP_BENDERS* sourcebenders; /* the Benders' decomposition of the source SCIP */
2300 SCIP_CONSHDLR* consbenders; /* a helper variable for the Benders' decomposition constraint handler */
2301 SCIP_CONS* transfercons = NULL; /* the constraint that is generated to transfer the constraints/cuts */
2302 SCIP_ROW* transfercut = NULL; /* the cut that is generated to transfer the constraints/cuts */
2303 SCIP_VAR* sourcevar; /* the source variable that will be added to the transferred cut */
2304 SCIP_VAR* origvar;
2305 SCIP_Real scalar;
2306 SCIP_Real constant;
2307 char cutname[SCIP_MAXSTRLEN]; /* the name of the transferred cut */
2308 int i;
2309 SCIP_Bool fail;
2310
2311 assert(sourcescip != NULL);
2312 assert(benders != NULL);
2313 assert(vars != NULL);
2314 assert(vals != NULL);
2315
2316 /* retrieving the source Benders' decomposition structure */
2317 sourcebenders = SCIPfindBenders(sourcescip, SCIPbendersGetName(benders));
2318
2319 /* retrieving the Benders' decomposition constraint handler */
2320 consbenders = SCIPfindConshdlr(sourcescip, "benders");
2321
2322 /* setting the name of the transferred cut */
2323 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "transferredcut_%d",
2324 SCIPbendersGetNTransferredCuts(sourcebenders) );
2325
2326 /* TODO: It could be more efficient to pass an updated vars array with the vals array to the
2327 * SCIPcreateConsBasicLinear/SCIPcreateEmptyRowConshdlr. This should be implemented to improve the performance of the
2328 * Large Neighbourhood Benders Search.
2329 */
2330
2331 /* creating an empty row/constraint for the transferred cut */
2332 if( sourcebenders->cutsasconss )
2333 {
2334 SCIP_CALL( SCIPcreateConsBasicLinear(sourcescip, &transfercons, cutname, 0, NULL, NULL, lhs, rhs) );
2335 SCIP_CALL( SCIPsetConsRemovable(sourcescip, transfercons, TRUE) );
2336 }
2337 else
2338 {
2339 SCIP_CALL( SCIPcreateEmptyRowConshdlr(sourcescip, &transfercut, consbenders, cutname, lhs, rhs, FALSE,
2340 FALSE, TRUE) );
2341 }
2342
2343 fail = FALSE;
2344 for( i = 0; i < nvars; i++ )
2345 {
2346 /* getting the original variable for the transformed variable */
2347 origvar = vars[i];
2348 scalar = 1.0;
2349 constant = 0.0;
2350 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
2351
2352 /* getting the source var from the hash map */
2353 sourcevar = (SCIP_VAR*) SCIPhashmapGetImage(benders->mastervarsmap, origvar);
2354
2355 /* if the source variable is not found, then the mapping in incomplete. So the constraint can not be
2356 * transferred. */
2357 if( sourcevar == NULL )
2358 {
2359 fail = TRUE;
2360 break;
2361 }
2362
2363 if( sourcebenders->cutsasconss )
2364 {
2365 assert( transfercons != NULL );
2366 SCIP_CALL( SCIPaddCoefLinear(sourcescip, transfercons, sourcevar, vals[i]) ); /*lint !e644*/
2367 }
2368 else
2369 {
2370 assert( transfercut != NULL );
2371 SCIP_CALL( SCIPaddVarToRow(sourcescip, transfercut, sourcevar, vals[i]) ); /*lint !e644*/
2372 }
2373 }
2374
2375 /* if all of the source variables were found to generate the cut */
2376 if( !fail )
2377 {
2378 if( sourcebenders->cutsasconss )
2379 {
2380 SCIP_CALL( SCIPaddCons(sourcescip, transfercons) );
2381 }
2382 else
2383 {
2384 SCIP_CALL( SCIPaddPoolCut(sourcescip, transfercut) );
2385 }
2386
2387 sourcebenders->ntransferred++;
2388 }
2389
2390 /* release the row/constraint */
2391 if( sourcebenders->cutsasconss )
2392 {
2393 /* only release if the creation of the constraint failed. */
2394 SCIP_CALL( SCIPreleaseCons(sourcescip, &transfercons) );
2395 }
2396 else
2397 {
2398 SCIP_CALL( SCIPreleaseRow(sourcescip, &transfercut) );
2399 }
2400
2401 return SCIP_OKAY;
2402}
2403
2404
2405/** transfers the cuts generated in a subscip to the source scip */
2406static
2408 SCIP* sourcescip, /**< the source SCIP from when the Benders' decomposition was copied */
2409 SCIP* subscip, /**< the sub SCIP where the Benders' cuts were generated */
2410 SCIP_BENDERS* benders /**< the Benders' decomposition structure of the sub SCIP */
2411 )
2412{
2413 SCIP_BENDERS* sourcebenders; /* the Benders' decomposition of the source SCIP */
2414 SCIP_VAR** vars; /* the variables of the added constraint/row */
2415 SCIP_Real* vals; /* the values of the added constraint/row */
2416 SCIP_Real lhs; /* the LHS of the added constraint/row */
2417 SCIP_Real rhs; /* the RHS of the added constraint/row */
2418 int naddedcuts;
2419 int nvars;
2420 int i;
2421
2422 assert(subscip != NULL);
2423 assert(benders != NULL);
2424
2425 /* retrieving the source Benders' decomposition structure */
2426 sourcebenders = SCIPfindBenders(sourcescip, SCIPbendersGetName(benders));
2427
2428 /* exit if the cuts should not be transferred from the sub SCIP to the source SCIP. */
2429 if( !sourcebenders->transfercuts || benders->mastervarsmap == NULL )
2430 return SCIP_OKAY;
2431
2432 /* retrieving the number of stored Benders' cuts */
2433 naddedcuts = SCIPbendersGetNStoredCuts(benders);
2434
2435 /* looping over all added cuts to construct the cut for the source scip */
2436 for( i = 0; i < naddedcuts; i++ )
2437 {
2438 /* collecting the variable information from the constraint */
2439 SCIP_CALL( SCIPbendersGetStoredCutData(benders, i, &vars, &vals, &lhs, &rhs, &nvars) );
2440
2441 if( nvars > 0 )
2442 {
2443 /* create and add the cut to be transferred from the sub SCIP to the source SCIP */
2444 SCIP_CALL( createAndAddTransferredCut(sourcescip, benders, vars, vals, lhs, rhs, nvars) );
2445 }
2446 }
2447
2448 return SCIP_OKAY;
2449}
2450
2452/** calls exit method of Benders' decomposition */
2454 SCIP_BENDERS* benders, /**< Benders' decomposition */
2455 SCIP_SET* set /**< global SCIP settings */
2456 )
2457{
2458 int nsubproblems;
2459 int i;
2460
2461 assert(benders != NULL);
2462 assert(set != NULL);
2463
2464 if( !benders->initialized )
2465 {
2466 SCIPerrorMessage("Benders' decomposition <%s> not initialized\n", benders->name);
2467 return SCIP_INVALIDCALL;
2468 }
2469
2470 /* start timing */
2471 SCIPclockStart(benders->setuptime, set);
2472
2473 if( benders->bendersexit != NULL )
2474 {
2475 SCIP_CALL( benders->bendersexit(set->scip, benders) );
2476 }
2477
2478 /* if the Benders' decomposition is a copy, then is a variable mapping was provided, then the generated cuts will
2479 * be transferred to the source scip
2480 */
2481 if( benders->iscopy && benders->mastervarsmap != NULL )
2482 {
2483 SCIP_CALL( transferBendersCuts(benders->sourcescip, set->scip, benders) );
2484 }
2485
2486 /* releasing the stored constraints */
2487 for( i = benders->nstoredcuts - 1; i >= 0; i-- )
2488 {
2489 SCIPfreeBlockMemoryArray(set->scip, &benders->storedcuts[i]->vals, benders->storedcuts[i]->nvars);
2490 SCIPfreeBlockMemoryArray(set->scip, &benders->storedcuts[i]->vars, benders->storedcuts[i]->nvars);
2491 SCIPfreeBlockMemory(set->scip, &benders->storedcuts[i]); /*lint !e866*/
2492 }
2493
2494 BMSfreeBlockMemoryArray(SCIPblkmem(set->scip), &benders->storedcuts, benders->storedcutssize);
2495 benders->storedcutssize = 0;
2496 benders->nstoredcuts = 0;
2497
2498 /* releasing all of the auxiliary variables and constraints */
2499 nsubproblems = SCIPbendersGetNSubproblems(benders);
2500 for( i = 0; i < nsubproblems; i++ )
2501 {
2502 /* it is possible that the master problem is not solved. As such, the auxiliary variables will not be created. So
2503 * we don't need to release the variables or the constraints
2504 */
2505 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX && benders->auxiliaryvarcons[i] != NULL )
2506 {
2507 SCIP_CALL( SCIPreleaseCons(set->scip, &benders->auxiliaryvarcons[i]) );
2508 }
2509
2510 if( benders->auxiliaryvars[i] != NULL )
2511 {
2512 /* we need to remove the locks from the auxiliary variables. This will be called always for the highest priority
2513 * Benders' plugin and others if the auxiliary variables are not shared
2514 */
2515 if( !benders->iscopy && SCIPvarGetNLocksDown(benders->auxiliaryvars[i]) > 0 )
2516 SCIP_CALL( SCIPaddVarLocksType(set->scip, benders->auxiliaryvars[i], SCIP_LOCKTYPE_MODEL, -1, 0) );
2517
2518 SCIP_CALL( SCIPreleaseVar(set->scip, &benders->auxiliaryvars[i]) );
2519 }
2520 }
2521
2522 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM && benders->auxiliaryvarcons[0] != NULL )
2523 {
2524 SCIP_CALL( SCIPreleaseCons(set->scip, &benders->auxiliaryvarcons[0]) );
2525 }
2526
2527 if( benders->masterauxvar != NULL )
2528 {
2529 /* we need to remove the locks from the auxiliary variables. This will be called always for the highest priority
2530 * Benders' plugin and others if the auxiliary variables are not shared
2531 */
2532 if( !benders->iscopy && SCIPvarGetNLocksDown(benders->masterauxvar) > 0 )
2533 {
2535 }
2536
2537 SCIP_CALL( SCIPreleaseVar(set->scip, &benders->masterauxvar) );
2538 }
2539
2541
2542 /* if a corepoint has been used for cut strengthening, then this needs to be freed */
2543 if( benders->corepoint != NULL )
2544 {
2545 SCIP_CALL( SCIPfreeSol(set->scip, &benders->corepoint) );
2546 }
2547
2548 /* calling the exit method for the Benders' cuts */
2550 for( i = 0; i < benders->nbenderscuts; i++ )
2551 {
2553 }
2554
2555 benders->initialized = FALSE;
2556
2557 /* stop timing */
2558 SCIPclockStop(benders->setuptime, set);
2559
2560 return SCIP_OKAY;
2561}
2562
2563/** Checks whether a subproblem is independent. */
2564static
2566 SCIP* scip, /**< the SCIP data structure */
2567 SCIP_BENDERS* benders /**< Benders' decomposition */
2568 )
2569{
2570 SCIP_VAR** vars;
2571 int nvars;
2572 int nsubproblems;
2573 int i;
2574 int j;
2575
2576 assert(scip != NULL);
2577 assert(benders != NULL);
2578
2579 /* retrieving the master problem variables */
2580 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2581
2582 nsubproblems = SCIPbendersGetNSubproblems(benders);
2583
2584 /* looping over all subproblems to check whether there exists at least one master problem variable */
2585 for( i = 0; i < nsubproblems; i++ )
2586 {
2587 /* if there are user defined solving or freeing functions, then it is not possible to declare the independence of
2588 * the subproblems.
2589 */
2590 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL
2591 && benders->bendersfreesub == NULL )
2592 {
2593 SCIP_Bool independent = TRUE;
2594
2595 for( j = 0; j < nvars; j++ )
2596 {
2597 SCIP_VAR* subprobvar;
2598
2599 /* getting the subproblem problem variable corresponding to the master problem variable */
2600 SCIP_CALL( SCIPgetBendersSubproblemVar(scip, benders, vars[j], &subprobvar, i) );
2601
2602 /* if the subporblem variable is not NULL, then the subproblem depends on the master problem */
2603 if( subprobvar != NULL )
2604 {
2605 independent = FALSE;
2606 break;
2607 }
2608 }
2609
2610 /* setting the independent flag */
2611 SCIPbendersSetSubproblemIsIndependent(benders, i, independent);
2612 }
2613 }
2614
2615 return SCIP_OKAY;
2616}
2618/** informs the Benders' decomposition that the presolving process is being started */
2620 SCIP_BENDERS* benders, /**< Benders' decomposition */
2621 SCIP_SET* set, /**< global SCIP settings */
2622 SCIP_STAT* stat /**< dynamic problem statistics */
2623 )
2624{
2625 assert(benders != NULL);
2626 assert(set != NULL);
2627 assert(stat != NULL);
2628
2629 /* the arrays for the auxiliary variables and constraints are not allocated at the activate stage. This is because
2630 * SCIPbendersActivate can be called during SCIP_STAGE_PROBLEM. As such, the user may still change the objective type
2631 * after the Benders' decomposition has been activated. The memory allocation occurs immediately before the variables
2632 * are created, then freed in SCIPbendersExit.
2633 */
2634 if( benders->objectivetype == SCIP_BENDERSOBJTYPE_SUM )
2635 {
2637 }
2638 else
2639 {
2640 assert(benders->objectivetype == SCIP_BENDERSOBJTYPE_MAX);
2642 }
2643
2644 /* if the Benders' decomposition is the original, then the auxiliary variables need to be created. If the Benders'
2645 * decomposition is a copy, then the auxiliary variables already exist. The assignment of the auxiliary variables
2646 * occurs in bendersInit
2647 */
2648 if( !benders->iscopy )
2649 {
2650 /* check the subproblem independence. This check is only performed if the user has not implemented a solve
2651 * subproblem function.
2652 */
2653 if( benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL )
2654 SCIP_CALL( checkSubproblemIndependence(set->scip, benders) );
2655
2656 /* adding the auxiliary variables to the master problem */
2657 SCIP_CALL( addAuxiliaryVariablesToMaster(set->scip, benders) );
2658 }
2659
2660 /* call presolving initialization method of Benders' decomposition */
2661 if( benders->bendersinitpre != NULL )
2662 {
2663 /* start timing */
2664 SCIPclockStart(benders->setuptime, set);
2665
2666 SCIP_CALL( benders->bendersinitpre(set->scip, benders) );
2667
2668 /* stop timing */
2669 SCIPclockStop(benders->setuptime, set);
2670 }
2671
2672 return SCIP_OKAY;
2673}
2674
2676/** informs the Benders ␚' decomposition that the presolving process has completed */
2678 SCIP_BENDERS* benders, /**< Benders' decomposition */
2679 SCIP_SET* set, /**< global SCIP settings */
2680 SCIP_STAT* stat /**< dynamic problem statistics */
2681 )
2682{
2683 assert(benders != NULL);
2684 assert(set != NULL);
2685 assert(stat != NULL);
2686
2687 /* call presolving deinitialization method of Benders' decomposition */
2688 if( benders->bendersexitpre != NULL )
2689 {
2690 /* start timing */
2691 SCIPclockStart(benders->setuptime, set);
2692
2693 SCIP_CALL( benders->bendersexitpre(set->scip, benders) );
2694
2695 /* stop timing */
2696 SCIPclockStop(benders->setuptime, set);
2697 }
2698
2699 return SCIP_OKAY;
2700}
2702/** informs Benders' decomposition that the branch and bound process is being started */
2704 SCIP_BENDERS* benders, /**< Benders' decomposition */
2705 SCIP_SET* set /**< global SCIP settings */
2706 )
2707{
2708 int i;
2709
2710 assert(benders != NULL);
2711 assert(set != NULL);
2712
2713 /* call solving process initialization method of Benders' decomposition */
2714 if( benders->bendersinitsol != NULL )
2715 {
2716 /* start timing */
2717 SCIPclockStart(benders->setuptime, set);
2718
2719 SCIP_CALL( benders->bendersinitsol(set->scip, benders) );
2720
2721 /* stop timing */
2722 SCIPclockStop(benders->setuptime, set);
2723 }
2724
2725 /* calling the initsol method for the Benders' cuts */
2727 for( i = 0; i < benders->nbenderscuts; i++ )
2728 {
2730 }
2731
2732 return SCIP_OKAY;
2733}
2735/** informs Benders' decomposition that the branch and bound process data is being freed */
2737 SCIP_BENDERS* benders, /**< Benders' decomposition */
2738 SCIP_SET* set /**< global SCIP settings */
2739 )
2740{
2741 int nsubproblems;
2742 int i;
2743
2744 assert(benders != NULL);
2745 assert(set != NULL);
2746
2747 nsubproblems = SCIPbendersGetNSubproblems(benders);
2748 /* freeing all subproblems that are independent, this is because they have not bee freed during the subproblem
2749 * solving loop.
2750 */
2751 for( i = 0; i < nsubproblems; i++ )
2752 {
2753 if( SCIPbendersSubproblemIsIndependent(benders, i) )
2754 {
2755 /* disabling the independence of the subproblem so that it can be freed */
2757
2758 /* freeing the independent subproblem */
2759 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, i) );
2760 }
2761 }
2762
2763 /* call solving process deinitialization method of Benders' decomposition */
2764 if( benders->bendersexitsol != NULL )
2765 {
2766 /* start timing */
2767 SCIPclockStart(benders->setuptime, set);
2768
2769 SCIP_CALL( benders->bendersexitsol(set->scip, benders) );
2770
2771 /* stop timing */
2772 SCIPclockStop(benders->setuptime, set);
2773 }
2774
2775 /* sorting the Benders' decomposition cuts in order of priority. Only a single cut is generated for each subproblem
2776 * per solving iteration. This is particularly important in the case of the optimality and feasibility cuts. Since
2777 * these work on two different solutions to the subproblem, it is not necessary to generate both cuts. So, once the
2778 * feasibility cut is generated, then no other cuts will be generated.
2779 */
2781
2782 /* calling the exitsol method for the Benders' cuts */
2783 for( i = 0; i < benders->nbenderscuts; i++ )
2784 {
2786 }
2787
2788 return SCIP_OKAY;
2789}
2791/** activates Benders' decomposition such that it is called in LP solving loop */
2793 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
2794 SCIP_SET* set, /**< global SCIP settings */
2795 int nsubproblems /**< the number subproblems used in this decomposition */
2796 )
2797{
2798 SCIP_EVENTHDLR* eventhdlr;
2799 SCIP_EVENTHDLRDATA* eventhdlrdata;
2800 int i;
2801
2802 assert(benders != NULL);
2803 assert(set != NULL);
2804 assert(set->stage == SCIP_STAGE_INIT || set->stage == SCIP_STAGE_PROBLEM);
2805
2806 if( !benders->active )
2807 {
2808 benders->active = TRUE;
2809 set->nactivebenders++;
2810 set->benderssorted = FALSE;
2811
2812 benders->nsubproblems = nsubproblems;
2813 benders->nactivesubprobs = nsubproblems;
2814 benders->prevlowerbound = -SCIPsetInfinity(set);
2815 benders->strengthenround = FALSE;
2816
2817 /* allocating memory for the subproblems arrays */
2825 SCIP_ALLOC( BMSallocMemoryArray(&benders->solvestat, benders->nsubproblems) );
2836
2837 /* creating the priority queue for the subproblem solving status */
2838 SCIP_CALL( SCIPpqueueCreate(&benders->subprobqueue, benders->nsubproblems, 1.1,
2839 benders->benderssubcomp == NULL ? benderssubcompdefault : benders->benderssubcomp, NULL) );
2840
2841 for( i = 0; i < benders->nsubproblems; i++ )
2842 {
2843 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
2844
2846
2847 benders->subproblems[i] = NULL;
2848 benders->auxiliaryvars[i] = NULL;
2850 benders->nsubmastervars[i] = 0;
2851 benders->nsubmasterbinvars[i] = 0;
2852 benders->nsubmasterintvars[i] = 0;
2853 benders->subprobobjval[i] = SCIPsetInfinity(set);
2854 benders->bestsubprobobjval[i] = SCIPsetInfinity(set);
2855 benders->subproblowerbound[i] = -SCIPsetInfinity(set);
2857 benders->subprobisconvex[i] = FALSE;
2858 benders->subprobisnonlinear[i] = FALSE;
2859 benders->subprobsetup[i] = FALSE;
2860 benders->indepsubprob[i] = FALSE;
2861 benders->subprobenabled[i] = TRUE;
2862 benders->mastervarscont[i] = FALSE;
2863
2864 /* initialising the subproblem solving status */
2865 SCIP_ALLOC( BMSallocMemory(&solvestat) );
2866 solvestat->idx = i;
2867 solvestat->ncalls = 0;
2868 solvestat->avgiter = 0;
2869 benders->solvestat[i] = solvestat;
2870
2871 /* inserting the initial elements into the priority queue */
2872 SCIP_CALL( SCIPpqueueInsert(benders->subprobqueue, benders->solvestat[i]) );
2873 }
2874
2876 {
2877 /* adding an eventhandler for updating the lower bound when the root node is solved. */
2878 eventhdlrdata = (SCIP_EVENTHDLRDATA*)benders;
2879
2880 /* include event handler into SCIP */
2882 eventExecBendersNodesolved, eventhdlrdata) );
2883 SCIP_CALL( SCIPsetEventhdlrInitsol(set->scip, eventhdlr, eventInitsolBendersNodesolved) );
2884 assert(eventhdlr != NULL);
2885 }
2886 }
2887
2888 return SCIP_OKAY;
2889}
2891/** deactivates Benders' decomposition such that it is no longer called in LP solving loop */
2893 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
2894 SCIP_SET* set /**< global SCIP settings */
2895 )
2896{
2897 int i;
2898
2899 assert(benders != NULL);
2900 assert(set != NULL);
2901 assert(set->stage == SCIP_STAGE_INIT || set->stage == SCIP_STAGE_PROBLEM);
2902
2903 if( benders->active )
2904 {
2905 SCIP_EVENTHDLR* eventhdlr;
2906 int nsubproblems;
2907
2908 nsubproblems = SCIPbendersGetNSubproblems(benders);
2909
2910#ifndef NDEBUG
2911 /* checking whether the auxiliary variables and subproblems are all NULL */
2912 for( i = 0; i < nsubproblems; i++ )
2913 assert(benders->auxiliaryvars[i] == NULL);
2914#endif
2915
2916 /* if the subproblems were created by the Benders' decomposition core, then they need to be freed */
2917 if( benders->freesubprobs )
2918 {
2919 for( i = SCIPbendersGetNSubproblems(benders) - 1; i >= 0; i-- )
2920 {
2921 SCIP* subproblem = SCIPbendersSubproblem(benders, i);
2922 SCIP_CALL( SCIPfree(&subproblem) );
2923 }
2924 }
2925
2926 benders->active = FALSE;
2927 set->nactivebenders--;
2928 set->benderssorted = FALSE;
2929
2930 /* freeing the priority queue memory */
2931 SCIPpqueueFree(&benders->subprobqueue);
2932
2933 for( i = nsubproblems - 1; i >= 0; i-- )
2934 BMSfreeMemory(&benders->solvestat[i]);
2935
2936 /* freeing the master variable storage if it exists */
2937 for( i = nsubproblems - 1; i >= 0; i-- )
2939
2940 /* freeing the memory allocated during the activation of the Benders' decomposition */
2951 BMSfreeMemoryArray(&benders->solvestat);
2959
2960 benders->ncalls = 0;
2961 benders->ncutsfound = 0;
2962 benders->ntransferred = 0;
2963
2964 benders->naddedsubprobs = 0;
2965 benders->nconvexsubprobs = 0;
2966 benders->nnonlinearsubprobs = 0;
2967 benders->subprobscreated = FALSE;
2968 benders->freesubprobs = FALSE;
2969 benders->masterisnonlinear = FALSE;
2970
2971 benders->nstrengthencuts = 0;
2972 benders->nstrengthencalls = 0;
2973 benders->nstrengthenfails = 0;
2974
2975 benders->npseudosols = 0;
2976 benders->feasibilityphase = FALSE;
2977
2978 /* dropping the event from the node solved event handler */
2980 if( eventhdlr != NULL && SCIPsetGetStage(set) >= SCIP_STAGE_INITSOLVE )
2981 {
2982 SCIP_CALL( SCIPdropEvent(set->scip, SCIP_EVENTTYPE_NODESOLVED, eventhdlr, NULL, -1) );
2983 }
2984 }
2985
2986 return SCIP_OKAY;
2987}
2989/** returns whether the given Benders' decomposition is in use in the current problem */
2991 SCIP_BENDERS* benders /**< the Benders' decomposition structure */
2992 )
2993{
2994 assert(benders != NULL);
2995
2996 return benders->active;
2997}
2998
2999/** updates the lower bound for all auxiliary variables. This is called if the first LP enforced is unbounded. */
3000static
3002 SCIP_BENDERS* benders, /**< Benders' decomposition */
3003 SCIP_SET* set, /**< global SCIP settings */
3004 SCIP_RESULT* result /**< the result from updating the auxiliary variable lower bound */
3005 )
3006{
3007 int nsubproblems;
3008 int i;
3009
3010 assert(benders != NULL);
3011 assert(set != NULL);
3012
3013 (*result) = SCIP_DIDNOTRUN;
3014
3015 nsubproblems = SCIPbendersGetNSubproblems(benders);
3016
3017 for( i = 0; i < nsubproblems; i++ )
3018 {
3019 SCIP_VAR* auxiliaryvar;
3020 SCIP_Real lowerbound;
3021 SCIP_Bool infeasible;
3022
3023 infeasible = FALSE;
3024
3025 /* computing the lower bound of the subproblem by solving it without any variable fixings */
3026 SCIP_CALL( SCIPbendersComputeSubproblemLowerbound(benders, set, i, &lowerbound, &infeasible) );
3027
3028 /* if the subproblem is infeasible, then the original problem is infeasible */
3029 if( infeasible )
3030 {
3031 (*result) = SCIP_INFEASIBLE;
3032 break;
3033 }
3034
3035 /* retrieving the auxiliary variable */
3036 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, i);
3037
3038 /* only update the lower bound if it is greater than the current lower bound */
3039 if( SCIPsetIsGT(set, lowerbound, SCIPvarGetLbGlobal(auxiliaryvar)) )
3040 {
3041 SCIPsetDebugMsg(set, "Tightened lower bound of <%s> to %g\n", SCIPvarGetName(auxiliaryvar), lowerbound);
3042 /* updating the lower bound of the auxiliary variable */
3043 SCIP_CALL( SCIPchgVarLb(set->scip, auxiliaryvar, lowerbound) );
3044 (*result) = SCIP_REDUCEDDOM;
3045 }
3046
3047 /* stores the lower bound for the subproblem */
3048 SCIPbendersUpdateSubproblemLowerbound(benders, i, lowerbound);
3049 }
3050
3051 return SCIP_OKAY;
3052}
3053
3054/** sets the core point used for cut strengthening. If the strenghtenintpoint is set to 'i', then the core point is
3055 * reinitialised each time the incumbent is updated
3057static
3059 SCIP* scip, /**< the SCIP data structure */
3060 SCIP_BENDERS* benders /**< Benders' decomposition */
3061 )
3062{
3063 SCIP_SOL* bestsol;
3064
3065 assert(scip != NULL);
3066 assert(benders != NULL);
3067
3068 /* if the core point is not NULL and the interior point is not reinitialised, then nothing is done */
3069 if( benders->corepoint != NULL && benders->strengthenintpoint != 'i' )
3070 return SCIP_OKAY;
3071
3072 bestsol = SCIPgetBestSol(scip);
3073
3074 /* if the core point should be updated, then this only happens if the incumbent solution has been updated */
3075 if( benders->strengthenintpoint == 'i' && benders->initcorepoint == bestsol )
3076 return SCIP_OKAY;
3077
3078 /* if a corepoint has been used for cut strengthening, then this needs to be freed */
3079 if( benders->corepoint != NULL )
3080 {
3081 SCIP_CALL( SCIPfreeSol(scip, &benders->corepoint) );
3082 }
3083
3084 switch( benders->strengthenintpoint )
3085 {
3086 SCIP_VAR** vars;
3087 SCIP_Real timelimit;
3088 int nvars;
3089 int i;
3090
3091 case 'l':
3093 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
3094 break;
3095 case 'f':
3096 case 'i':
3097 SCIP_CALL( SCIPcreateSolCopy(scip, &benders->corepoint, bestsol) );
3098 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
3099 benders->initcorepoint = bestsol;
3100 break;
3101 case 'r':
3102 /* prepare time limit */
3103 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3104 if ( ! SCIPisInfinity(scip, timelimit) )
3105 timelimit -= SCIPgetSolvingTime(scip);
3106
3107 /* if there is time remaining, then compute the relative interior point. Otherwise, return the LP solution */
3108 if ( timelimit > 0.0 )
3109 {
3110 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, 0, "Computing relative interior point (time limit: %g, iter limit: %d) ...\n", timelimit, INT_MAX);
3111 SCIP_CALL( SCIPcomputeLPRelIntPoint(scip, TRUE, FALSE, timelimit, INT_MAX, &benders->corepoint) );
3112 }
3113 else
3114 {
3116 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
3117 }
3118 break;
3119 case 'z':
3120 SCIP_CALL( SCIPcreateSol(scip, &benders->corepoint, NULL) );
3121 break;
3122 case 'o':
3123 SCIP_CALL( SCIPcreateSol(scip, &benders->corepoint, NULL) );
3124
3125 /* getting the variable data so that the */
3126 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
3127
3128 /* setting all variable values to 1.0 */
3129 for( i = 0; i < nvars; i++ )
3130 {
3131 SCIP_CALL( SCIPsetSolVal(scip, benders->corepoint, vars[i], 1.0) );
3132 }
3133 break;
3134 default:
3136 SCIP_CALL( SCIPunlinkSol(scip, benders->corepoint) );
3137 }
3138
3139 return SCIP_OKAY;
3140}
3141
3142/** performs cut strengthening by using an interior solution to generate cuts */
3143static
3145 SCIP_BENDERS* benders, /**< Benders' decomposition */
3146 SCIP_SET* set, /**< global SCIP settings */
3147 SCIP_SOL* sol, /**< primal CIP solution */
3148 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3149 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
3150 SCIP_Bool perturbsol, /**< should the solution be perturbed to escape infeasibility? */
3151 SCIP_Bool* auxviol, /**< set to TRUE only if the solution is feasible but the aux vars are violated */
3152 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
3153 SCIP_Bool* skipsolve, /**< should the main solve be skipped as a result of this strengthening? */
3154 SCIP_RESULT* result /**< result of the pricing process */
3155 )
3156{
3157 SCIP_SOL* sepapoint;
3158 SCIP_VAR** vars;
3159 int prevcutsfound;
3160 int nvars;
3161 int i;
3162
3163 assert(benders != NULL);
3164 assert(set != NULL);
3165
3166 (*result) = SCIP_DIDNOTRUN;
3167 (*skipsolve) = FALSE;
3168
3169 /* the cut stabilisation is only performed when enforcing LP solutions. The solution is not NULL if the stabilisation
3170 * is currently being performed. It is important to avoid recursion
3171 */
3172 if( type != SCIP_BENDERSENFOTYPE_LP || sol != NULL )
3173 return SCIP_OKAY;
3174
3175 /* checking if a change to the lower bound has occurred */
3176 if( SCIPsetIsGT(set, SCIPgetLowerbound(set->scip), benders->prevlowerbound)
3177 || SCIPgetCurrentNode(set->scip) != benders->prevnode )
3178 {
3179 benders->prevnode = SCIPgetCurrentNode(set->scip);
3180 benders->prevlowerbound = SCIPgetLowerbound(set->scip);
3181 benders->noimprovecount = 0;
3182 }
3183 else
3184 benders->noimprovecount++;
3185
3186 /* if the number of iterations without improvement exceeds 3*noimprovelimit, then the no stabilisation is performed
3187 */
3188 if( benders->noimprovecount > 3*benders->noimprovelimit )
3189 return SCIP_OKAY;
3190
3191 /* if there is no incumbent solution, then it is not possible to create the core point and hence the strengthening
3192 * can not be performed
3193 */
3194 if( SCIPgetBestSol(set->scip) == NULL )
3195 return SCIP_OKAY;
3196
3197 /* if no LP iterations have been performed since the last call of the cut strenghtening, then the strengthening is
3198 * aborted
3199 */
3200 if( benders->prevnlpiter == SCIPgetNLPIterations(set->scip) )
3201 return SCIP_OKAY;
3202
3203 benders->prevnlpiter = SCIPgetNLPIterations(set->scip);
3204
3205 /* if the separation point solution is NULL, then we create the solution using the current LP relaxation. */
3206 SCIP_CALL( setAndUpdateCorePoint(set->scip, benders) );
3207
3208 /* creating the separation point
3209 * TODO: This could be a little to memory heavy, it may be better just to create the separation point once and then
3210 * update it each time.
3211 */
3212 SCIP_CALL( SCIPcreateLPSol(set->scip, &sepapoint, NULL) );
3213 SCIP_CALL( SCIPunlinkSol(set->scip, sepapoint) );
3214
3215 SCIP_CALL( SCIPgetVarsData(set->scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
3216 assert(vars != NULL);
3217
3218 /* creating a solution that is a convex combination of the LP solution and the separation point */
3219 for( i = 0; i < nvars; i++ )
3220 {
3221 SCIP_VAR* subvar;
3222 SCIP_Real corepointval;
3223 SCIP_Real lpsolval;
3224 SCIP_Real newsolval;
3225 int j;
3226
3227 corepointval = SCIPgetSolVal(set->scip, benders->corepoint, vars[i]);
3228 lpsolval = SCIPgetSolVal(set->scip, sol, vars[i]);
3229 newsolval = lpsolval;
3230
3231 /* checking whether the master variable is mapped to any subproblem variables */
3232 subvar = NULL;
3233 j = 0;
3234 while( subvar == NULL && j < SCIPgetBendersNSubproblems(set->scip, benders) )
3235 {
3236 SCIP_CALL( SCIPgetBendersSubproblemVar(set->scip, benders, vars[i], &subvar, j) );
3237 j++;
3238 }
3239
3240 /* if the variable is a linking variable and it is not fixed, then a convex combination with the corepoint is
3241 * computed.
3242 */
3243 if( subvar != NULL && SCIPvarGetStatus(vars[i]) != SCIP_VARSTATUS_FIXED )
3244 {
3245 /* if the number of iterations without improvement exceeds noimprovelimit, then no convex combination is
3246 * created
3247 */
3248 if( !perturbsol && benders->noimprovecount <= benders->noimprovelimit )
3249 {
3250 newsolval = lpsolval*benders->convexmult + corepointval*(1 - benders->convexmult);
3251
3252 /* updating the core point */
3253 SCIP_CALL( SCIPsetSolVal(set->scip, benders->corepoint, vars[i], newsolval) );
3254 }
3255
3256 /* if the number of iterations without improvement is less than 2*noimprovelimit, then perturbation is
3257 * performed
3258 * TODO: This should be a random vector!!!!
3259 */
3260 if( perturbsol || benders->noimprovecount <= 2*benders->noimprovelimit )
3261 newsolval += benders->perturbeps;
3262 }
3263
3264 /* updating the separation point */
3265 SCIP_CALL( SCIPsetSolVal(set->scip, sepapoint, vars[i], newsolval) );
3266 }
3267
3268 /* storing the number of cuts found */
3269 prevcutsfound = SCIPbendersGetNCutsFound(benders);
3270
3271 SCIPsetDebugMsg(set, "solving Benders' decomposition subproblems with stabilised point.\n");
3272
3273 /* calling the subproblem solving method to generate cuts from the separation solution */
3274 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sepapoint, result, infeasible, auxviol, type, checkint) );
3275
3276 SCIPsetDebugMsg(set, "solved Benders' decomposition subproblems with stabilised point. noimprovecount %d result %d\n",
3277 benders->noimprovecount, (*result));
3278
3279 /* if constraints were added, then the main Benders' solving loop is skipped. */
3280 if( !(*infeasible) && ((*result) == SCIP_CONSADDED || (*result) == SCIP_SEPARATED) )
3281 (*skipsolve) = TRUE;
3282
3283 /* capturing cut strengthening statistics */
3284 benders->nstrengthencalls++;
3285 benders->nstrengthencuts += (SCIPbendersGetNCutsFound(benders) - prevcutsfound);
3286
3287 /* if no cuts were added, then the strengthening round is marked as failed */
3288 if( SCIPbendersGetNCutsFound(benders) == prevcutsfound )
3289 benders->nstrengthenfails++;
3290
3291 /* freeing the sepapoint solution */
3292 SCIP_CALL( SCIPfreeSol(set->scip, &sepapoint) );
3293
3294 return SCIP_OKAY;
3295}
3296
3297
3298/** Returns whether only the convex relaxations will be checked in this solve loop
3299 * when Benders' is used in the LNS heuristics, only the convex relaxations of the master/subproblems are checked,
3300 * i.e. no integer cuts are generated. In this case, then Benders' decomposition is performed under the assumption
3301 * that all subproblems are convex relaxations.
3302 */
3304 SCIP_BENDERS* benders, /**< Benders' decomposition */
3305 SCIP_Bool subscipsoff /**< flag indicating whether plugins using sub-SCIPs are deactivated */
3306 )
3307{
3308 return benders->iscopy && benders->lnscheck && subscipsoff;
3309}
3310
3311/** returns the number of subproblems that will be checked in this iteration */
3312static
3314 SCIP_BENDERS* benders, /**< Benders' decomposition */
3315 SCIP_SET* set, /**< global SCIP settings */
3316 SCIP_BENDERSENFOTYPE type /**< the type of solution being enforced */
3317 )
3318{
3319 if( benders->ncalls == 0 || type == SCIP_BENDERSENFOTYPE_CHECK
3321 return SCIPbendersGetNSubproblems(benders);
3322 else
3323 return (int) SCIPsetCeil(set, (SCIP_Real) SCIPbendersGetNSubproblems(benders)*benders->subprobfrac);
3324}
3325
3326/** returns whether the solving of the given subproblem needs to be executed */
3327static
3329 SCIP_BENDERS* benders, /**< Benders' decomposition */
3330 int probnumber /**< the subproblem index */
3331 )
3332{
3333 return (!SCIPbendersSubproblemIsIndependent(benders, probnumber)
3334 && SCIPbendersSubproblemIsEnabled(benders, probnumber));
3335}
3336
3337/** creates an ordered list of subproblem indices to be solved */
3338static
3340 SCIP_BENDERS* benders, /**< Benders' decomposition */
3341 SCIP_SET* set, /**< global SCIP settings */
3342 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3343 int** solveidx, /**< a list of subproblem indices to the solved in the current iteration */
3344 int* nsolveidx /**< the number of subproblem indices in the list */
3345 )
3346{
3347 int nsubproblems;
3348 int numtocheck;
3349 int subproblemcount;
3350
3351 assert(benders != NULL);
3352 assert(set != NULL);
3353 assert((*solveidx) != NULL);
3354 assert(nsolveidx != NULL);
3355 assert(SCIPpqueueNElems(benders->subprobqueue) <= SCIPbendersGetNSubproblems(benders));
3356
3357 nsubproblems = SCIPbendersGetNSubproblems(benders);
3358
3359 /* it is possible to only solve a subset of subproblems. This is given by a parameter. */
3360 numtocheck = numSubproblemsToCheck(benders, set, type);
3361
3362 (*nsolveidx) = 0;
3363
3364 subproblemcount = 0;
3365 while( subproblemcount < nsubproblems && subproblemcount < numtocheck )
3366 {
3367 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
3368
3370 (*solveidx)[(*nsolveidx)] = solvestat->idx;
3371 (*nsolveidx)++;
3372
3373 subproblemcount++;
3374 }
3375}
3376
3377/** updates the subproblem solving statistics and inserts the indices into the queue */
3378static
3380 SCIP_BENDERS* benders, /**< Benders' decomposition */
3381 int* solveidx, /**< the list of indices of subproblems that were solved */
3382 int nsolveidx, /**< the number of subproblem indices */
3383 SCIP_Bool updatestat /**< should the statistics be updated */
3384 )
3385{
3386 int i;
3387
3388 assert(benders != NULL);
3389 assert(solveidx != NULL);
3390
3391 for( i = 0; i < nsolveidx; i++ )
3392 {
3393 SCIP* subproblem;
3394 SCIP_SUBPROBLEMSOLVESTAT* solvestat;
3395
3396 subproblem = SCIPbendersSubproblem(benders, solveidx[i]);
3397 solvestat = benders->solvestat[solveidx[i]];
3398 assert(solvestat->idx == solveidx[i]);
3399
3400 /* updating the solving statistics */
3401 if( updatestat )
3402 {
3403 if( !subproblemIsActive(benders, solveidx[i]) || subproblem == NULL )
3404 solvestat->avgiter = 1;
3405 else
3406 solvestat->avgiter = (SCIP_Real)(solvestat->avgiter*solvestat->ncalls + SCIPgetNLPIterations(subproblem))
3407 /(SCIP_Real)(solvestat->ncalls + 1);
3408 solvestat->ncalls++;
3409 }
3410
3411 /* inserting the solving statistics into the priority queue */
3412 SCIP_CALL( SCIPpqueueInsert(benders->subprobqueue, solvestat) );
3413 }
3414
3415 assert(SCIPpqueueNElems(benders->subprobqueue) == SCIPbendersGetNSubproblems(benders));
3416
3417 return SCIP_OKAY;
3418}
3419
3420/** Solves each of the Benders' decomposition subproblems for the given solution. All, or a fraction, of subproblems are
3421 * solved before the Benders' decomposition cuts are generated.
3422 * Since a convex relaxation of the subproblem could be solved to generate cuts, a parameter nverified is used to
3423 * identified the number of subproblems that have been solved in their "original" form. For example, if the subproblem
3424 * is a MIP, then if the LP is solved to generate cuts, this does not constitute a verification. The verification is
3425 * only performed when the MIP is solved.
3427static
3429 SCIP_BENDERS* benders, /**< Benders' decomposition */
3430 SCIP_SET* set, /**< global SCIP settings */
3431 SCIP_SOL* sol, /**< primal CIP solution */
3432 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3433 SCIP_BENDERSSOLVELOOP solveloop, /**< the current solve loop */
3434 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
3435 int* nverified, /**< the number of subproblems verified in the current loop */
3436 int* solveidx, /**< the indices of subproblems to be solved in this loop */
3437 int nsolveidx, /**< the number of subproblems to be solved in this loop */
3438 SCIP_Bool** subprobsolved, /**< an array indicating the subproblems that were solved in this loop. */
3439 SCIP_BENDERSSUBSTATUS** substatus, /**< array to store the status of the subsystem */
3440 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
3441 SCIP_Bool* optimal, /**< is the current solution optimal? */
3442 SCIP_Bool* stopped /**< was the solving process stopped? */
3443 )
3444{
3445 SCIP_Bool onlyconvexcheck;
3446 int i;
3447 int j;
3448
3449 SCIP_RETCODE retcode = SCIP_OKAY;
3450
3451 assert(benders != NULL);
3452 assert(set != NULL);
3453
3454 /* in the case of an LNS check, only the convex relaxations of the subproblems will be solved. This is a performance
3455 * feature, since solving the convex relaxation is typically much faster than solving the corresponding CIP. While
3456 * the CIP is not solved during the LNS check, the solutions are still of higher quality than when Benders' is not
3457 * employed.
3458 */
3459 onlyconvexcheck = SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set));
3460
3461 SCIPsetDebugMsg(set, "Performing the subproblem solving process. Number of subproblems to check %d\n", nsolveidx);
3462
3463 SCIPsetDebugMsg(set, "Benders' decomposition - solve loop %d\n", solveloop);
3464
3465 if( type == SCIP_BENDERSENFOTYPE_CHECK && sol == NULL )
3466 {
3467 /* TODO: Check whether this is absolutely necessary. I think that this if statment can be removed. */
3468 (*infeasible) = TRUE;
3469 }
3470 else
3471 {
3472 /* solving each of the subproblems for Benders' decomposition */
3473 /* TODO: ensure that the each of the subproblems solve and update the parameters with the correct return values
3474 */
3475 for( j = 0; j < nsolveidx; j++ )
3476 {
3477 SCIP_Bool subinfeas = FALSE;
3478 SCIP_Bool convexsub;
3479 SCIP_Bool solvesub = TRUE;
3480 SCIP_Bool solved;
3481
3482 i = solveidx[j];
3484
3485 /* the subproblem is initially flagged as not solved for this solving loop */
3486 (*subprobsolved)[i] = FALSE;
3487
3488 /* setting the subsystem status to UNKNOWN at the start of each solve loop */
3489 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_UNKNOWN;
3490
3491 /* for the second solving loop, if the problem is an LP, it is not solved again. If the problem is a MIP,
3492 * then the subproblem objective function value is set to infinity. However, if the subproblem is proven
3493 * infeasible from the LP, then the IP loop is not performed.
3494 * If the solve loop is SCIP_BENDERSSOLVELOOP_USERCIP, then nothing is done. It is assumed that the user will
3495 * correctly update the objective function within the user-defined solving function.
3496 */
3497 if( solveloop == SCIP_BENDERSSOLVELOOP_CIP )
3498 {
3499 if( convexsub )
3500 solvesub = FALSE;
3501 else
3502 {
3503 SCIPbendersSetSubproblemObjval(benders, i, SCIPbendersSubproblem(benders, i) != NULL ?
3505 }
3506 }
3507
3508 /* if the subproblem is independent, then it does not need to be solved. In this case, the nverified flag will
3509 * increase by one. When the subproblem is not independent, then it needs to be checked.
3510 */
3511 if( !subproblemIsActive(benders, i) )
3512 {
3513 /* NOTE: There is no need to update the optimal flag. This is because optimal is always TRUE until a
3514 * non-optimal subproblem is found.
3515 */
3516 /* if the auxiliary variable value is infinity, then the subproblem has not been solved yet. Currently the
3517 * subproblem statue is unknown. */
3521 {
3522 SCIPbendersSetSubproblemObjval(benders, i, SCIPbendersSubproblem(benders, i) != NULL ?
3524
3525 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_UNKNOWN;
3526 (*optimal) = FALSE;
3527
3528 SCIPsetDebugMsg(set, "Benders' decomposition: subproblem %d is not active, but has not been solved."
3529 " setting status to UNKNOWN\n", i);
3530 }
3531 else
3532 {
3534 SCIPbendersGetAuxiliaryVarVal(benders, set, sol, i)) < benders->solutiontol )
3535 {
3537 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_OPTIMAL;
3538 }
3539 else
3540 {
3542 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_AUXVIOL;
3543 }
3544
3545 SCIPsetDebugMsg(set, "Benders' decomposition: subproblem %d is not active, setting status to OPTIMAL\n", i);
3546 }
3547
3548 (*subprobsolved)[i] = TRUE;
3549
3550 /* the nverified counter is only increased in the convex solving loop */
3551 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX )
3552 (*nverified)++;
3553 }
3554 else if( solvesub )
3555 {
3556 retcode = SCIPbendersExecSubproblemSolve(benders, set, sol, i, solveloop, FALSE, &solved, &subinfeas, type);
3557
3558 /* the solution for the subproblem is only processed if the return code is SCIP_OKAY */
3559 if( retcode == SCIP_OKAY )
3560 {
3561#ifdef SCIP_DEBUG
3562 if( type == SCIP_BENDERSENFOTYPE_LP )
3563 {
3564 SCIPsetDebugMsg(set, "Enfo LP: Subproblem %d Type %d (%f < %f)\n", i,
3565 SCIPbendersGetSubproblemType(benders, i), SCIPbendersGetAuxiliaryVarVal(benders, set, sol, i),
3566 SCIPbendersGetSubproblemObjval(benders, i));
3567 }
3568#endif
3569 (*subprobsolved)[i] = solved;
3570
3571 (*infeasible) = (*infeasible) || subinfeas;
3572 if( subinfeas )
3573 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_INFEAS;
3574
3575 /* if the subproblems are solved to check integer feasibility, then the optimality check must be performed.
3576 * This will only be performed if checkint is TRUE and the subproblem was solved. The subproblem may not be
3577 * solved if the user has defined a solving function
3578 */
3579 if( checkint && (*subprobsolved)[i] )
3580 {
3581 /* if the subproblem is feasible, then it is necessary to update the value of the auxiliary variable to the
3582 * objective function value of the subproblem.
3583 */
3584 if( !subinfeas )
3585 {
3586 SCIP_Bool subproboptimal;
3587
3588 subproboptimal = SCIPbendersSubproblemIsOptimal(benders, set, sol, i);
3589
3590 if( subproboptimal )
3591 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_OPTIMAL;
3592 else
3593 (*substatus)[i] = SCIP_BENDERSSUBSTATUS_AUXVIOL;
3594
3595 /* It is only possible to determine the optimality of a solution within a given subproblem in four
3596 * different cases:
3597 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX or USERCONVEX and the subproblem is convex.
3598 * ii) solveloop == SCIP_BENDERSOLVELOOP_CONVEX and only the convex relaxations will be checked.
3599 * iii) solveloop == SCIP_BENDERSSOLVELOOP_USERCIP and the subproblem was solved, since the user has
3600 * defined a solve function, it is expected that the solving is correctly executed.
3601 * iv) solveloop == SCIP_BENDERSSOLVELOOP_CIP and the MIP for the subproblem has been solved.
3602 */
3603 if( convexsub || onlyconvexcheck
3604 || solveloop == SCIP_BENDERSSOLVELOOP_CIP
3605 || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
3606 (*optimal) = (*optimal) && subproboptimal;
3607
3608#ifdef SCIP_DEBUG
3609 if( convexsub || solveloop >= SCIP_BENDERSSOLVELOOP_CIP )
3610 {
3611 if( subproboptimal )
3612 {
3613 SCIPsetDebugMsg(set, "Subproblem %d is Optimal (%f >= %f)\n", i,
3615 }
3616 else
3617 {
3618 SCIPsetDebugMsg(set, "Subproblem %d is NOT Optimal (%f < %f)\n", i,
3620 }
3621 }
3622#endif
3623
3624 /* the nverified variable is only incremented when the original form of the subproblem has been solved.
3625 * What is meant by "original" is that the LP relaxation of CIPs are solved to generate valid cuts. So
3626 * if the subproblem is defined as a CIP, then it is only classified as checked if the CIP is solved.
3627 * There are three cases where the "original" form is solved are:
3628 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX or USERCONVEX and the subproblem is an LP
3629 * - the original form has been solved.
3630 * ii) solveloop == SCIP_BENDERSSOLVELOOP_CIP or USERCIP and the CIP for the subproblem has been
3631 * solved.
3632 * iii) or, only a convex check is performed.
3633 */
3634 if( ((solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX)
3635 && convexsub)
3636 || ((solveloop == SCIP_BENDERSSOLVELOOP_CIP || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP)
3637 && !convexsub)
3638 || onlyconvexcheck )
3639 (*nverified)++;
3640 }
3641 }
3642 }
3643 }
3644
3645 /* checking whether the limits have been exceeded in the master problem */
3646 (*stopped) = SCIPisStopped(set->scip);
3647 }
3648 }
3649
3650 return retcode;
3651}
3652
3653/** Calls the Benders' decompsition cuts for the given solve loop. There are four cases:
3654 * i) solveloop == SCIP_BENDERSSOLVELOOP_CONVEX - only the LP Benders' cuts are called
3655 * ii) solveloop == SCIP_BENDERSSOLVELOOP_CIP - only the CIP Benders' cuts are called
3656 * iii) solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX - only the LP Benders' cuts are called
3657 * iv) solveloop == SCIP_BENDERSSOLVELOOP_USERCIP - only the CIP Benders' cuts are called
3658 *
3659 * The priority of the results are: SCIP_CONSADDED (SCIP_SEPARATED), SCIP_DIDNOTFIND, SCIP_FEASIBLE, SCIP_DIDNOTRUN. In
3660 * this function, there are four levels of results that need to be assessed. These are:
3661 * i) The result from the individual cut for the subproblem
3662 * ii) The overall result for the subproblem from all cuts
3663 * iii) the overall result for the solve loop from all cuts
3664 * iv) the over all result from all solve loops.
3665 * In each level, the priority of results must be adhered to.
3667static
3669 SCIP_BENDERS* benders, /**< Benders' decomposition */
3670 SCIP_SET* set, /**< global SCIP settings */
3671 SCIP_SOL* sol, /**< primal CIP solution */
3672 SCIP_RESULT* result, /**< result of the pricing process */
3673 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3674 SCIP_BENDERSSOLVELOOP solveloop, /**< the current solve loop */
3675 SCIP_Bool checkint, /**< are the subproblems called during a check/enforce of integer sols? */
3676 SCIP_Bool* subprobsolved, /**< an array indicating the subproblems that were solved in this loop. */
3677 SCIP_BENDERSSUBSTATUS* substatus, /**< array to store the status of the subsystem */
3678 int* solveidx, /**< the indices of subproblems to be solved in this loop */
3679 int nsolveidx, /**< the number of subproblems to be solved in this loop */
3680 int** mergecands, /**< the subproblems that are merge candidates */
3681 int* npriomergecands, /**< the number of priority merge candidates. */
3682 int* nmergecands, /**< the number of merge candidates. */
3683 int* nsolveloops /**< the number of solve loops, is updated w.r.t added cuts */
3684 )
3685{
3686 SCIP_BENDERSCUT** benderscuts;
3687 SCIP_RESULT solveloopresult;
3688 int nbenderscuts;
3689 SCIP_Longint addedcuts = 0;
3690 int i;
3691 int j;
3692 int k;
3693 SCIP_Bool onlyconvexcheck;
3694
3695 assert(benders != NULL);
3696 assert(set != NULL);
3697
3698 /* getting the Benders' decomposition cuts */
3699 benderscuts = SCIPbendersGetBenderscuts(benders);
3700 nbenderscuts = SCIPbendersGetNBenderscuts(benders);
3701
3702 solveloopresult = SCIP_DIDNOTRUN;
3703
3704 /* in the case of an LNS check, only the convex relaxations of the subproblems will be solved. This is a performance
3705 * feature, since solving the convex relaxation is typically much faster than solving the corresponding CIP. While
3706 * the CIP is not solved during the LNS check, the solutions are still of higher quality than when Benders' is not
3707 * employed.
3708 */
3709 onlyconvexcheck = SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set));
3710
3711 /* It is only possible to add cuts to the problem if it has not already been solved */
3714 && (benders->cutcheck || type != SCIP_BENDERSENFOTYPE_CHECK) )
3715 {
3716 /* This is done in two loops. The first is by subproblem and the second is by cut type. */
3717 for( k = 0; k < nsolveidx; k++ )
3718 {
3719 SCIP_RESULT subprobresult;
3720 SCIP_Bool convexsub;
3721
3722 i = solveidx[k];
3723
3725
3726 /* cuts can only be generated if the subproblem is not independent and if it has been solved. Additionally, the
3727 * status of the subproblem solving must not be INFEASIBLE while in a cut strengthening round.
3728 * The subproblem solved flag is important for the user-defined subproblem solving methods
3729 */
3730 if( subproblemIsActive(benders, i) && subprobsolved[i]
3731 && !(substatus[i] == SCIP_BENDERSSUBSTATUS_INFEAS && benders->strengthenround) )
3732 {
3733 subprobresult = SCIP_DIDNOTRUN;
3734 for( j = 0; j < nbenderscuts; j++ )
3735 {
3736 SCIP_RESULT cutresult;
3737 SCIP_Longint prevaddedcuts;
3738
3739 assert(benderscuts[j] != NULL);
3740
3741 prevaddedcuts = SCIPbenderscutGetNFound(benderscuts[j]);
3742 cutresult = SCIP_DIDNOTRUN;
3743
3744 /* the result is updated only if a Benders' cut is generated or one was not found. However, if a cut has
3745 * been found in a previous iteration, then the result is returned as SCIP_CONSADDED or SCIP_SEPARATED.
3746 * This result is permitted because if a constraint was added, the solution that caused the error in the cut
3747 * generation will be cutoff from the master problem.
3748 */
3749 if( (SCIPbenderscutIsLPCut(benderscuts[j]) && (solveloop == SCIP_BENDERSSOLVELOOP_CONVEX
3750 || solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX))
3751 || (!SCIPbenderscutIsLPCut(benderscuts[j]) && ((solveloop == SCIP_BENDERSSOLVELOOP_CIP && !convexsub)
3752 || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP)) )
3753 SCIP_CALL( SCIPbenderscutExec(benderscuts[j], set, benders, sol, i, type, &cutresult) );
3754
3755 addedcuts += (SCIPbenderscutGetNFound(benderscuts[j]) - prevaddedcuts);
3756
3757 /* the result is updated only if a Benders' cut is generated */
3758 if( cutresult == SCIP_CONSADDED || cutresult == SCIP_SEPARATED )
3759 {
3760 subprobresult = cutresult;
3761
3762 benders->ncutsfound++;
3763
3764 /* at most a single cut is generated for each subproblem */
3765 break;
3766 }
3767 else
3768 {
3769 /* checking from lowest priority result */
3770 if( subprobresult == SCIP_DIDNOTRUN )
3771 subprobresult = cutresult;
3772 else if( subprobresult == SCIP_FEASIBLE && cutresult == SCIP_DIDNOTFIND )
3773 subprobresult = cutresult;
3774 /* if the subprobresult is SCIP_DIDNOTFIND, then it can't be updated. */
3775 }
3776 }
3777
3778 /* the highest priority for the results is CONSADDED and SEPARATED. The solveloopresult will always be
3779 * updated if the subprobresult is either of these.
3780 */
3781 if( subprobresult == SCIP_CONSADDED || subprobresult == SCIP_SEPARATED )
3782 {
3783 solveloopresult = subprobresult;
3784 }
3785 else if( subprobresult == SCIP_FEASIBLE )
3786 {
3787 /* updating the solve loop result based upon the priority */
3788 if( solveloopresult == SCIP_DIDNOTRUN )
3789 solveloopresult = subprobresult;
3790 }
3791 else if( subprobresult == SCIP_DIDNOTFIND )
3792 {
3793 /* updating the solve loop result based upon the priority */
3794 if( solveloopresult == SCIP_DIDNOTRUN || solveloopresult == SCIP_FEASIBLE )
3795 solveloopresult = subprobresult;
3796
3797 /* since a cut was not found, then merging could be useful to avoid this in subsequent iterations. The
3798 * candidate is labelled as a non-priority merge candidate
3799 */
3800 if( substatus[i] != SCIP_BENDERSSUBSTATUS_OPTIMAL )
3801 {
3802 (*mergecands)[(*nmergecands)] = i;
3803 (*nmergecands)++;
3804 }
3805 }
3806 else if( subprobresult == SCIP_DIDNOTRUN )
3807 {
3808 /* if the subproblem is infeasible and no cut generation methods were run, then the infeasibility will
3809 * never be resolved. As such, the subproblem will be merged into the master problem. If the subproblem
3810 * was not infeasible, then it is added as a possible merge candidate
3811 */
3812 if( substatus[i] == SCIP_BENDERSSUBSTATUS_INFEAS )
3813 {
3814 (*mergecands)[(*nmergecands)] = (*mergecands)[(*npriomergecands)];
3815 (*mergecands)[(*npriomergecands)] = i;
3816 (*npriomergecands)++;
3817 (*nmergecands)++;
3818 }
3819 else if( substatus[i] != SCIP_BENDERSSUBSTATUS_OPTIMAL )
3820 {
3821 (*mergecands)[(*nmergecands)] = i;
3822 (*nmergecands)++;
3823 }
3824 }
3825 }
3826 }
3827 }
3828
3829 /* updating the overall result based upon the priorities */
3830 if( solveloopresult == SCIP_CONSADDED || solveloopresult == SCIP_SEPARATED )
3831 {
3832 (*result) = solveloopresult;
3833 }
3834 else if( solveloopresult == SCIP_FEASIBLE )
3835 {
3836 /* updating the solve loop result based upon the priority */
3837 if( (*result) == SCIP_DIDNOTRUN )
3838 (*result) = solveloopresult;
3839 }
3840 else if( solveloopresult == SCIP_DIDNOTFIND )
3841 {
3842 /* updating the solve loop result based upon the priority */
3843 if( (*result) == SCIP_DIDNOTRUN || (*result) == SCIP_FEASIBLE )
3844 (*result) = solveloopresult;
3845 }
3846
3847 /* if no cuts were added, then the number of solve loops is increased */
3848 if( addedcuts == 0 && SCIPbendersGetNConvexSubproblems(benders) < SCIPbendersGetNSubproblems(benders)
3849 && checkint && !onlyconvexcheck )
3850 (*nsolveloops) = 2;
3851
3852 return SCIP_OKAY;
3853}
3854
3855/** Solves the subproblem using the current master problem solution.
3856 *
3857 * The checkint flag indicates whether integer feasibility can be assumed. If it is not assumed, i.e. checkint ==
3858 * FALSE, then only the convex relaxations of the subproblems are solved. If integer feasibility is assumed, i.e.
3859 * checkint == TRUE, then the convex relaxations and the full CIP are solved to generate Benders' cuts and check
3860 * solution feasibility.
3861 *
3862 * TODO: consider allowing the possibility to pass solution information back from the subproblems instead of the scip
3863 * instance. This would allow the use of different solvers for the subproblems, more importantly allowing the use of an
3864 * LP solver for LP subproblems.
3865 */
3867 SCIP_BENDERS* benders, /**< Benders' decomposition */
3868 SCIP_SET* set, /**< global SCIP settings */
3869 SCIP_SOL* sol, /**< primal CIP solution */
3870 SCIP_RESULT* result, /**< result of the pricing process */
3871 SCIP_Bool* infeasible, /**< is the master problem infeasible with respect to the Benders' cuts? */
3872 SCIP_Bool* auxviol, /**< set to TRUE only if the solution is feasible but the aux vars are violated */
3873 SCIP_BENDERSENFOTYPE type, /**< the type of solution being enforced */
3874 SCIP_Bool checkint /**< should the integer solution be checked by the subproblems */
3875 )
3876{
3877 int nsubproblems;
3878 int subproblemcount;
3879 int nsolveloops;
3880 int nverified;
3881 int nsolved;
3882 int* mergecands;
3883 int npriomergecands;
3884 int nmergecands;
3885 int* solveidx;
3886 int* executedidx;
3887 int nsolveidx;
3888 int nexecutedidx;
3889 int nfree;
3890 SCIP_Bool* subprobsolved;
3891 SCIP_BENDERSSUBSTATUS* substatus;
3892 SCIP_Bool optimal;
3893 SCIP_Bool allverified;
3894 SCIP_Bool success;
3895 SCIP_Bool stopped;
3896 int i;
3897 int l;
3898
3899 success = TRUE;
3900 stopped = FALSE;
3901
3902 SCIPsetDebugMsg(set, "Starting Benders' decomposition subproblem solving. type %d checkint %u\n", type, checkint);
3903
3904#ifdef SCIP_MOREDEBUG
3905 SCIP_CALL( SCIPprintSol(set->scip, sol, NULL, FALSE) );
3906#endif
3907
3908 /* start timing */
3909 SCIPclockStart(benders->bendersclock, set);
3910
3911 nsubproblems = SCIPbendersGetNSubproblems(benders);
3912
3913 (*auxviol) = FALSE;
3914 (*infeasible) = FALSE;
3915
3916 /* It is assumed that the problem is optimal, until a subproblem is found not to be optimal. However, not all
3917 * subproblems could be checked in each iteration. As such, it is not possible to state that the problem is optimal
3918 * if not all subproblems are checked. Situations where this may occur is when a subproblem is a MIP and only the LP
3919 * is solved. Also, in a distributed computation, then it may be advantageous to only solve some subproblems before
3920 * resolving the master problem. As such, for a problem to be optimal, then (optimal && allverified) == TRUE
3921 */
3922 optimal = TRUE;
3923 nverified = 0;
3924 nsolved = 0;
3925
3926 assert(benders != NULL);
3927 assert(result != NULL);
3928 assert(infeasible != NULL);
3929 assert(auxviol != NULL);
3930
3931 /* if the Benders' decomposition is called from a sub-SCIP and the sub-SCIPs have been deactivated, then it is
3932 * assumed that this is an LNS heuristic. As such, the check is not performed and the solution is assumed to be
3933 * feasible
3934 */
3935 if( benders->iscopy && set->subscipsoff
3936 && (!benders->lnscheck
3937 || (benders->lnsmaxdepth > -1 && SCIPgetDepth(benders->sourcescip) >= benders->lnsmaxdepth)
3938 || (benders->lnsmaxcalls > -1 && SCIPbendersGetNCalls(benders) >= benders->lnsmaxcalls)
3939 || (type != SCIP_BENDERSENFOTYPE_CHECK && SCIPgetDepth(set->scip) == 0 && benders->lnsmaxcallsroot > -1
3940 && SCIPbendersGetNCalls(benders) >= benders->lnsmaxcallsroot)) )
3941 {
3942 (*result) = SCIP_DIDNOTRUN;
3943 return SCIP_OKAY;
3944 }
3945
3946 /* it is not necessary to check all primal solutions by solving the Benders' decomposition subproblems.
3947 * Only the improving solutions are checked to improve efficiency of the algorithm.
3948 * If the solution is non-improving, the result FEASIBLE is returned. While this may be incorrect w.r.t to the
3949 * Benders' subproblems, this solution will never be the optimal solution. A non-improving solution may be used
3950 * within LNS primal heuristics. If this occurs, the improving solution, if found, will be checked by the solving
3951 * the Benders' decomposition subproblems.
3952 * TODO: Add a parameter to control this behaviour.
3953 */
3954 if( checkint && SCIPsetIsLE(set, SCIPgetPrimalbound(set->scip)*(int)SCIPgetObjsense(set->scip),
3955 SCIPgetSolOrigObj(set->scip, sol)*(int)SCIPgetObjsense(set->scip)) )
3956 {
3957 (*result) = SCIP_DIDNOTRUN;
3958 return SCIP_OKAY;
3959 }
3960
3961 /* if the enforcement type is SCIP_BENDERSENFOTYPE_LP and the LP is currently unbounded. This could mean that there
3962 * is no lower bound on the auxiliary variables. In this case, we try to update the lower bound for the auxiliary
3963 * variables.
3964 */
3966 && benders->updateauxvarbound )
3967 {
3968 SCIP_CALL( updateAuxiliaryVarLowerbound(benders, set, result) );
3969
3970 /* the auxiliary variable bound will only be updated once. */
3971 benders->updateauxvarbound = FALSE;
3972 }
3973
3974 /* sets the stored objective function values of the subproblems to infinity */
3976
3977 *result = SCIP_DIDNOTRUN;
3978
3979 if( benders->benderspresubsolve != NULL && !benders->strengthenround )
3980 {
3981 SCIP_Bool skipsolve;
3982
3983 skipsolve = FALSE;
3984 SCIP_CALL( benders->benderspresubsolve(set->scip, benders, sol, type, checkint, infeasible, auxviol, &skipsolve,
3985 result) );
3986
3987 /* evaluate result */
3988 if( (*result) != SCIP_DIDNOTRUN
3989 && (*result) != SCIP_FEASIBLE
3990 && (*result) != SCIP_INFEASIBLE
3991 && (*result) != SCIP_CONSADDED
3992 && (*result) != SCIP_SEPARATED )
3993 {
3994 SCIPerrorMessage("the user-defined pre subproblem solving method for the Benders' decomposition <%s> returned "
3995 "invalid result <%d>\n", benders->name, *result);
3996 return SCIP_INVALIDRESULT;
3997 }
3998
3999 /* if the solve must be skipped, then the solving loop is exited and the user defined result is returned */
4000 if( skipsolve )
4001 {
4002 SCIPsetDebugMsg(set, "skipping the subproblem solving for Benders' decomposition <%s>. "
4003 "returning result <%d>\n", benders->name, *result);
4004 return SCIP_OKAY;
4005 }
4006 }
4007
4008 /* the cut strengthening is performed before the regular subproblem solve is called. To avoid recursion, the flag
4009 * strengthenround is set to TRUE when the cut strengthening is performed. The cut strengthening is not performed as
4010 * part of the large neighbourhood Benders' search.
4011 *
4012 * NOTE: cut strengthening is only applied for fractional solutions and integer solutions if there are no CIP
4013 * subproblems.
4014 */
4015 if( benders->strengthenenabled && !benders->strengthenround && !benders->iscopy
4016 && (!checkint || SCIPbendersGetNConvexSubproblems(benders) == SCIPbendersGetNSubproblems(benders)) )
4017 {
4018 SCIP_Bool skipsolve;
4019
4020 benders->strengthenround = TRUE;
4021 /* if the user has not requested the solve to be skipped, then the cut strengthening is performed */
4022 SCIP_CALL( performInteriorSolCutStrengthening(benders, set, sol, type, checkint, FALSE, infeasible, auxviol,
4023 &skipsolve, result) );
4024 benders->strengthenround = FALSE;
4025
4026 /* if the solve must be skipped, then the solving loop is exited and the user defined result is returned */
4027 if( skipsolve )
4028 {
4029 SCIPsetDebugMsg(set, "skipping the subproblem solving because cut strengthening found a cut "
4030 "for Benders' decomposition <%s>. Returning result <%d>\n", benders->name, *result);
4031 return SCIP_OKAY;
4032 }
4033
4034 /* the result flag need to be reset to DIDNOTRUN for the main subproblem solve */
4035 (*result) = SCIP_DIDNOTRUN;
4036 }
4037
4038 /* allocating memory for the infeasible subproblem array */
4039 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &subprobsolved, nsubproblems) );
4040 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &substatus, nsubproblems) );
4041 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &mergecands, nsubproblems) );
4042 npriomergecands = 0;
4043 nmergecands = 0;
4044
4045 /* allocating the memory for the subproblem solving and cut generation indices */
4046 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &solveidx, nsubproblems) );
4047 SCIP_CALL( SCIPallocClearBlockMemoryArray(set->scip, &executedidx, nsubproblems) );
4048 nsolveidx = 0;
4049 nexecutedidx = 0;
4050
4051 /* only a subset of the subproblems are initially solved. Both solving loops are executed for the subproblems to
4052 * check whether any cuts are generated. If a cut is generated, then no further subproblems are solved. If a cut is
4053 * not generated, then an additional set of subproblems are solved.
4054 */
4055 while( nsolved < nsubproblems )
4056 {
4057 /* getting the indices for the subproblems that will be solved */
4058 createSolveSubproblemIndexList(benders, set, type, &solveidx, &nsolveidx);
4059
4060 /* by default the number of solve loops is 1. This is the case if all subproblems are LP or the user has defined a
4061 * benderssolvesub callback. If there is a subproblem that is not an LP, then 2 solve loops are performed. The first
4062 * loop is the LP solving loop, the second solves the subproblem to integer optimality.
4063 */
4064 nsolveloops = 1;
4065
4066 for( l = 0; l < nsolveloops; l++ )
4067 {
4068 SCIP_BENDERSSOLVELOOP solveloop; /* identifies what problem type is solve in this solve loop */
4069
4070 /* if either benderssolvesubconvex or benderssolvesub are implemented, then the user callbacks are invoked */
4071 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL )
4072 {
4073 if( l == 0 )
4075 else
4077 }
4078 else
4079 solveloop = (SCIP_BENDERSSOLVELOOP) l;
4080
4081 /* solving the subproblems for this round of enforcement/checking. */
4082 SCIP_CALL( solveBendersSubproblems(benders, set, sol, type, solveloop, checkint, &nverified,
4083 solveidx, nsolveidx, &subprobsolved, &substatus, infeasible, &optimal, &stopped) );
4084
4085 /* if the solving has been stopped, then the subproblem solving and cut generation must terminate */
4086 if( stopped )
4087 break;
4088
4089 /* Generating cuts for the subproblems. Cuts are only generated when the solution is from primal heuristics,
4090 * relaxations or the LP
4091 */
4092 if( type != SCIP_BENDERSENFOTYPE_PSEUDO )
4093 {
4094 SCIP_CALL( generateBendersCuts(benders, set, sol, result, type, solveloop, checkint, subprobsolved,
4095 substatus, solveidx, nsolveidx, &mergecands, &npriomergecands, &nmergecands, &nsolveloops) );
4096 }
4097 else
4098 {
4099 /* The first solving loop solves the convex subproblems and the convex relaxations of the CIP subproblems. The
4100 * second solving loop solves the CIP subproblems. The second solving loop is only called if the integer
4101 * feasibility is being checked and if the convex subproblems and convex relaxations are not infeasible.
4102 */
4103 if( !(*infeasible) && checkint && !SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set))
4105 nsolveloops = 2;
4106 }
4107 }
4108
4109 nsolved += nsolveidx;
4110
4111 /* storing the indices of the subproblems for which the solving loop was executed */
4112 for( i = 0; i < nsolveidx; i++ )
4113 executedidx[nexecutedidx++] = solveidx[i];
4114
4115 /* if the result is CONSADDED or SEPARATED, then a cut is generated and no further subproblem processing is
4116 * required
4117 */
4118 if( (*result) == SCIP_CONSADDED || (*result) == SCIP_SEPARATED )
4119 break;
4120 }
4121
4122 /* inserting the subproblems into the priority queue for the next solve call */
4123 SCIP_CALL( updateSubproblemStatQueue(benders, executedidx, nexecutedidx, TRUE) );
4124
4125 if( stopped ) /*lint !e774*/
4126 goto TERMINATE;
4127
4128 allverified = (nverified == nsubproblems);
4129
4130 SCIPsetDebugMsg(set, "End Benders' decomposition subproblem solve. result %d infeasible %u auxviol %u nverified %d\n",
4131 *result, *infeasible, *auxviol, nverified);
4132
4133#ifdef SCIP_DEBUG
4134 if( (*result) == SCIP_CONSADDED )
4135 {
4136 SCIPsetDebugMsg(set, "Benders' decomposition: Cut added\n");
4137 }
4138#endif
4139
4140 /* if the number of checked pseudo solutions exceeds a set limit, then all subproblems are passed as merge
4141 * candidates. Currently, merging subproblems into the master problem is the only method for resolving numerical
4142 * troubles.
4143 *
4144 * We are only interested in the pseudo solutions that have been checked completely for integrality. This is
4145 * identified by checkint == TRUE. This means that the Benders' decomposition constraint is one of the last
4146 * constraint handlers that must resolve the infeasibility. If the Benders' decomposition framework can't resolve the
4147 * infeasibility, then this will result in an error.
4148 */
4149 if( type == SCIP_BENDERSENFOTYPE_PSEUDO && checkint )
4150 {
4151 benders->npseudosols++;
4152
4153 if( benders->npseudosols > BENDERS_MAXPSEUDOSOLS )
4154 {
4155 /* if a priority merge candidate already exists, then no other merge candidates need to be added.*/
4156 if( npriomergecands == 0 )
4157 {
4158 /* all subproblems are added to the merge candidate list. The first active subproblem is added as a
4159 * priority merge candidate
4160 */
4161 nmergecands = 0;
4162 npriomergecands = 1;
4163 for( i = 0; i < nsubproblems; i++ )
4164 {
4165 /* only active subproblems are added to the merge candidate list */
4166 if( subproblemIsActive(benders, i) )
4167 {
4168 mergecands[nmergecands] = i;
4169 nmergecands++;
4170 }
4171 }
4172
4173 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_HIGH, NULL, " The number of checked pseudo solutions exceeds the "
4174 "limit of %d. All active subproblems are merge candidates, with subproblem %d a priority candidate.\n",
4175 BENDERS_MAXPSEUDOSOLS, mergecands[0]);
4176 }
4177 }
4178 }
4179 else
4180 benders->npseudosols = 0;
4181
4182 /* if the result is SCIP_DIDNOTFIND, then there was a error in generating cuts in all subproblems that are not
4183 * optimal. This result does not cutoff any solution, so the Benders' decomposition algorithm will fail.
4184 *
4185 * It could happen that the cut strengthening approach causes an error the cut generation. In this case, an error
4186 * should not be thrown. So, this check will be skipped when in a strengthening round.
4187 * TODO: Work out a way to ensure Benders' decomposition does not terminate due to a SCIP_DIDNOTFIND result.
4188 */
4189 if( (*result) == SCIP_DIDNOTFIND && !benders->strengthenround )
4190 {
4191 if( type == SCIP_BENDERSENFOTYPE_PSEUDO )
4192 (*result) = SCIP_SOLVELP;
4193 else
4194 (*result) = SCIP_INFEASIBLE;
4195
4196 SCIPerrorMessage("An error was found when generating cuts for non-optimal subproblems of Benders' "
4197 "decomposition <%s>. Consider merging the infeasible subproblems into the master problem.\n", SCIPbendersGetName(benders));
4198
4199 /* since no other cuts are generated, then this error will result in a crash. It is possible to avoid the error,
4200 * by merging the affected subproblem into the master problem.
4201 *
4202 * NOTE: If the error occurs while checking solutions, i.e. SCIP_BENDERSENFOTYPE_CHECK, then it is valid to set
4203 * the result to SCIP_INFEASIBLE and the success flag to TRUE
4204 */
4205 if( type != SCIP_BENDERSENFOTYPE_CHECK )
4206 success = FALSE;
4207
4208 goto POSTSOLVE;
4209 }
4210
4211 if( type == SCIP_BENDERSENFOTYPE_PSEUDO )
4212 {
4213 if( (*infeasible) || !allverified )
4214 (*result) = SCIP_SOLVELP;
4215 else
4216 {
4217 (*result) = SCIP_FEASIBLE;
4218
4219 /* if the subproblems are not infeasible, but they are also not optimal. This means that there is a violation
4220 * in the auxiliary variable values. In this case, a feasible result is returned with the auxviol flag set to
4221 * TRUE.
4222 */
4223 (*auxviol) = !optimal;
4224 }
4225 }
4226 else if( checkint && (type == SCIP_BENDERSENFOTYPE_CHECK
4227 || ((*result) != SCIP_CONSADDED && (*result) != SCIP_SEPARATED)) )
4228 {
4229 /* if the subproblems are being solved as part of conscheck, then the results flag must be returned after the solving
4230 * has completed.
4231 */
4232 if( (*infeasible) || !allverified )
4233 (*result) = SCIP_INFEASIBLE;
4234 else
4235 {
4236 (*result) = SCIP_FEASIBLE;
4237
4238 /* if the subproblems are not infeasible, but they are also not optimal. This means that there is a violation
4239 * in the auxiliary variable values. In this case, a feasible result is returned with the auxviol flag set to
4240 * TRUE.
4241 */
4242 (*auxviol) = !optimal;
4243 }
4244 }
4245
4246POSTSOLVE:
4247 /* calling the post-solve call back for the Benders' decomposition algorithm. This allows the user to work directly
4248 * with the solved subproblems and the master problem */
4249 if( benders->benderspostsolve != NULL )
4250 {
4251 SCIP_Bool merged;
4252
4253 merged = FALSE;
4254
4255 SCIP_CALL( benders->benderspostsolve(set->scip, benders, sol, type, mergecands, npriomergecands, nmergecands,
4256 checkint, (*infeasible), &merged) );
4257
4258 if( merged )
4259 {
4260 (*result) = SCIP_CONSADDED;
4261
4262 /* since subproblems have been merged, then constraints have been added. This could resolve the unresolved
4263 * infeasibility, so the error has been corrected.
4264 */
4265 success = TRUE;
4266 }
4267 else if( !success )
4268 {
4269 SCIPerrorMessage("An error occurred during Benders' decomposition cut generations and no merging had been "
4270 "performed. It is not possible to continue solving the problem by Benders' decomposition\n");
4271 }
4272 }
4273
4274TERMINATE:
4275 /* if the solving process has stopped, then all subproblems need to be freed */
4276 if( stopped ) /*lint !e774*/
4277 nfree = nsubproblems;
4278 else
4279 nfree = nexecutedidx;
4280
4281 /* freeing the subproblems after the cuts are generated */
4282 subproblemcount = 0;
4283 while( subproblemcount < nfree )
4284 {
4285 int subidx;
4286
4287 if( stopped )
4288 subidx = subproblemcount;
4289 else
4290 subidx = executedidx[subproblemcount];
4291
4292 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, subidx) );
4293
4294 subproblemcount++;
4295 }
4296
4297#ifndef NDEBUG
4298 for( i = 0; i < nsubproblems; i++ )
4299 assert(SCIPbendersSubproblem(benders, i) == NULL
4301 || !SCIPinProbing(SCIPbendersSubproblem(benders, i))
4302 || !subproblemIsActive(benders, i));
4303#endif
4304
4305 /* increment the number of calls to the Benders' decomposition subproblem solve */
4306 benders->ncalls++;
4307
4308 SCIPsetDebugMsg(set, "End Benders' decomposition execution method. result %d infeasible %u auxviol %u\n", *result,
4309 *infeasible, *auxviol);
4310
4311 /* end timing */
4312 SCIPclockStop(benders->bendersclock, set);
4313
4314 /* freeing memory */
4315 SCIPfreeBlockMemoryArray(set->scip, &executedidx, nsubproblems);
4316 SCIPfreeBlockMemoryArray(set->scip, &solveidx, nsubproblems);
4317 SCIPfreeBlockMemoryArray(set->scip, &mergecands, nsubproblems);
4318 SCIPfreeBlockMemoryArray(set->scip, &substatus, nsubproblems);
4319 SCIPfreeBlockMemoryArray(set->scip, &subprobsolved, nsubproblems);
4320
4321 /* if there was an error in generating cuts and merging was not performed, then the solution is perturbed in an
4322 * attempt to generate a cut and correct the infeasibility
4323 */
4324 if( !success && !stopped )
4325 {
4326 SCIP_Bool skipsolve;
4327 SCIP_RESULT perturbresult;
4328
4329 skipsolve = FALSE;
4330
4331 benders->strengthenround = TRUE;
4332 /* if the user has not requested the solve to be skipped, then the cut strengthening is performed */
4333 SCIP_CALL( performInteriorSolCutStrengthening(benders, set, sol, type, checkint, TRUE, infeasible, auxviol,
4334 &skipsolve, &perturbresult) );
4335 benders->strengthenround = FALSE;
4336
4337 if( perturbresult == SCIP_CONSADDED || perturbresult == SCIP_SEPARATED )
4338 (*result) = perturbresult;
4339
4340 success = skipsolve;
4341 }
4342
4343 /* if the Benders' decomposition subproblem check stopped, then we don't have a valid result. In this case, the
4344 * safest thing to do is report INFEASIBLE.
4345 */
4346 if( stopped )
4347 (*result) = SCIP_INFEASIBLE;
4348
4349 /* if the subproblem verification identifies the solution as feasible, then a check whether slack variables have been
4350 * used is necessary. If any slack variables are non-zero, then the solution is reverified after the objective
4351 * coefficient for the slack variables is increased.
4352 */
4353 if( (*result) == SCIP_FEASIBLE )
4354 {
4355 SCIP_Bool activeslack;
4356
4357 SCIP_CALL( SCIPbendersSolSlackVarsActive(benders, &activeslack) );
4358 SCIPsetDebugMsg(set, "Type: %d Active slack: %u Feasibility Phase: %u\n", type, activeslack,
4359 benders->feasibilityphase);
4360 if( activeslack )
4361 {
4362 if( type == SCIP_BENDERSENFOTYPE_CHECK )
4363 (*result) = SCIP_INFEASIBLE;
4364 else
4365 {
4366 /* increasing the value of the slack variable by a factor of 10 */
4367 benders->slackvarcoef *= 10.0;
4368
4369 if( benders->slackvarcoef <= benders->maxslackvarcoef )
4370 {
4371 SCIPmessagePrintVerbInfo(SCIPgetMessagehdlr(set->scip), set->disp_verblevel, SCIP_VERBLEVEL_HIGH, "Increasing the slack variable coefficient to %g.\n", benders->slackvarcoef);
4372 }
4373 else
4374 {
4375 SCIPmessagePrintVerbInfo(SCIPgetMessagehdlr(set->scip), set->disp_verblevel, SCIP_VERBLEVEL_HIGH, "Fixing the slack variables to zero.\n");
4376 }
4377
4378 /* resolving the subproblems with an increased slack variable */
4379 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sol, result, infeasible, auxviol, type, checkint) );
4380 }
4381 }
4382 else if( benders->feasibilityphase )
4383 {
4384 if( type != SCIP_BENDERSENFOTYPE_CHECK )
4385 {
4386 /* disabling the feasibility phase */
4387 benders->feasibilityphase = FALSE;
4388
4389 /* resolving the subproblems with the slack variables set to zero */
4390 SCIP_CALL( SCIPsolveBendersSubproblems(set->scip, benders, sol, result, infeasible, auxviol, type, checkint) );
4391 }
4392 }
4393 }
4394
4395 if( !success )
4396 return SCIP_ERROR;
4397 else
4398 return SCIP_OKAY;
4399}
4400
4401/** solves the user-defined subproblem solving function */
4402static
4404 SCIP_BENDERS* benders, /**< Benders' decomposition */
4405 SCIP_SET* set, /**< global SCIP settings */
4406 SCIP_SOL* sol, /**< primal CIP solution */
4407 int probnumber, /**< the subproblem number */
4408 SCIP_BENDERSSOLVELOOP solveloop, /**< the solve loop iteration. The first iter is for LP, the second for IP */
4409 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
4410 SCIP_Real* objective, /**< the objective function value of the subproblem */
4411 SCIP_RESULT* result /**< the result from solving the subproblem */
4412 )
4413{
4414 assert(benders != NULL);
4415 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
4416 assert(benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL);
4417
4418 assert(solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP);
4419
4420 (*objective) = -SCIPsetInfinity(set);
4421
4422 /* calls the user defined subproblem solving method. Only the convex relaxations are solved during the Large
4423 * Neighbourhood Benders' Search. */
4424 if( solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX )
4425 {
4426 if( benders->benderssolvesubconvex != NULL )
4427 {
4428 SCIP_CALL( benders->benderssolvesubconvex(set->scip, benders, sol, probnumber,
4429 SCIPbendersOnlyCheckConvexRelax(benders, SCIPsetGetSubscipsOff(set)), objective, result) );
4430 }
4431 else
4432 (*result) = SCIP_DIDNOTRUN;
4433 }
4434 else if( solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
4435 {
4436 if( benders->benderssolvesub != NULL )
4437 {
4438 SCIP_CALL( benders->benderssolvesub(set->scip, benders, sol, probnumber, objective, result) );
4439 }
4440 else
4441 (*result) = SCIP_DIDNOTRUN;
4442 }
4443
4444 /* evaluate result */
4445 if( (*result) != SCIP_DIDNOTRUN
4446 && (*result) != SCIP_FEASIBLE
4447 && (*result) != SCIP_INFEASIBLE
4448 && (*result) != SCIP_UNBOUNDED )
4449 {
4450 SCIPerrorMessage("the user-defined solving method for the Benders' decomposition <%s> returned invalid result <%d>\n",
4451 benders->name, *result);
4452 return SCIP_INVALIDRESULT;
4453 }
4454
4455 if( (*result) == SCIP_INFEASIBLE )
4456 (*infeasible) = TRUE;
4457
4458 if( (*result) == SCIP_FEASIBLE
4459 && (SCIPsetIsInfinity(set, -(*objective)) || SCIPsetIsInfinity(set, (*objective))) )
4460 {
4461 SCIPerrorMessage("the user-defined solving method for the Benders' decomposition <%s> returned objective value %g\n",
4462 benders->name, (*objective));
4463 return SCIP_ERROR;
4464 }
4465
4466 /* if the result is SCIP_DIDNOTFIND, then an error is returned and SCIP will terminate. */
4467 if( (*result) == SCIP_DIDNOTFIND )
4468 return SCIP_ERROR;
4469 else
4470 return SCIP_OKAY;
4471}
4473/** executes the subproblem solving process */
4475 SCIP_BENDERS* benders, /**< Benders' decomposition */
4476 SCIP_SET* set, /**< global SCIP settings */
4477 SCIP_SOL* sol, /**< primal CIP solution */
4478 int probnumber, /**< the subproblem number */
4479 SCIP_BENDERSSOLVELOOP solveloop, /**< the solve loop iteration. The first iter is for LP, the second for IP */
4480 SCIP_Bool enhancement, /**< is the solve performed as part of and enhancement? */
4481 SCIP_Bool* solved, /**< flag to indicate whether the subproblem was solved */
4482 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
4483 SCIP_BENDERSENFOTYPE type /**< the enforcement type calling this function */
4484 )
4485{ /*lint --e{715}*/
4486 SCIP* subproblem;
4487 SCIP_RESULT result;
4488 SCIP_Real objective;
4489 SCIP_STATUS solvestatus = SCIP_STATUS_UNKNOWN;
4490
4491 assert(benders != NULL);
4492 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
4493
4494 SCIPsetDebugMsg(set, "Benders' decomposition: solving subproblem %d\n", probnumber);
4495
4496 result = SCIP_DIDNOTRUN;
4497 objective = SCIPsetInfinity(set);
4498
4499 subproblem = SCIPbendersSubproblem(benders, probnumber);
4500
4501 if( subproblem == NULL && (benders->benderssolvesubconvex == NULL || benders->benderssolvesub == NULL) )
4502 {
4503 SCIPerrorMessage("The subproblem %d is set to NULL, but both bendersSolvesubconvex%s and bendersSolvesub%s "
4504 "are not defined.\n", probnumber, benders->name, benders->name);
4505 SCIPABORT();
4506 return SCIP_ERROR;
4507 }
4508
4509 /* initially setting the solved flag to FALSE */
4510 (*solved) = FALSE;
4511
4512 /* if the subproblem solve callback is implemented, then that is used instead of the default setup */
4513 if( solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP )
4514 {
4515 /* calls the user defined subproblem solving method. Only the convex relaxations are solved during the Large
4516 * Neighbourhood Benders' Search. */
4517 SCIP_CALL( executeUserDefinedSolvesub(benders, set, sol, probnumber, solveloop, infeasible, &objective, &result) );
4518
4519 /* if the result is DIDNOTRUN, then the subproblem was not solved */
4520 (*solved) = (result != SCIP_DIDNOTRUN);
4521 }
4522 else if( subproblem != NULL )
4523 {
4524 /* setting up the subproblem */
4525 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX )
4526 {
4527 SCIP_CALL( SCIPbendersSetupSubproblem(benders, set, sol, probnumber, type) );
4528
4529 /* if the limits of the master problem were hit during the setup process, then the subproblem will not have
4530 * been setup. In this case, the solving function must be exited.
4531 */
4532 if( !SCIPbendersSubproblemIsSetup(benders, probnumber) )
4533 {
4534 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
4535 (*solved) = FALSE;
4536 return SCIP_OKAY;
4537 }
4538 }
4539 else
4540 {
4541 SCIP_CALL( updateEventhdlrUpperbound(benders, probnumber, SCIPbendersGetAuxiliaryVarVal(benders, set, sol, probnumber)) );
4542 }
4543
4544 /* solving the subproblem
4545 * the LP of the subproblem is solved in the first solveloop.
4546 * In the second solve loop, the MIP problem is solved */
4547 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX
4549 {
4550 SCIP_CALL( SCIPbendersSolveSubproblemLP(set->scip, benders, probnumber, &solvestatus, &objective) );
4551
4552 /* if the (N)LP was solved without error, then the subproblem is labelled as solved */
4553 if( solvestatus == SCIP_STATUS_OPTIMAL || solvestatus == SCIP_STATUS_INFEASIBLE )
4554 (*solved) = TRUE;
4555
4556 if( solvestatus == SCIP_STATUS_INFEASIBLE )
4557 (*infeasible) = TRUE;
4558 }
4559 else
4560 {
4561 SCIP_SOL* bestsol;
4562
4563 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, FALSE) );
4564
4565 if( solvestatus == SCIP_STATUS_INFEASIBLE )
4566 (*infeasible) = TRUE;
4567
4568 /* if the generic subproblem solving methods are used, then the CIP subproblems are always solved. */
4569 (*solved) = TRUE;
4570
4571 bestsol = SCIPgetBestSol(subproblem);
4572 if( bestsol != NULL )
4573 objective = SCIPgetSolOrigObj(subproblem, bestsol)*(int)SCIPgetObjsense(set->scip);
4574 else
4575 objective = SCIPsetInfinity(set);
4576 }
4577 }
4578 else
4579 {
4580 SCIPABORT();
4581 }
4582
4583 if( !enhancement )
4584 {
4585 /* The following handles the cases when the subproblem is OPTIMAL, INFEASIBLE and UNBOUNDED.
4586 * If a subproblem is unbounded, then the auxiliary variables are set to -infinity and the unbounded flag is
4587 * returned as TRUE. No cut will be generated, but the result will be set to SCIP_FEASIBLE.
4588 */
4589 if( solveloop == SCIP_BENDERSSOLVELOOP_CONVEX || solveloop == SCIP_BENDERSSOLVELOOP_CIP )
4590 {
4591 /* TODO: Consider whether other solutions status should be handled */
4592 if( solvestatus == SCIP_STATUS_OPTIMAL )
4593 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
4594 else if( solvestatus == SCIP_STATUS_INFEASIBLE )
4595 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
4596 else if( solvestatus == SCIP_STATUS_USERINTERRUPT || solvestatus == SCIP_STATUS_BESTSOLLIMIT )
4597 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
4598 else if( solvestatus == SCIP_STATUS_MEMLIMIT || solvestatus == SCIP_STATUS_TIMELIMIT
4599 || solvestatus == SCIP_STATUS_UNKNOWN )
4600 {
4601 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_FULL, NULL, " Benders' decomposition: Error solving "
4602 "subproblem %d. No cut will be generated for this subproblem.\n", probnumber);
4603 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
4604 }
4605 else if( solvestatus == SCIP_STATUS_UNBOUNDED )
4606 {
4607 SCIPerrorMessage("The Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
4608 probnumber);
4609 SCIPABORT();
4610 }
4611 else
4612 {
4613 SCIPerrorMessage("Invalid status returned from solving Benders' decomposition subproblem %d. Solution status: %d\n",
4614 probnumber, solvestatus);
4615 SCIPABORT();
4616 }
4617 }
4618 else
4619 {
4620 assert(solveloop == SCIP_BENDERSSOLVELOOP_USERCONVEX || solveloop == SCIP_BENDERSSOLVELOOP_USERCIP);
4621 if( result == SCIP_FEASIBLE )
4622 SCIPbendersSetSubproblemObjval(benders, probnumber, objective);
4623 else if( result == SCIP_INFEASIBLE )
4624 SCIPbendersSetSubproblemObjval(benders, probnumber, SCIPsetInfinity(set));
4625 else if( result == SCIP_UNBOUNDED )
4626 {
4627 SCIPerrorMessage("The Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
4628 probnumber);
4629 SCIPABORT();
4630 }
4631 else if( result != SCIP_DIDNOTRUN )
4632 {
4633 SCIPerrorMessage("Invalid result <%d> from user-defined subproblem solving method. This should not happen.\n",
4634 result);
4635 }
4636 }
4637 }
4638
4639 return SCIP_OKAY;
4640}
4642/** sets up the subproblem using the solution to the master problem */
4644 SCIP_BENDERS* benders, /**< Benders' decomposition */
4645 SCIP_SET* set, /**< global SCIP settings */
4646 SCIP_SOL* sol, /**< primal CIP solution */
4647 int probnumber, /**< the subproblem number */
4648 SCIP_BENDERSENFOTYPE type /**< the enforcement type calling this function */
4649 )
4650{
4651 SCIP* subproblem;
4652 SCIP_VAR** vars;
4653 SCIP_VAR* mastervar;
4654 SCIP_Real solval;
4655 int nvars;
4656 int i;
4657
4658 assert(benders != NULL);
4659 assert(set != NULL);
4660 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
4661
4662 subproblem = SCIPbendersSubproblem(benders, probnumber);
4663
4664 /* the subproblem setup can only be performed if the subproblem is not NULL */
4665 if( subproblem == NULL )
4666 {
4667 SCIPerrorMessage("The subproblem %d is NULL. Thus, the subproblem setup must be performed manually in either "
4668 "bendersSolvesubconvex%s or bendersSolvesub%s.\n", probnumber, benders->name, benders->name);
4669 return SCIP_ERROR;
4670 }
4671 assert(subproblem != NULL);
4672
4673 /* changing all of the master problem variable to continuous. */
4674 SCIP_CALL( SCIPbendersChgMastervarsToCont(benders, set, probnumber) );
4675
4676 /* if the Benders' decomposition subproblem is convex and has continuous variables, then probing mode
4677 * must be started.
4678 * If the subproblem contains non-convex constraints or discrete variables, then the problem must be initialised,
4679 * and then put into SCIP_STAGE_SOLVING to be able to change the variable bounds. The probing mode is entered once
4680 * the variable bounds are set.
4681 * In the latter case, the transformed problem is freed after each subproblem solve round. */
4683 {
4684 SCIP_CALL( SCIPstartProbing(subproblem) );
4685 }
4686 else
4687 {
4688 SCIP_Bool infeasible;
4689 SCIP_Bool success;
4690
4691 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, &infeasible, &success) );
4692 assert(success == !infeasible);
4693
4694 /* if the problem is identified as infeasible, this means that the underlying LP is infeasible. Since no variable
4695 * fixings have been applied at this stage, this means that the complete problem is infeasible. It is only
4696 * possible to set this parameter if we are at the root node or in an initialisation stage.
4697 */
4698 if( infeasible )
4700
4701 if( !success )
4702 {
4703 /* set the flag to indicate that the subproblems have been set up */
4704 SCIPbendersSetSubproblemIsSetup(benders, probnumber, FALSE);
4705
4706 return SCIP_OKAY;
4707 }
4708 }
4709
4710 vars = SCIPgetVars(subproblem);
4711 nvars = SCIPgetNVars(subproblem);
4712
4713 /* looping over all variables in the subproblem to find those corresponding to the master problem variables. */
4714 /* TODO: It should be possible to store the pointers to the master variables to speed up the subproblem setup */
4715 for( i = 0; i < nvars; i++ )
4716 {
4717 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
4718
4719 if( mastervar != NULL )
4720 {
4721 /* It is possible due to numerics that the solution value exceeds the upper or lower bounds. When this
4722 * happens, it causes an error in the LP solver as a result of inconsistent bounds. So the following statements
4723 * are used to ensure that the bounds are not exceeded when applying the fixings for the Benders'
4724 * decomposition subproblems
4725 */
4726 solval = SCIPgetSolVal(set->scip, sol, mastervar);
4727 if( !SCIPisLT(set->scip, solval, SCIPvarGetUbLocal(vars[i])) )
4728 solval = SCIPvarGetUbLocal(vars[i]);
4729 else if( !SCIPisGT(set->scip, solval, SCIPvarGetLbLocal(vars[i])) )
4730 solval = SCIPvarGetLbLocal(vars[i]);
4731
4732 /* fixing the variable in the subproblem */
4733 if( !SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])) )
4734 {
4735 if( SCIPisGT(subproblem, solval, SCIPvarGetLbLocal(vars[i])) )
4736 {
4737 SCIP_CALL( SCIPchgVarLb(subproblem, vars[i], solval) );
4738 }
4739 if( SCIPisLT(subproblem, solval, SCIPvarGetUbLocal(vars[i])) )
4740 {
4741 SCIP_CALL( SCIPchgVarUb(subproblem, vars[i], solval) );
4742 }
4743 }
4744
4745 assert(SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])));
4746 }
4747 else if( strstr(SCIPvarGetName(vars[i]), SLACKVAR_NAME) != NULL )
4748 {
4749 /* if the slack variables have been added to help improve feasibility, then they remain unfixed with a large
4750 * objective coefficient. Once the root node has been solved to optimality, then the slack variables are
4751 * fixed to zero.
4752 */
4753 if( benders->feasibilityphase && SCIPgetDepth(set->scip) == 0 && type != SCIP_BENDERSENFOTYPE_CHECK )
4754 {
4755 /* The coefficient update or variable fixing can only be performed if the subproblem is in probing mode.
4756 * If the slack var coef gets very large, then we fix the slack variable to 0 instead.
4757 */
4758 if( SCIPinProbing(subproblem) )
4759 {
4760 if( benders->slackvarcoef <= benders->maxslackvarcoef )
4761 {
4762 SCIP_CALL( SCIPchgVarObjProbing(subproblem, vars[i], benders->slackvarcoef) );
4763 }
4764 else
4765 {
4766 SCIP_CALL( SCIPchgVarUbProbing(subproblem, vars[i], 0.0) );
4767 }
4768 }
4769 }
4770 else
4771 {
4772 /* if the subproblem is non-linear and convex, then slack variables have been added to the subproblem. These
4773 * need to be fixed to zero when first solving the subproblem. However, if the slack variables have been added
4774 * by setting the execfeasphase runtime parameter, then they must not get fixed to zero
4775 */
4776 assert( !SCIPisEQ(subproblem, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])) );
4777 assert( SCIPisZero(subproblem, SCIPvarGetLbLocal(vars[i])) );
4778
4779 if( SCIPisLT(subproblem, 0.0, SCIPvarGetUbLocal(vars[i])) )
4780 {
4781 SCIP_CALL( SCIPchgVarUb(subproblem, vars[i], 0.0) );
4782 }
4783 }
4784 }
4785 }
4786
4787 /* if the subproblem contain non-convex constraints or discrete variables, then the probing mode is entered after
4788 * setting up the subproblem
4789 */
4791 {
4792 SCIP_CALL( SCIPstartProbing(subproblem) );
4793 }
4794
4795 /* set the flag to indicate that the subproblems have been set up */
4796 SCIPbendersSetSubproblemIsSetup(benders, probnumber, TRUE);
4797
4798 return SCIP_OKAY;
4799}
4800
4801/** Solve a Benders' decomposition subproblems. This will either call the user defined method or the generic solving
4802 * methods. If the generic method is called, then the subproblem must be set up before calling this method. */
4804 SCIP_BENDERS* benders, /**< Benders' decomposition */
4805 SCIP_SET* set, /**< global SCIP settings */
4806 SCIP_SOL* sol, /**< primal CIP solution, can be NULL */
4807 int probnumber, /**< the subproblem number */
4808 SCIP_Bool* infeasible, /**< returns whether the current subproblem is infeasible */
4809 SCIP_Bool solvecip, /**< directly solve the CIP subproblem */
4810 SCIP_Real* objective /**< the objective function value of the subproblem, can be NULL */
4811 )
4812{
4813 assert(benders != NULL);
4814 assert(set != NULL);
4815 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
4816
4817 assert(infeasible != NULL);
4818 (*infeasible) = FALSE;
4819
4820 /* the subproblem must be set up before this function is called. */
4821 if( SCIPbendersSubproblem(benders, probnumber) != NULL && !SCIPbendersSubproblemIsSetup(benders, probnumber)
4822 && !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
4823 {
4824 SCIPerrorMessage("Benders' decomposition subproblem %d must be set up before calling SCIPbendersSolveSubproblem(). Call SCIPsetupSubproblem() first.\n", probnumber);
4825 return SCIP_ERROR;
4826 }
4827
4828 /* if the subproblem solve callback is implemented, then that is used instead of the default setup */
4829 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL)
4830 {
4831 SCIP_BENDERSSOLVELOOP solveloop;
4832 SCIP_RESULT result;
4833 SCIP_Real subobj;
4834
4835 if( solvecip )
4837 else
4839
4840 SCIP_CALL( executeUserDefinedSolvesub(benders, set, sol, probnumber, solveloop, infeasible, &subobj, &result) );
4841
4842 if( objective != NULL )
4843 (*objective) = subobj;
4844 }
4845 else
4846 {
4847 SCIP* subproblem;
4848
4849 subproblem = SCIPbendersSubproblem(benders, probnumber);
4850 assert(subproblem != NULL);
4851
4852 /* solving the subproblem */
4853 if( solvecip && SCIPbendersGetSubproblemType(benders, probnumber) != SCIP_BENDERSSUBTYPE_CONVEXCONT )
4854 {
4855 SCIP_STATUS solvestatus;
4856
4857 SCIP_CALL( SCIPbendersSolveSubproblemCIP(set->scip, benders, probnumber, &solvestatus, solvecip) );
4858
4859 if( solvestatus == SCIP_STATUS_INFEASIBLE )
4860 (*infeasible) = TRUE;
4861 if( objective != NULL )
4862 (*objective) = SCIPgetSolOrigObj(subproblem, SCIPgetBestSol(subproblem))*(int)SCIPgetObjsense(subproblem);
4863 }
4864 else
4865 {
4866 SCIP_Bool success;
4867
4868 /* if the subproblem has convex constraints and continuous variables, then it should have been initialised and
4869 * in SCIP_STAGE_SOLVING. In this case, the subproblem only needs to be put into probing mode.
4870 */
4872 {
4873 /* if the subproblem is not in probing mode, then it must be put into that mode for the LP solve. */
4874 if( !SCIPinProbing(subproblem) )
4875 {
4876 SCIP_CALL( SCIPstartProbing(subproblem) );
4877 }
4878
4879 success = TRUE;
4880 }
4881 else
4882 {
4883 SCIP_CALL( initialiseSubproblem(benders, set, probnumber, infeasible, &success) );
4884 }
4885
4886 /* if setting up the subproblem was successful */
4887 if( success )
4888 {
4889 SCIP_STATUS solvestatus;
4890 SCIP_Real lpobjective;
4891
4892 SCIP_CALL( SCIPbendersSolveSubproblemLP(set->scip, benders, probnumber, &solvestatus, &lpobjective) );
4893
4894 if( solvestatus == SCIP_STATUS_INFEASIBLE )
4895 (*infeasible) = TRUE;
4896 else if( objective != NULL )
4897 (*objective) = lpobjective;
4898 }
4899 else
4900 {
4901 if( objective != NULL )
4902 (*objective) = SCIPinfinity(subproblem);
4903 }
4904 }
4905 }
4906
4907 return SCIP_OKAY;
4908}
4909
4910/** copies the time and memory limit from the master problem to the subproblem */
4911static
4913 SCIP* scip, /**< the SCIP data structure */
4914 SCIP* subproblem /**< the Benders' decomposition subproblem */
4915 )
4916{
4917 SCIP_Real mastertimelimit;
4918 SCIP_Real subtimelimit;
4919 SCIP_Real maxsubtimelimit;
4920 SCIP_Real mastermemorylimit;
4921 SCIP_Real submemorylimit;
4922 SCIP_Real maxsubmemorylimit;
4923
4924 assert(scip != NULL);
4925
4926 /* setting the time limit for the Benders' decomposition subproblems. It is set to 102% of the remaining time. */
4927 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &mastertimelimit) );
4928 maxsubtimelimit = SCIPparamGetRealMax(SCIPgetParam(subproblem, "limits/time"));
4929 subtimelimit = (mastertimelimit - SCIPgetSolvingTime(scip)) * 1.02;
4930 subtimelimit = MIN(subtimelimit, maxsubtimelimit);
4931 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", MAX(0.0, subtimelimit)) );
4932
4933 /* setting the memory limit for the Benders' decomposition subproblems. */
4934 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &mastermemorylimit) );
4935 maxsubmemorylimit = SCIPparamGetRealMax(SCIPgetParam(subproblem, "limits/memory"));
4936 submemorylimit = mastermemorylimit - (SCIPgetMemUsed(scip) + SCIPgetMemExternEstim(scip))/1048576.0;
4937 submemorylimit = MIN(submemorylimit, maxsubmemorylimit);
4938 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", MAX(0.0, submemorylimit)) );
4939
4940 return SCIP_OKAY;
4941}
4942
4943/** stores the original parameters from the subproblem */
4944static
4946 SCIP* subproblem, /**< the SCIP data structure */
4947 SCIP_SUBPROBPARAMS* origparams /**< the original subproblem parameters */
4948 )
4949{
4950 assert(subproblem != NULL);
4951 assert(origparams != NULL);
4952
4953 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/memory", &origparams->limits_memory) );
4954 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/time", &origparams->limits_time) );
4955 SCIP_CALL( SCIPgetBoolParam(subproblem, "conflict/enable", &origparams->conflict_enable) );
4956 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/disablecutoff", &origparams->lp_disablecutoff) );
4957 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/scaling", &origparams->lp_scaling) );
4958 SCIP_CALL( SCIPgetCharParam(subproblem, "lp/initalgorithm", &origparams->lp_initalg) );
4959 SCIP_CALL( SCIPgetCharParam(subproblem, "lp/resolvealgorithm", &origparams->lp_resolvealg) );
4960 SCIP_CALL( SCIPgetBoolParam(subproblem, "lp/alwaysgetduals", &origparams->lp_alwaysgetduals) );
4961 SCIP_CALL( SCIPgetBoolParam(subproblem, "misc/scaleobj", &origparams->misc_scaleobj) );
4962 SCIP_CALL( SCIPgetBoolParam(subproblem, "misc/catchctrlc", &origparams->misc_catchctrlc) );
4963 SCIP_CALL( SCIPgetIntParam(subproblem, "propagating/maxrounds", &origparams->prop_maxrounds) );
4964 SCIP_CALL( SCIPgetIntParam(subproblem, "propagating/maxroundsroot", &origparams->prop_maxroundsroot) );
4965 SCIP_CALL( SCIPgetIntParam(subproblem, "constraints/linear/propfreq", &origparams->cons_linear_propfreq) );
4966
4967 return SCIP_OKAY;
4968}
4969
4970/** sets the parameters for the subproblem */
4971static
4973 SCIP* scip, /**< the SCIP data structure */
4974 SCIP* subproblem /**< the subproblem SCIP instance */
4975 )
4976{
4977 assert(scip != NULL);
4978 assert(subproblem != NULL);
4979
4980 /* copying memory and time limits */
4981 SCIP_CALL( copyMemoryAndTimeLimits(scip, subproblem) );
4982
4983 /* Do we have to disable presolving? If yes, we have to store all presolving parameters. */
4985
4986 /* Disabling heuristics so that the problem is not trivially solved */
4988
4989 /* store parameters that are changed for the generation of the subproblem cuts */
4990 SCIP_CALL( SCIPsetBoolParam(subproblem, "conflict/enable", FALSE) );
4991
4992 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", 1) );
4993 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/scaling", 0) );
4994
4995 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/initalgorithm", 'd') );
4996 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/resolvealgorithm", 'd') );
4997
4998 SCIP_CALL( SCIPsetBoolParam(subproblem, "lp/alwaysgetduals", TRUE) );
4999 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/scaleobj", FALSE) );
5000
5001 /* do not abort subproblem on CTRL-C */
5002 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/catchctrlc", FALSE) );
5003
5004#ifndef SCIP_MOREDEBUG
5005 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_NONE) );
5006#endif
5007
5008 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxrounds", 0) );
5009 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxroundsroot", 0) );
5010
5011 SCIP_CALL( SCIPsetIntParam(subproblem, "constraints/linear/propfreq", -1) );
5012
5013 SCIP_CALL( SCIPsetIntParam(subproblem, "heuristics/alns/freq", -1) );
5014
5015 SCIP_CALL( SCIPsetIntParam(subproblem, "separating/aggregation/freq", -1) );
5016 SCIP_CALL( SCIPsetIntParam(subproblem, "separating/gomory/freq", -1) );
5017
5018 return SCIP_OKAY;
5019}
5020
5021/** resets the original parameters from the subproblem */
5022static
5024 SCIP* subproblem, /**< the SCIP data structure */
5025 SCIP_SUBPROBPARAMS* origparams /**< the original subproblem parameters */
5026 )
5027{
5028 assert(subproblem != NULL);
5029 assert(origparams != NULL);
5030
5031 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", origparams->limits_memory) );
5032 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", origparams->limits_time) );
5033 SCIP_CALL( SCIPsetBoolParam(subproblem, "conflict/enable", origparams->conflict_enable) );
5034 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", origparams->lp_disablecutoff) );
5035 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/scaling", origparams->lp_scaling) );
5036 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/initalgorithm", origparams->lp_initalg) );
5037 SCIP_CALL( SCIPsetCharParam(subproblem, "lp/resolvealgorithm", origparams->lp_resolvealg) );
5038 SCIP_CALL( SCIPsetBoolParam(subproblem, "lp/alwaysgetduals", origparams->lp_alwaysgetduals) );
5039 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/scaleobj", origparams->misc_scaleobj) );
5040 SCIP_CALL( SCIPsetBoolParam(subproblem, "misc/catchctrlc", origparams->misc_catchctrlc) );
5041 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxrounds", origparams->prop_maxrounds) );
5042 SCIP_CALL( SCIPsetIntParam(subproblem, "propagating/maxroundsroot", origparams->prop_maxroundsroot) );
5043 SCIP_CALL( SCIPsetIntParam(subproblem, "constraints/linear/propfreq", origparams->cons_linear_propfreq) );
5044
5045 return SCIP_OKAY;
5046}
5048/** returns NLP solver parameters used for solving NLP subproblems */
5050 SCIP_BENDERS* benders /**< Benders' decomposition */
5051 )
5052{
5053 assert(benders != NULL);
5054
5055 return benders->nlpparam;
5056}
5057
5058/** solves the LP of the Benders' decomposition subproblem
5059 *
5060 * This requires that the subproblem is in probing mode.
5061 */
5063 SCIP* scip, /**< the SCIP data structure */
5064 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
5065 int probnumber, /**< the subproblem number */
5066 SCIP_STATUS* solvestatus, /**< status of subproblem solve */
5067 SCIP_Real* objective /**< optimal value of subproblem, if solved to optimality */
5068 )
5069{
5070 SCIP* subproblem;
5071 SCIP_SUBPROBPARAMS* origparams;
5072 SCIP_Bool solvenlp;
5073
5074 assert(benders != NULL);
5075 assert(solvestatus != NULL);
5076 assert(objective != NULL);
5077 assert(SCIPbendersSubproblemIsSetup(benders, probnumber));
5078
5079 /* TODO: This should be solved just as an LP, so as a MIP. There is too much overhead with the MIP.
5080 * Need to change status check for checking the LP. */
5081 subproblem = SCIPbendersSubproblem(benders, probnumber);
5082 assert(subproblem != NULL);
5083
5084 /* only solve the NLP relaxation if the NLP has been constructed and there exists an NLPI. If it is not possible to
5085 * solve the NLP relaxation, then the LP relaxation is used to generate Benders' cuts
5086 */
5087 solvenlp = FALSE;
5088 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0
5090 solvenlp = TRUE;
5091
5092 *objective = SCIPinfinity(subproblem);
5093
5094 assert(SCIPisNLPConstructed(subproblem) || SCIPisLPConstructed(subproblem));
5095 assert(SCIPinProbing(subproblem));
5096
5097 /* allocating memory for the parameter storage */
5098 SCIP_CALL( SCIPallocBlockMemory(subproblem, &origparams) );
5099
5100 /* store the original parameters of the subproblem */
5101 SCIP_CALL( storeOrigSubproblemParams(subproblem, origparams) );
5102
5103 /* setting the subproblem parameters */
5104 SCIP_CALL( setSubproblemParams(scip, subproblem) );
5105
5106 if( solvenlp )
5107 {
5108 SCIP_NLPSOLSTAT nlpsolstat;
5109 SCIP_NLPTERMSTAT nlptermstat;
5110#ifdef SCIP_MOREDEBUG
5111 SCIP_SOL* nlpsol;
5112#endif
5113
5114 SCIP_CALL( SCIPsolveNLPParam(subproblem, benders->nlpparam) );
5115
5116 nlpsolstat = SCIPgetNLPSolstat(subproblem);
5117 nlptermstat = SCIPgetNLPTermstat(subproblem);
5118 SCIPdebugMsg(scip, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
5119
5120 if( nlptermstat == SCIP_NLPTERMSTAT_OKAY && (nlpsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE) )
5121 {
5122 /* trust infeasible only if terminated "okay" */
5123 (*solvestatus) = SCIP_STATUS_INFEASIBLE;
5124 }
5125 else if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT
5126 || nlpsolstat == SCIP_NLPSOLSTAT_FEASIBLE )
5127 {
5128#ifdef SCIP_MOREDEBUG
5129 SCIP_CALL( SCIPcreateNLPSol(subproblem, &nlpsol, NULL) );
5130 SCIP_CALL( SCIPprintSol(subproblem, nlpsol, NULL, FALSE) );
5131 SCIP_CALL( SCIPfreeSol(subproblem, &nlpsol) );
5132#endif
5133
5134 (*solvestatus) = SCIP_STATUS_OPTIMAL;
5135 (*objective) = SCIPretransformObj(subproblem, SCIPgetNLPObjval(subproblem));
5136 }
5137 else if( nlpsolstat == SCIP_NLPSOLSTAT_UNBOUNDED )
5138 {
5139 (*solvestatus) = SCIP_STATUS_UNBOUNDED;
5140 SCIPerrorMessage("The NLP of Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
5141 probnumber);
5142 SCIPABORT();
5143 }
5144 else if( nlptermstat == SCIP_NLPTERMSTAT_TIMELIMIT )
5145 {
5146 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
5147 }
5148 else if( nlptermstat == SCIP_NLPTERMSTAT_ITERLIMIT)
5149 {
5150 /* this is an approximation in lack of a better fitting SCIP_STATUS */
5151 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));
5152 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
5153 }
5154 else if( nlptermstat == SCIP_NLPTERMSTAT_INTERRUPT )
5155 {
5156 (*solvestatus) = SCIP_STATUS_USERINTERRUPT;
5157 }
5158 else
5159 {
5160 SCIPerrorMessage("Invalid solution status: %d. Termination status: %d. Solving the NLP relaxation of Benders' decomposition subproblem %d.\n",
5161 nlpsolstat, nlptermstat, probnumber);
5162 SCIPABORT();
5163 }
5164 }
5165 else
5166 {
5167 SCIP_Bool lperror;
5168 SCIP_Bool cutoff;
5169
5170 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
5171
5172 switch( SCIPgetLPSolstat(subproblem) )
5173 {
5175 {
5176 (*solvestatus) = SCIP_STATUS_INFEASIBLE;
5177 break;
5178 }
5179
5181 {
5182 (*solvestatus) = SCIP_STATUS_OPTIMAL;
5183 (*objective) = SCIPgetSolOrigObj(subproblem, NULL)*(int)SCIPgetObjsense(scip);
5184 break;
5185 }
5186
5188 {
5189 (*solvestatus) = SCIP_STATUS_UNBOUNDED;
5190 SCIPerrorMessage("The LP of Benders' decomposition subproblem %d is unbounded. This should not happen.\n",
5191 probnumber);
5192 SCIPABORT();
5193 break;
5194 }
5195
5199 {
5200 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_TIMELIMIT )
5201 (*solvestatus) = SCIP_STATUS_TIMELIMIT;
5202 else
5203 (*solvestatus) = SCIP_STATUS_UNKNOWN;
5204
5205 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, " Benders' decomposition: Error solving LP "
5206 "relaxation of subproblem %d. No cut will be generated for this subproblem.\n", probnumber);
5207 break;
5208 }
5209
5212 default:
5213 {
5214 SCIPerrorMessage("Invalid status: %d. Solving the LP relaxation of Benders' decomposition subproblem %d.\n",
5215 SCIPgetLPSolstat(subproblem), probnumber);
5216 SCIPABORT();
5217 break;
5218 }
5219 }
5220 }
5221
5222 /* resetting the subproblem parameters */
5223 SCIP_CALL( resetOrigSubproblemParams(subproblem, origparams) );
5224
5225 /* freeing the parameter storage */
5226 SCIPfreeBlockMemory(subproblem, &origparams);
5227
5228 return SCIP_OKAY;
5229}
5231/** solves the Benders' decomposition subproblem */
5233 SCIP* scip, /**< the SCIP data structure */
5234 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
5235 int probnumber, /**< the subproblem number */
5236 SCIP_STATUS* solvestatus, /**< status of subproblem solve */
5237 SCIP_Bool solvecip /**< directly solve the CIP subproblem */
5238 )
5239{
5240 SCIP* subproblem;
5241 SCIP_SUBPROBPARAMS* origparams;
5242
5243 assert(benders != NULL);
5244 assert(solvestatus != NULL);
5245
5246 subproblem = SCIPbendersSubproblem(benders, probnumber);
5247 assert(subproblem != NULL);
5248
5249 /* allocating memory for the parameter storage */
5250 SCIP_CALL( SCIPallocBlockMemory(subproblem, &origparams) );
5251
5252 /* store the original parameters of the subproblem */
5253 SCIP_CALL( storeOrigSubproblemParams(subproblem, origparams) );
5254
5255 /* If the solve has been stopped for the subproblem, then we need to restart it to complete the solve. The subproblem
5256 * is stopped when it is a MIP so that LP cuts and IP cuts can be generated. */
5257 if( SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING )
5258 {
5259 /* the subproblem should be in probing mode. Otherwise, the event handler did not work correctly */
5260 assert( SCIPinProbing(subproblem) );
5261
5262 /* the probing mode needs to be stopped so that the MIP can be solved */
5263 SCIP_CALL( SCIPendProbing(subproblem) );
5264
5265 /* the problem was interrupted in the event handler, so SCIP needs to be informed that the problem is to be restarted */
5266 SCIP_CALL( SCIPrestartSolve(subproblem) );
5267 }
5268 else if( solvecip )
5269 {
5270 /* if the MIP will be solved directly, then the probing mode needs to be skipped.
5271 * This is achieved by setting the solvecip flag in the event handler data to TRUE
5272 */
5273 SCIP_EVENTHDLR* eventhdlr;
5274 SCIP_EVENTHDLRDATA* eventhdlrdata;
5275
5276 eventhdlr = SCIPfindEventhdlr(subproblem, MIPNODEFOCUS_EVENTHDLR_NAME);
5277 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
5278
5279 eventhdlrdata->solvecip = TRUE;
5280 }
5281 else
5282 {
5283 /* if the problem is not in probing mode, then we need to solve the LP. That requires all methods that will
5284 * modify the structure of the problem need to be deactivated */
5285
5286 /* setting the subproblem parameters */
5287 SCIP_CALL( setSubproblemParams(scip, subproblem) );
5288
5289#ifdef SCIP_EVENMOREDEBUG
5290 SCIP_CALL( SCIPsetBoolParam(subproblem, "display/lpinfo", TRUE) );
5291#endif
5292 }
5293
5294#ifdef SCIP_MOREDEBUG
5295 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_FULL) );
5296 SCIP_CALL( SCIPsetIntParam(subproblem, "display/freq", 1) );
5297#endif
5298
5299 SCIP_CALL( SCIPsolve(subproblem) );
5300
5301 *solvestatus = SCIPgetStatus(subproblem);
5302
5303 if( *solvestatus != SCIP_STATUS_OPTIMAL && *solvestatus != SCIP_STATUS_UNBOUNDED
5304 && *solvestatus != SCIP_STATUS_INFEASIBLE && *solvestatus != SCIP_STATUS_USERINTERRUPT
5305 && *solvestatus != SCIP_STATUS_BESTSOLLIMIT && *solvestatus != SCIP_STATUS_TIMELIMIT
5306 && *solvestatus != SCIP_STATUS_MEMLIMIT )
5307 {
5308 SCIPerrorMessage("Invalid status: %d. Solving the CIP of Benders' decomposition subproblem %d.\n",
5309 *solvestatus, probnumber);
5310 SCIPABORT();
5311 }
5312
5313 /* resetting the subproblem parameters */
5314 SCIP_CALL( resetOrigSubproblemParams(subproblem, origparams) );
5315
5316 /* freeing the parameter storage */
5317 SCIPfreeBlockMemory(subproblem, &origparams);
5318
5319 return SCIP_OKAY;
5320}
5322/** frees the subproblems */
5324 SCIP_BENDERS* benders, /**< Benders' decomposition */
5325 SCIP_SET* set, /**< global SCIP settings */
5326 int probnumber /**< the subproblem number */
5327 )
5328{
5329 assert(benders != NULL);
5330 assert(benders->bendersfreesub != NULL
5331 || (benders->bendersfreesub == NULL && benders->benderssolvesubconvex == NULL && benders->benderssolvesub == NULL));
5332 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
5333
5334 if( benders->bendersfreesub != NULL )
5335 {
5336 SCIP_CALL( benders->bendersfreesub(set->scip, benders, probnumber) );
5337 }
5338 else
5339 {
5340 /* the subproblem is only freed if it is not independent */
5341 if( subproblemIsActive(benders, probnumber) )
5342 {
5343 SCIP* subproblem = SCIPbendersSubproblem(benders, probnumber);
5344
5346 {
5347 /* ending probing mode to reset the current node. The probing mode will be restarted at the next solve */
5348 if( SCIPinProbing(subproblem) )
5349 {
5350 SCIP_CALL( SCIPendProbing(subproblem) );
5351 }
5352 }
5353 else
5354 {
5355 /* if the subproblems were solved as part of an enforcement stage, then they will still be in probing mode. The
5356 * probing mode must first be finished and then the problem can be freed */
5357 if( SCIPgetStage(subproblem) >= SCIP_STAGE_TRANSFORMED && SCIPinProbing(subproblem) )
5358 {
5359 SCIP_CALL( SCIPendProbing(subproblem) );
5360 }
5361
5362 SCIP_CALL( SCIPfreeTransform(subproblem) );
5363 }
5364 }
5365 }
5366
5367 /* setting the setup flag for the subproblem to FALSE */
5368 SCIPbendersSetSubproblemIsSetup(benders, probnumber, FALSE);
5369 return SCIP_OKAY;
5370}
5372/** compares the subproblem objective value with the auxiliary variable value for optimality */
5374 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
5375 SCIP_SET* set, /**< global SCIP settings */
5376 SCIP_SOL* sol, /**< primal CIP solution */
5377 int probnumber /**< the subproblem number */
5378 )
5379{
5380 SCIP_Real auxiliaryvarval;
5381 SCIP_Bool optimal;
5382
5383 assert(benders != NULL);
5384 assert(set != NULL);
5385 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
5386
5387 optimal = FALSE;
5388
5389 auxiliaryvarval = SCIPbendersGetAuxiliaryVarVal(benders, set, sol, probnumber);
5390
5391 SCIPsetDebugMsg(set, "Subproblem %d - Auxiliary Variable: %g Subproblem Objective: %g Reldiff: %g Soltol: %g\n",
5392 probnumber, auxiliaryvarval, SCIPbendersGetSubproblemObjval(benders, probnumber),
5393 SCIPrelDiff(SCIPbendersGetSubproblemObjval(benders, probnumber), auxiliaryvarval), benders->solutiontol);
5394
5395 if( SCIPrelDiff(SCIPbendersGetSubproblemObjval(benders, probnumber), auxiliaryvarval) < benders->solutiontol )
5396 optimal = TRUE;
5397
5398 return optimal;
5399}
5401/** returns the value of the auxiliary variable value in a master problem solution */
5403 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
5404 SCIP_SET* set, /**< global SCIP settings */
5405 SCIP_SOL* sol, /**< primal CIP solution */
5406 int probnumber /**< the subproblem number */
5407 )
5408{
5409 SCIP_VAR* auxiliaryvar;
5410
5411 assert(benders != NULL);
5412 assert(set != NULL);
5413
5414 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
5415 assert(auxiliaryvar != NULL);
5416
5417 return SCIPgetSolVal(set->scip, sol, auxiliaryvar);
5418}
5419
5420/** Solves an independent subproblem to identify its lower bound. The lower bound is then used to update the bound on
5421 * the auxiliary variable.
5422 */
5424 SCIP_BENDERS* benders, /**< Benders' decomposition */
5425 SCIP_SET* set, /**< global SCIP settings */
5426 int probnumber, /**< the subproblem to be evaluated */
5427 SCIP_Real* lowerbound, /**< the lowerbound for the subproblem */
5428 SCIP_Bool* infeasible /**< was the subproblem found to be infeasible? */
5429 )
5430{
5431 SCIP* subproblem;
5432 SCIP_Real dualbound;
5433 SCIP_Real memorylimit;
5434 SCIP_Real timelimit;
5435 SCIP_Longint totalnodes;
5436 int disablecutoff;
5437 int verblevel;
5438 SCIP_Bool lperror;
5439 SCIP_Bool cutoff;
5440
5441 assert(benders != NULL);
5442 assert(set != NULL);
5443
5444 if( benders->benderssolvesub != NULL || benders->benderssolvesubconvex != NULL )
5445 {
5446 (*lowerbound) = SCIPvarGetLbGlobal(SCIPbendersGetAuxiliaryVar(benders, probnumber));
5447 (*infeasible) = FALSE;
5448
5449 SCIPinfoMessage(set->scip, NULL, "Benders' decomposition: a bendersSolvesub or bendersSolvesubconvex has been "
5450 "implemented. SCIPbendersComputeSubproblemLowerbound can not be executed.\n");
5451 SCIPinfoMessage(set->scip, NULL, "Set the auxiliary variable lower bound by calling "
5452 "SCIPbendersUpdateSubproblemLowerbound in bendersCreatesub. The auxiliary variable %d will remain as %g\n",
5453 probnumber, (*lowerbound));
5454
5455 return SCIP_OKAY;
5456 }
5457 else
5458 {
5459 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_FULL, NULL, "Benders' decomposition: Computing a lower bound for"
5460 " subproblem %d\n", probnumber);
5461 }
5462
5463 /* getting the subproblem to evaluate */
5464 subproblem = SCIPbendersSubproblem(benders, probnumber);
5465
5466 (*lowerbound) = -SCIPinfinity(subproblem);
5467 (*infeasible) = FALSE;
5468
5469 SCIP_CALL( SCIPgetIntParam(subproblem, "display/verblevel", &verblevel) );
5470 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_NONE) );
5471#ifdef SCIP_MOREDEBUG
5472 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", (int)SCIP_VERBLEVEL_HIGH) );
5473#endif
5474
5475 /* copying memory and time limits */
5476 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/time", &timelimit) );
5477 SCIP_CALL( SCIPgetRealParam(subproblem, "limits/memory", &memorylimit) );
5478 SCIP_CALL( copyMemoryAndTimeLimits(set->scip, subproblem) );
5479
5480 /* if the subproblem is independent, then the default SCIP settings are used. Otherwise, only the root node is solved
5481 * to compute a lower bound on the subproblem
5482 */
5483 SCIP_CALL( SCIPgetLongintParam(subproblem, "limits/totalnodes", &totalnodes) );
5484 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/disablecutoff", &disablecutoff) );
5485 if( !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
5486 {
5487 SCIP_CALL( SCIPsetLongintParam(subproblem, "limits/totalnodes", 1LL) );
5488 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", 1) );
5489 }
5490
5491 /* if the subproblem not independent and is convex, then the probing LP is solved. Otherwise, the MIP is solved */
5492 dualbound = -SCIPinfinity(subproblem);
5494 {
5495 SCIP_Bool solvenlp = FALSE;
5496
5497 assert(SCIPisLPConstructed(subproblem) || SCIPisNLPConstructed(subproblem));
5498
5499 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0
5501 solvenlp = TRUE;
5502
5503 SCIP_CALL( SCIPstartProbing(subproblem) );
5504 if( solvenlp )
5505 {
5506 SCIP_NLPSOLSTAT nlpsolstat;
5507 SCIP_NLPTERMSTAT nlptermstat;
5508
5509 SCIP_CALL( SCIPsolveNLPParam(subproblem, benders->nlpparam) );
5510
5511 nlpsolstat = SCIPgetNLPSolstat(subproblem);
5512 nlptermstat = SCIPgetNLPTermstat(subproblem);
5513 SCIPdebugMsg(set->scip, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
5514
5515 if( nlptermstat == SCIP_NLPTERMSTAT_OKAY && (nlpsolstat == SCIP_NLPSOLSTAT_LOCINFEASIBLE || nlpsolstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE) )
5516 {
5517 /* trust infeasible only if terminated "okay" */
5518 (*infeasible) = TRUE;
5519 }
5520 else if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT )
5521 {
5522 dualbound = SCIPretransformObj(subproblem, SCIPgetNLPObjval(subproblem));
5523 }
5524 }
5525 else
5526 {
5527 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
5528
5529 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_INFEASIBLE )
5530 (*infeasible) = TRUE;
5531 else if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_OPTIMAL )
5532 dualbound = SCIPgetSolOrigObj(subproblem, NULL)*(int)SCIPgetObjsense(set->scip);
5533 }
5534 }
5535 else
5536 {
5537 SCIP_EVENTHDLRDATA* eventhdlrdata;
5538
5539 /* if the subproblem is not convex, then event handlers have been added to interrupt the solve. These must be
5540 * disabled
5541 */
5543 eventhdlrdata->solvecip = TRUE;
5544
5545 SCIP_CALL( SCIPsolve(subproblem) );
5546
5547 if( SCIPgetStatus(subproblem) == SCIP_STATUS_INFEASIBLE )
5548 (*infeasible) = TRUE;
5549 else
5550 dualbound = SCIPgetDualbound(subproblem);
5551 }
5552
5553 /* getting the lower bound value */
5554 (*lowerbound) = dualbound;
5555
5556 if( !SCIPbendersSubproblemIsIndependent(benders, probnumber) )
5557 {
5558 SCIP_CALL( SCIPsetLongintParam(subproblem, "limits/totalnodes", totalnodes) );
5559 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/disablecutoff", disablecutoff) );
5560 }
5561 SCIP_CALL( SCIPsetIntParam(subproblem, "display/verblevel", verblevel) );
5562 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/memory", memorylimit) );
5563 SCIP_CALL( SCIPsetRealParam(subproblem, "limits/time", timelimit) );
5564
5565 /* the subproblem must be freed so that it is reset for the subsequent Benders' decomposition solves. If the
5566 * subproblems are independent, they are not freed. SCIPfreeBendersSubproblem must still be called, but in this
5567 * function the independent subproblems are not freed. However, they will still be freed at the end of the
5568 * solving process for the master problem.
5569 */
5570 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, probnumber) );
5571
5572 return SCIP_OKAY;
5573}
5574
5575/** Merges a subproblem into the master problem. This process just adds a copy of the subproblem variables and
5576 * constraints to the master problem, but keeps the subproblem stored in the Benders' decomposition data structure. The reason for
5577 * keeping the subproblem available is for when it is queried for solutions after the problem is solved.
5578 *
5579 * Once the subproblem is merged into the master problem, then the subproblem is flagged as disabled. This means that
5580 * it will not be solved in the subsequent subproblem solving loops.
5581 *
5582 * The associated auxiliary variables are kept in the master problem. The objective function of the merged subproblem
5583 * is added as an underestimator constraint.
5584 */
5586 SCIP_BENDERS* benders, /**< Benders' decomposition */
5587 SCIP_SET* set, /**< global SCIP settings */
5588 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of subproblem variables corresponding
5589 * to the newly created master variables, or NULL */
5590 SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of subproblem constraints to the
5591 * corresponding newly created constraints, or NULL */
5592 int probnumber /**< the number of the subproblem that will be merged into the master problem*/
5593 )
5594{
5595 SCIP* subproblem;
5596 SCIP_HASHMAP* localvarmap;
5597 SCIP_HASHMAP* localconsmap;
5598 SCIP_VAR** vars;
5599 SCIP_VAR* auxiliaryvar;
5600 SCIP_CONS** conss;
5601 SCIP_CONS* objcons;
5602 int nvars;
5603 int nconss;
5604 int i;
5605 SCIP_Bool uselocalvarmap;
5606 SCIP_Bool uselocalconsmap;
5607 char varname[SCIP_MAXSTRLEN];
5608 char consname[SCIP_MAXSTRLEN];
5609 const char* origvarname;
5610
5611 assert(benders != NULL);
5612 assert(set != NULL);
5613 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
5614
5615 SCIPverbMessage(set->scip, SCIP_VERBLEVEL_HIGH, NULL, " Benders' decomposition: Infeasibility of subproblem %d can't "
5616 "be resolved. Subproblem %d is being merged into the master problem.\n", probnumber, probnumber);
5617
5618 /* freeing the subproblem because it will be flagged as independent. Since the subproblem is flagged as independent,
5619 * it will no longer be solved or freed within the solving loop.
5620 */
5621 SCIP_CALL( SCIPbendersFreeSubproblem(benders, set, probnumber) );
5622
5623 subproblem = SCIPbendersSubproblem(benders, probnumber);
5624
5625 uselocalvarmap = (varmap == NULL);
5626 uselocalconsmap = (consmap == NULL);
5627
5628 if( uselocalvarmap )
5629 {
5630 /* create the variable mapping hash map */
5631 SCIP_CALL( SCIPhashmapCreate(&localvarmap, SCIPblkmem(set->scip), SCIPgetNVars(subproblem)) );
5632 }
5633 else
5634 localvarmap = varmap;
5635
5636 if( uselocalconsmap )
5637 {
5638 /* create the constraint mapping hash map */
5639 SCIP_CALL( SCIPhashmapCreate(&localconsmap, SCIPblkmem(set->scip), SCIPgetNConss(subproblem)) );
5640 }
5641 else
5642 localconsmap = consmap;
5643
5644 /* retrieving the subproblem variable to build a subproblem mapping */
5645 vars = SCIPgetVars(subproblem);
5646 nvars = SCIPgetNVars(subproblem);
5647
5648 /* creating the objective function constraint that will be added to the master problem */
5649 /* setting the name of the transferred cut */
5650 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "objectivecons_%d", probnumber );
5651 SCIP_CALL( SCIPcreateConsBasicLinear(set->scip, &objcons, consname, 0, NULL, NULL, -SCIPsetInfinity(set), 0.0) );
5652 SCIP_CALL( SCIPsetConsRemovable(set->scip, objcons, TRUE) );
5653
5654 for( i = 0; i < nvars; i++ )
5655 {
5656 SCIP_VAR* mastervar = NULL;
5657 SCIP_Bool releasevar = FALSE;
5658
5659 SCIP_CALL( SCIPgetBendersMasterVar(set->scip, benders, vars[i], &mastervar) );
5660
5661 /* if the master problem variable is not NULL, then there is a corresponding variable in the master problem for
5662 * the given subproblem variable. In this case, the variable is added to the hashmap.
5663 */
5664 if( mastervar == NULL )
5665 {
5666 SCIP_VAR* origvar;
5667 SCIP_Real scalar;
5668 SCIP_Real constant;
5669
5670 /* This is following the same process as in createVariableMappings. The original variable is used to map
5671 * between the subproblem and the master problem
5672 */
5673 origvar = vars[i];
5674 scalar = 1.0;
5675 constant = 0.0;
5676 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
5677
5678 /* retrieving the var name */
5679 origvarname = SCIPvarGetName(origvar);
5680 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s", origvarname);
5681
5682 /* creating and adding the variable to the Benders' decomposition master problem */
5683 SCIP_CALL( SCIPcreateVarBasic(set->scip, &mastervar, varname, SCIPvarGetLbOriginal(origvar),
5684 SCIPvarGetUbOriginal(origvar), 0.0, SCIPvarGetType(origvar)) );
5685
5686 /* adding the variable to the master problem */
5687 SCIP_CALL( SCIPaddVar(set->scip, mastervar) );
5688
5689 /* adds the variable to the objective function constraint */
5690 SCIP_CALL( SCIPaddCoefLinear(set->scip, objcons, mastervar, SCIPvarGetObj(origvar)) );
5691
5692 /* the variable must be released */
5693 releasevar = TRUE;
5694 }
5695
5696 /* creating the mapping betwen the subproblem var and the master var for the constraint copying */
5697 SCIP_CALL( SCIPhashmapInsert(localvarmap, vars[i], mastervar) );
5698
5699 /* releasing the variable */
5700 if( releasevar )
5701 {
5702 SCIP_CALL( SCIPreleaseVar(set->scip, &mastervar) );
5703 }
5704 }
5705
5706 /* getting the constraints from the subproblem that will be added to the master problem */
5707 conss = SCIPgetConss(subproblem);
5708 nconss = SCIPgetNConss(subproblem);
5709
5710 /* getting a copy of all constraints and adding it to the master problem */
5711 for( i = 0; i < nconss; i++ )
5712 {
5713 SCIP_CONS* targetcons;
5714 SCIP_Bool initial;
5715 SCIP_Bool valid;
5716
5717 /* NOTE: adding all subproblem constraints appears to cause an error when resolving the LP, which results in the
5718 * current incumbent being reported as optimal. To avoid this, only half of the subproblem constraints are added
5719 * the master problem. The remaining half are marked as lazy and are separated as required.
5720 */
5721 initial = (i < nconss/2);
5722
5723 SCIP_CALL( SCIPgetConsCopy(subproblem, set->scip, conss[i], &targetcons, SCIPconsGetHdlr(conss[i]),
5724 localvarmap, localconsmap, NULL, initial, SCIPconsIsSeparated(conss[i]),
5725 SCIPconsIsEnforced(conss[i]), SCIPconsIsChecked(conss[i]), SCIPconsIsPropagated(conss[i]), FALSE,
5726 SCIPconsIsModifiable(conss[i]), SCIPconsIsDynamic(conss[i]), SCIPconsIsRemovable(conss[i]),
5727 FALSE, TRUE, &valid) );
5728 assert(SCIPconsIsInitial(conss[i]));
5729 assert(valid);
5730
5731 SCIP_CALL( SCIPaddCons(set->scip, targetcons) );
5732
5733 SCIP_CALL( SCIPreleaseCons(set->scip, &targetcons) );
5734 }
5735
5736 /* freeing the hashmaps */
5737 if( uselocalvarmap )
5738 {
5739 /* free hash map */
5740 SCIPhashmapFree(&localvarmap);
5741 }
5742
5743 if( uselocalconsmap )
5744 {
5745 /* free hash map */
5746 SCIPhashmapFree(&localconsmap);
5747 }
5748
5749 /* adding the auxiliary variable to the objective constraint */
5750 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
5751 SCIP_CALL( SCIPaddCoefLinear(set->scip, objcons, auxiliaryvar, -1.0) );
5752
5753 /* adding the objective function constraint to the master problem */
5754 SCIP_CALL( SCIPaddCons(set->scip, objcons) );
5755
5756 SCIP_CALL( SCIPreleaseCons(set->scip, &objcons) );
5757
5758 /* the merged subproblem is no longer solved. This is indicated by setting the subproblem as disabled. The
5759 * subproblem still exists, but it is not solved in the solving loop.
5760 */
5761 SCIPbendersSetSubproblemEnabled(benders, probnumber, FALSE);
5762
5763 return SCIP_OKAY;
5764}
5765
5766/** Returns the corresponding master or subproblem variable for the given variable.
5767 * This provides a call back for the variable mapping between the master and subproblems. */
5769 SCIP_BENDERS* benders, /**< Benders' decomposition */
5770 SCIP_SET* set, /**< global SCIP settings */
5771 SCIP_VAR* var, /**< the variable for which the corresponding variable is desired */
5772 SCIP_VAR** mappedvar, /**< the variable that is mapped to var */
5773 int probnumber /**< the problem number for the desired variable, -1 for the master problem */
5774 )
5775{
5776 assert(benders != NULL);
5777 assert(set != NULL);
5778 assert(var != NULL);
5779 assert(mappedvar != NULL);
5780 assert(benders->bendersgetvar != NULL);
5781
5782 (*mappedvar) = NULL;
5783
5784 /* if the variable name matches the auxiliary variable, then the master variable is returned as NULL */
5785 if( strstr(SCIPvarGetName(var), AUXILIARYVAR_NAME) != NULL )
5786 return SCIP_OKAY;
5787
5788 SCIP_CALL( benders->bendersgetvar(set->scip, benders, var, mappedvar, probnumber) );
5789
5790 return SCIP_OKAY;
5791}
5793/** gets user data of Benders' decomposition */
5795 SCIP_BENDERS* benders /**< Benders' decomposition */
5796 )
5797{
5798 assert(benders != NULL);
5799
5800 return benders->bendersdata;
5801}
5803/** sets user data of Benders' decomposition; user has to free old data in advance! */
5805 SCIP_BENDERS* benders, /**< Benders' decomposition */
5806 SCIP_BENDERSDATA* bendersdata /**< new Benders' decomposition user data */
5807 )
5808{
5809 assert(benders != NULL);
5810
5811 benders->bendersdata = bendersdata;
5812}
5814/** sets copy callback of Benders' decomposition */
5816 SCIP_BENDERS* benders, /**< Benders' decomposition */
5817 SCIP_DECL_BENDERSCOPY ((*benderscopy)) /**< copy callback of Benders' decomposition */
5818 )
5819{
5820 assert(benders != NULL);
5821
5822 benders->benderscopy = benderscopy;
5823}
5825/** sets destructor callback of Benders' decomposition */
5827 SCIP_BENDERS* benders, /**< Benders' decomposition */
5828 SCIP_DECL_BENDERSFREE ((*bendersfree)) /**< destructor of Benders' decomposition */
5829 )
5830{
5831 assert(benders != NULL);
5832
5833 benders->bendersfree = bendersfree;
5834}
5836/** sets initialization callback of Benders' decomposition */
5838 SCIP_BENDERS* benders, /**< Benders' decomposition */
5839 SCIP_DECL_BENDERSINIT((*bendersinit)) /**< initialize the Benders' decomposition */
5840 )
5841{
5842 assert(benders != NULL);
5843
5844 benders->bendersinit = bendersinit;
5845}
5847/** sets deinitialization callback of Benders' decomposition */
5849 SCIP_BENDERS* benders, /**< Benders' decomposition */
5850 SCIP_DECL_BENDERSEXIT((*bendersexit)) /**< deinitialize the Benders' decomposition */
5851 )
5852{
5853 assert(benders != NULL);
5854
5855 benders->bendersexit = bendersexit;
5856}
5858/** sets presolving initialization callback of Benders' decomposition */
5860 SCIP_BENDERS* benders, /**< Benders' decomposition */
5861 SCIP_DECL_BENDERSINITPRE((*bendersinitpre))/**< initialize presolving for Benders' decomposition */
5862 )
5863{
5864 assert(benders != NULL);
5865
5866 benders->bendersinitpre = bendersinitpre;
5867}
5869/** sets presolving deinitialization callback of Benders' decomposition */
5871 SCIP_BENDERS* benders, /**< Benders' decomposition */
5872 SCIP_DECL_BENDERSEXITPRE((*bendersexitpre))/**< deinitialize presolving for Benders' decomposition */
5873 )
5874{
5875 assert(benders != NULL);
5876
5877 benders->bendersexitpre = bendersexitpre;
5878}
5880/** sets solving process initialization callback of Benders' decomposition */
5882 SCIP_BENDERS* benders, /**< Benders' decomposition */
5883 SCIP_DECL_BENDERSINITSOL((*bendersinitsol))/**< solving process initialization callback of Benders' decomposition */
5884 )
5885{
5886 assert(benders != NULL);
5887
5888 benders->bendersinitsol = bendersinitsol;
5889}
5891/** sets solving process deinitialization callback of Benders' decomposition */
5893 SCIP_BENDERS* benders, /**< Benders' decomposition */
5894 SCIP_DECL_BENDERSEXITSOL((*bendersexitsol))/**< solving process deinitialization callback of Benders' decomposition */
5895 )
5896{
5897 assert(benders != NULL);
5898
5899 benders->bendersexitsol = bendersexitsol;
5900}
5902/** sets the pre subproblem solve callback of Benders' decomposition */
5904 SCIP_BENDERS* benders, /**< Benders' decomposition */
5905 SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve))/**< called prior to the subproblem solving loop */
5906 )
5907{
5908 assert(benders != NULL);
5909
5910 benders->benderspresubsolve = benderspresubsolve;
5911}
5913/** sets convex solve callback of Benders' decomposition */
5915 SCIP_BENDERS* benders, /**< Benders' decomposition */
5916 SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex))/**< solving method for the convex Benders' decomposition subproblem */
5917 )
5918{
5919 assert(benders != NULL);
5920
5921 benders->benderssolvesubconvex = benderssolvesubconvex;
5922}
5924/** sets solve callback of Benders' decomposition */
5926 SCIP_BENDERS* benders, /**< Benders' decomposition */
5927 SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub))/**< solving method for a Benders' decomposition subproblem */
5928 )
5929{
5930 assert(benders != NULL);
5931
5932 benders->benderssolvesub = benderssolvesub;
5933}
5935/** sets post-solve callback of Benders' decomposition */
5937 SCIP_BENDERS* benders, /**< Benders' decomposition */
5938 SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve))/**< solving process deinitialization callback of Benders' decomposition */
5939 )
5940{
5941 assert(benders != NULL);
5942
5943 benders->benderspostsolve = benderspostsolve;
5944}
5946/** sets post-solve callback of Benders' decomposition */
5948 SCIP_BENDERS* benders, /**< Benders' decomposition */
5949 SCIP_DECL_SORTPTRCOMP((*benderssubcomp)) /**< a comparator for defining the solving order of the subproblems */
5950 )
5951{
5952 assert(benders != NULL);
5953
5954 benders->benderssubcomp = benderssubcomp;
5955}
5957/** sets free subproblem callback of Benders' decomposition */
5959 SCIP_BENDERS* benders, /**< Benders' decomposition */
5960 SCIP_DECL_BENDERSFREESUB((*bendersfreesub))/**< the freeing callback for the subproblem */
5961 )
5962{
5963 assert(benders != NULL);
5964
5965 benders->bendersfreesub = bendersfreesub;
5966}
5968/** gets name of Benders' decomposition */
5969const char* SCIPbendersGetName(
5970 SCIP_BENDERS* benders /**< Benders' decomposition */
5971 )
5972{
5973 assert(benders != NULL);
5974
5975 return benders->name;
5976}
5978/** gets description of Benders' decomposition */
5979const char* SCIPbendersGetDesc(
5980 SCIP_BENDERS* benders /**< Benders' decomposition */
5981 )
5982{
5983 assert(benders != NULL);
5984
5985 return benders->desc;
5986}
5988/** gets priority of Benders' decomposition */
5990 SCIP_BENDERS* benders /**< Benders' decomposition */
5991 )
5992{
5993 assert(benders != NULL);
5994
5995 return benders->priority;
5996}
5998/** sets priority of Benders' decomposition */
6000 SCIP_BENDERS* benders, /**< Benders' decomposition */
6001 SCIP_SET* set, /**< global SCIP settings */
6002 int priority /**< new priority of the Benders' decomposition */
6003 )
6004{
6005 assert(benders != NULL);
6006 assert(set != NULL);
6007
6008 benders->priority = priority;
6009 set->benderssorted = FALSE;
6010}
6012/** gets the number of subproblems for the Benders' decomposition */
6014 SCIP_BENDERS* benders /**< the Benders' decomposition data structure */
6015 )
6016{
6017 assert(benders != NULL);
6018
6019 return benders->nsubproblems;
6020}
6022/** returns the SCIP instance for a given subproblem */
6024 SCIP_BENDERS* benders, /**< the Benders' decomposition data structure */
6025 int probnumber /**< the subproblem number */
6026 )
6027{
6028 assert(benders != NULL);
6029 assert(probnumber >= 0 && probnumber < benders->nsubproblems);
6030
6031 return benders->subproblems[probnumber];
6032}
6034/** gets the number of times, the Benders' decomposition was called and tried to find a variable with negative reduced costs */
6036 SCIP_BENDERS* benders /**< Benders' decomposition */
6037 )
6038{
6039 assert(benders != NULL);
6040
6041 return benders->ncalls;
6042}
6044/** gets the number of optimality cuts found by the collection of Benders' decomposition subproblems */
6046 SCIP_BENDERS* benders /**< Benders' decomposition */
6047 )
6048{
6049 assert(benders != NULL);
6050
6051 return benders->ncutsfound;
6052}
6054/** gets the number of cuts found from the strengthening round */
6056 SCIP_BENDERS* benders /**< Benders' decomposition */
6057 )
6058{
6059 assert(benders != NULL);
6060
6061 return benders->nstrengthencuts;
6062}
6064/** gets the number of calls to the strengthening round */
6066 SCIP_BENDERS* benders /**< Benders' decomposition */
6067 )
6068{
6069 assert(benders != NULL);
6070
6071 return benders->nstrengthencalls;
6072}
6074/** gets the number of calls to the strengthening round that fail */
6076 SCIP_BENDERS* benders /**< Benders' decomposition */
6077 )
6078{
6079 assert(benders != NULL);
6080
6081 return benders->nstrengthenfails;
6082}
6084/** gets time in seconds used in this Benders' decomposition for setting up for next stages */
6086 SCIP_BENDERS* benders /**< Benders' decomposition */
6087 )
6088{
6089 assert(benders != NULL);
6090
6091 return SCIPclockGetTime(benders->setuptime);
6092}
6094/** gets time in seconds used in this Benders' decomposition */
6096 SCIP_BENDERS* benders /**< Benders' decomposition */
6097 )
6098{
6099 assert(benders != NULL);
6100
6101 return SCIPclockGetTime(benders->bendersclock);
6102}
6104/** enables or disables all clocks of the Benders' decomposition, depending on the value of the flag */
6106 SCIP_BENDERS* benders, /**< the Benders' decomposition for which all clocks should be enabled or disabled */
6107 SCIP_Bool enable /**< should the clocks of the Benders' decomposition be enabled? */
6108 )
6109{
6110 assert(benders != NULL);
6111
6112 SCIPclockEnableOrDisable(benders->setuptime, enable);
6113 SCIPclockEnableOrDisable(benders->bendersclock, enable);
6114}
6116/** is Benders' decomposition initialized? */
6118 SCIP_BENDERS* benders /**< Benders' decomposition */
6119 )
6120{
6121 assert(benders != NULL);
6122
6123 return benders->initialized;
6124}
6126/** Are Benders' cuts generated from the LP solutions? */
6128 SCIP_BENDERS* benders /**< Benders' decomposition */
6129 )
6130{
6131 assert(benders != NULL);
6132
6133 return benders->cutlp;
6134}
6136/** Are Benders' cuts generated from the pseudo solutions? */
6138 SCIP_BENDERS* benders /**< Benders' decomposition */
6139 )
6140{
6141 assert(benders != NULL);
6142
6143 return benders->cutpseudo;
6144}
6146/** Are Benders' cuts generated from the relaxation solutions? */
6148 SCIP_BENDERS* benders /**< Benders' decomposition */
6149 )
6150{
6151 assert(benders != NULL);
6152
6153 return benders->cutrelax;
6154}
6156/** should this Benders' use the auxiliary variables from the highest priority Benders' */
6158 SCIP_BENDERS* benders /**< Benders' decomposition */
6159 )
6160{
6161 assert(benders != NULL);
6162
6163 return benders->shareauxvars;
6164}
6165
6166/** adds a subproblem to the Benders' decomposition data. If a custom subproblem solving method is used, then the
6167 * subproblem pointer can be set to NULL
6168 */
6170 SCIP_BENDERS* benders, /**< Benders' decomposition */
6171 SCIP* subproblem /**< subproblem to be added to the data storage, can be NULL */
6172 )
6173{
6174 assert(benders != NULL);
6175 assert(benders->naddedsubprobs + 1 <= benders->nsubproblems);
6176
6177 /* if the subproblem pointer is NULL, then the subproblem solving callback functions must be set. */
6178 if( subproblem == NULL && (!benders->benderssolvesubconvex || !benders->benderssolvesub) )
6179 {
6180 SCIPerrorMessage("The subproblem can only be set to NULL if both bendersSolvesubconvex%s and bendersSolvesub%s "
6181 "are defined.\n", benders->name, benders->name);
6182 return SCIP_ERROR;
6183 }
6184
6185 benders->subproblems[benders->naddedsubprobs] = subproblem;
6186
6187 benders->naddedsubprobs++;
6188
6189 return SCIP_OKAY;
6190}
6192/** removes the subproblems from the Benders' decomposition data */
6194 SCIP_BENDERS* benders /**< Benders' decomposition */
6195 )
6196{
6197 assert(benders != NULL);
6198 assert(benders->subproblems != NULL);
6199
6200 BMSclearMemoryArray(&benders->subproblems, benders->naddedsubprobs);
6201 benders->naddedsubprobs = 0;
6202}
6204/** returns the main auxiliary variable that is used the subproblem objective function. */
6206 SCIP_BENDERS* benders /**< Benders' decomposition */
6207 )
6208{
6209 assert(benders != NULL);
6210
6211 return benders->masterauxvar;
6212}
6214/** returns the auxiliary variable for the given subproblem */
6216 SCIP_BENDERS* benders, /**< Benders' decomposition */
6217 int probnumber /**< the subproblem number */
6218 )
6219{
6220 assert(benders != NULL);
6221 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6222
6223 return benders->auxiliaryvars[probnumber];
6224}
6226/** returns all auxiliary variables */
6228 SCIP_BENDERS* benders /**< Benders' decomposition */
6229 )
6230{
6231 assert(benders != NULL);
6232
6233 return benders->auxiliaryvars;
6234}
6236/** returns the subproblem master variables for the given subproblem */
6238 SCIP_BENDERS* benders, /**< Benders' decomposition */
6239 int probnumber /**< the subproblem number */
6240 )
6241{
6242 assert(benders != NULL);
6243 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6244
6245 return benders->submastervars[probnumber];
6246}
6248/** returns the number of subproblem master variables for the given subproblem */
6250 SCIP_BENDERS* benders, /**< Benders' decomposition */
6251 int probnumber /**< the subproblem number */
6252 )
6253{
6254 assert(benders != NULL);
6255 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6256
6257 return benders->nsubmastervars[probnumber];
6258}
6260/** returns the subproblem master variable data for the given subproblem */
6262 SCIP_BENDERS* benders, /**< Benders' decomposition */
6263 int probnumber, /**< the subproblem number */
6264 SCIP_VAR*** vars, /**< pointer to store the master variables, or NULL */
6265 int* nvars, /**< the number of master problem variables, or NULL */
6266 int* nbinvars, /**< the number of binary master problem variables, or NULL */
6267 int* nintvars /**< the number of integer master problem variables, or NULL */
6268 )
6269{
6270 assert(benders != NULL);
6271 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6272
6273 if( vars != NULL )
6274 (*vars) = benders->submastervars[probnumber];
6275
6276 if( nvars != NULL )
6277 (*nvars) = benders->nsubmastervars[probnumber];
6278
6279 if( nbinvars != NULL )
6280 (*nbinvars) = benders->nsubmasterbinvars[probnumber];
6281
6282 if( nintvars != NULL )
6283 (*nintvars) = benders->nsubmasterintvars[probnumber];
6284}
6286/** stores the objective function value of the subproblem for use in cut generation */
6288 SCIP_BENDERS* benders, /**< the Benders' decomposition structure */
6289 int probnumber, /**< the subproblem number */
6290 SCIP_Real objval /**< the objective function value for the subproblem */
6291 )
6292{
6293 assert(benders != NULL);
6294 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6295
6296 /* updating the best objval */
6297 if( objval < benders->bestsubprobobjval[probnumber] )
6298 benders->bestsubprobobjval[probnumber] = objval;
6299
6300 benders->subprobobjval[probnumber] = objval;
6301}
6303/** returns the objective function value of the subproblem for use in cut generation */
6305 SCIP_BENDERS* benders, /**< Benders' decomposition */
6306 int probnumber /**< the subproblem number */
6307 )
6308{
6309 assert(benders != NULL);
6310 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6311
6312 return benders->subprobobjval[probnumber];
6313}
6315/** returns whether the solution has non-zero slack variables */
6317 SCIP_BENDERS* benders, /**< Benders' decomposition */
6318 SCIP_Bool* activeslack /**< flag to indicate whether a slack variable is active */
6319 )
6320{
6321 SCIP* subproblem;
6322 SCIP_SOL* sol;
6323 SCIP_VAR** vars;
6324 int nsubproblems;
6325 int nvars;
6326 int ncontvars;
6327 int i;
6328 int j;
6329 SCIP_Bool freesol = FALSE;
6330
6331 assert(benders != NULL);
6332 assert(activeslack != NULL);
6333
6334 (*activeslack) = FALSE;
6335
6336 /* if the slack variables have not been added, then we can immediately state that no slack variables are active */
6337 if( !benders->feasibilityphase )
6338 {
6339 return SCIP_OKAY;
6340 }
6341
6342 nsubproblems = SCIPbendersGetNSubproblems(benders);
6343
6344 /* checking all subproblems for active slack variables */
6345 for( i = 0; i < nsubproblems && !(*activeslack); i++ )
6346 {
6347 subproblem = SCIPbendersSubproblem(benders, i);
6348
6349 /* if the subproblem is convex and an NLP, then we need to create the NLP solution. Otherwise, the solution can be
6350 * retrieved from the LP or CIP.
6351 */
6353 {
6354 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) > 0 )
6355 {
6356 SCIP_CALL( SCIPcreateNLPSol(subproblem, &sol, NULL) );
6357 }
6358 else
6359 {
6360 SCIP_CALL( SCIPcreateCurrentSol(subproblem, &sol, NULL) );
6361 }
6362 freesol = TRUE;
6363 }
6364 else
6365 sol = SCIPgetBestSol(subproblem);
6366
6367 /* getting the variable data. Only the continuous variables are important. */
6368 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, &nvars, NULL, NULL, NULL, &ncontvars) );
6369
6370 /* checking all slack variables for non-zero solution values */
6371 for( j = nvars - 1; j >= nvars - ncontvars; j-- )
6372 {
6373 if( strstr(SCIPvarGetName(vars[j]), SLACKVAR_NAME) != NULL )
6374 {
6375 if( SCIPisPositive(subproblem, SCIPgetSolVal(subproblem, sol, vars[j])) )
6376 {
6377 (*activeslack) = TRUE;
6378 break;
6379 }
6380 }
6381 }
6382
6383 /* freeing the LP and NLP solutions */
6384 if( freesol )
6385 {
6386 SCIP_CALL( SCIPfreeSol(subproblem, &sol) );
6387 }
6388 }
6389
6390 return SCIP_OKAY;
6391}
6392
6393/** sets the subproblem type
6394 *
6395 * The subproblem types are:
6396 * - Convex constraints with continuous variables
6397 * - Convex constraints with discrete variables
6398 * - Non-convex constraints with continuous variables
6399 * - Non-convex constraints with discrete variables
6400 */
6402 SCIP_BENDERS* benders, /**< Benders' decomposition */
6403 int probnumber, /**< the subproblem number */
6404 SCIP_BENDERSSUBTYPE subprobtype /**< the subproblem type */
6405 )
6406{
6407 assert(benders != NULL);
6408 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6409
6410 if( subprobtype == SCIP_BENDERSSUBTYPE_CONVEXCONT
6411 && benders->subprobtype[probnumber] != SCIP_BENDERSSUBTYPE_CONVEXCONT )
6412 benders->nconvexsubprobs++;
6413 else if( subprobtype != SCIP_BENDERSSUBTYPE_CONVEXCONT
6414 && benders->subprobtype[probnumber] == SCIP_BENDERSSUBTYPE_CONVEXCONT )
6415 benders->nconvexsubprobs--;
6416
6417 benders->subprobtype[probnumber] = subprobtype;
6418
6419 assert(benders->nconvexsubprobs >= 0 && benders->nconvexsubprobs <= benders->nsubproblems);
6420}
6421
6422/** returns the type of the subproblem
6423 *
6424 * This type is used to determine whether the duals of the problem can be used to generate cuts
6425 */
6427 SCIP_BENDERS* benders, /**< Benders' decomposition */
6428 int probnumber /**< the subproblem number */
6429 )
6430{
6431 assert(benders != NULL);
6432 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6433
6434 return benders->subprobtype[probnumber];
6435}
6436
6437/** sets the flag indicating whether a subproblem is convex
6438 *
6439 * It is possible that this can change during the solving process. One example is when the three-phase method is
6440 * employed, where the first phase solves the convex relaxation of both the master and subproblems, the second phase
6441 * reintroduces the integrality constraints to the master problem and the third phase then reintroduces integrality
6442 * constraints to the subproblems.
6443 */
6445 SCIP_BENDERS* benders, /**< Benders' decomposition */
6446 int probnumber, /**< the subproblem number */
6447 SCIP_Bool isconvex /**< flag to indicate whether the subproblem is convex */
6448 )
6449{
6450 assert(benders != NULL);
6451 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6452
6453 if( isconvex && !benders->subprobisconvex[probnumber] )
6454 benders->nconvexsubprobs++;
6455 else if( !isconvex && benders->subprobisconvex[probnumber] )
6456 benders->nconvexsubprobs--;
6457
6458 benders->subprobisconvex[probnumber] = isconvex;
6459
6460 assert(benders->nconvexsubprobs >= 0 && benders->nconvexsubprobs <= benders->nsubproblems);
6461}
6462
6463/** returns whether the subproblem is convex
6464 *
6465 * This means that the dual solution can be used to generate cuts.
6466 */
6468 SCIP_BENDERS* benders, /**< Benders' decomposition */
6469 int probnumber /**< the subproblem number */
6470 )
6471{
6472 assert(benders != NULL);
6473 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6474
6475 return benders->subprobisconvex[probnumber];
6476}
6478/** returns the number of subproblems that are convex */
6480 SCIP_BENDERS* benders /**< Benders' decomposition */
6481 )
6482{
6483 assert(benders != NULL);
6484
6485 return benders->nconvexsubprobs;
6486}
6488/** sets the flag indicating whether a subproblem contains non-linear constraints */
6490 SCIP_BENDERS* benders, /**< Benders' decomposition */
6491 int probnumber, /**< the subproblem number */
6492 SCIP_Bool isnonlinear /**< flag to indicate whether the subproblem contains non-linear constraints */
6493 )
6494{
6495 assert(benders != NULL);
6496 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6497
6498 if( isnonlinear && !benders->subprobisnonlinear[probnumber] )
6499 benders->nnonlinearsubprobs++;
6500 else if( !isnonlinear && benders->subprobisnonlinear[probnumber] )
6501 benders->nnonlinearsubprobs--;
6502
6503 benders->subprobisnonlinear[probnumber] = isnonlinear;
6504
6505 assert(benders->nnonlinearsubprobs >= 0 && benders->nnonlinearsubprobs <= benders->nsubproblems);
6506}
6508/** returns whether the subproblem contains non-linear constraints. */
6510 SCIP_BENDERS* benders, /**< Benders' decomposition */
6511 int probnumber /**< the subproblem number */
6512 )
6513{
6514 assert(benders != NULL);
6515 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6516
6517 return benders->subprobisnonlinear[probnumber];
6518}
6520/** returns the number of subproblems that contain non-linear constraints */
6522 SCIP_BENDERS* benders /**< Benders' decomposition */
6523 )
6524{
6525 assert(benders != NULL);
6526
6527 return benders->nnonlinearsubprobs;
6528}
6530/** sets the flag indicating whether the master problem contains non-linear constraints */
6532 SCIP_BENDERS* benders, /**< Benders' decomposition */
6533 SCIP_Bool isnonlinear /**< flag to indicate whether the subproblem contains non-linear constraints */
6534 )
6535{
6536 assert(benders != NULL);
6537
6538 benders->masterisnonlinear = isnonlinear;
6539}
6541/** returns whether the master problem contains non-linear constraints. */
6543 SCIP_BENDERS* benders /**< Benders' decomposition */
6544 )
6545{
6546 assert(benders != NULL);
6547
6548 return benders->masterisnonlinear;
6549}
6551/** returns the flag indicating that Benders' decomposition is in a cut strengthening round */
6553 SCIP_BENDERS* benders /**< Benders' decomposition */
6554 )
6555{
6556 assert(benders != NULL);
6557
6558 return benders->strengthenround;
6559}
6560
6561/** sets the flag to indicate that at least one subproblem is always infeasible
6562 * NOTE: this is without any variable fixing being performed
6563 */
6565 SCIP_BENDERS* benders, /**< Benders' decomposition */
6566 SCIP_SET* set /**< global SCIP settings */
6567 )
6568{
6569 assert(benders != NULL);
6570 assert(set != NULL);
6571
6572 if( SCIPgetDepth(set->scip) <= 0 )
6573 benders->subprobsinfeasible = TRUE;
6574}
6575
6576/** returns whether at least one of the subproblems has been identified as infeasible.
6577 * NOTE: this is without any variable fixing being performed
6578 */
6580 SCIP_BENDERS* benders /**< Benders' decomposition */
6581 )
6582{
6583 assert(benders != NULL);
6584
6585 return benders->subprobsinfeasible;
6586}
6588/** changes all of the master problem variables in the given subproblem to continuous. */
6590 SCIP_BENDERS* benders, /**< Benders' decomposition */
6591 SCIP_SET* set, /**< global SCIP settings */
6592 int probnumber /**< the subproblem number */
6593 )
6594{
6595 SCIP* subproblem;
6596 SCIP_VAR** vars;
6597 int nbinvars;
6598 int nintvars;
6599 int nimplvars;
6600 int chgvarscount;
6601 int origintvars;
6602 int i;
6603 SCIP_Bool infeasible;
6604
6605 assert(benders != NULL);
6606 assert(set != NULL);
6607 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6608
6609 subproblem = SCIPbendersSubproblem(benders, probnumber);
6610 assert(subproblem != NULL);
6611
6612 /* only set the master problem variable to continuous if they have not already been changed. */
6613 if( !SCIPbendersGetMastervarsCont(benders, probnumber) )
6614 {
6615 SCIP_VAR* mastervar;
6616
6617 /* retrieving the variable data */
6618 SCIP_CALL( SCIPgetVarsData(subproblem, &vars, NULL, &nbinvars, &nintvars, &nimplvars, NULL) );
6619
6620 origintvars = nbinvars + nintvars + nimplvars;
6621
6622 chgvarscount = 0;
6623
6624 /* looping over all integer variables to change the master variables to continuous */
6625 i = 0;
6626 while( i < nbinvars + nintvars + nimplvars )
6627 {
6628 SCIP_CALL( SCIPbendersGetVar(benders, set, vars[i], &mastervar, -1) );
6629
6630 if( SCIPvarIsIntegral(vars[i]) && mastervar != NULL )
6631 {
6632 /* remove integrality of the subproblem variable corresponding to mastervar */
6633 SCIP_CALL( SCIPchgVarType(subproblem, vars[i], SCIP_VARTYPE_CONTINUOUS, &infeasible) );
6634 assert(!infeasible);
6635 SCIP_CALL( SCIPchgVarImplType(subproblem, vars[i], SCIP_IMPLINTTYPE_NONE, &infeasible) );
6636 assert(!infeasible);
6637
6638 chgvarscount++;
6639 SCIP_CALL( SCIPgetVarsData(subproblem, NULL, NULL, &nbinvars, &nintvars, &nimplvars, NULL) );
6640 }
6641 else
6642 i++;
6643 }
6644
6645 /* if all of the integer variables have been changed to continuous, then the subproblem could now be a convex
6646 * problem. This must be checked and if TRUE, then the LP subproblem is initialised and then put into probing
6647 * mode
6648 */
6649 if( chgvarscount > 0 && chgvarscount == origintvars )
6650 {
6651 /* checking the convexity of the subproblem */
6652 SCIP_CALL( checkSubproblemConvexity(benders, set, probnumber) );
6653
6654 /* if the subproblem has convex constraints and continuous variables, then it is initialised and put into
6655 * probing mode
6656 */
6658 {
6659 SCIP_CALL( initialiseLPSubproblem(benders, set, probnumber, &infeasible) );
6660
6661 /* if the initialisation process indicates that the LP is infeasible, then the complete problem is
6662 * infeasible. The subprobsinfeasible flag is set so that SCIP can be informed at the correct point
6663 * during the solving process.
6664 */
6665 if( infeasible )
6667 }
6668 }
6669
6670 SCIP_CALL( SCIPbendersSetMastervarsCont(benders, probnumber, TRUE) );
6671 }
6672
6673 return SCIP_OKAY;
6674}
6676/** sets the subproblem setup flag */
6678 SCIP_BENDERS* benders, /**< Benders' decomposition */
6679 int probnumber, /**< the subproblem number */
6680 SCIP_Bool issetup /**< flag to indicate whether the subproblem has been setup */
6681 )
6682{
6683 assert(benders != NULL);
6684 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6685
6686 benders->subprobsetup[probnumber] = issetup;
6687}
6689/** returns the subproblem setup flag */
6691 SCIP_BENDERS* benders, /**< Benders' decomposition */
6692 int probnumber /**< the subproblem number */
6693 )
6694{
6695 assert(benders != NULL);
6696 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6697
6698 return benders->subprobsetup[probnumber];
6699}
6701/** sets the independent subproblem flag */
6703 SCIP_BENDERS* benders, /**< Benders' decomposition */
6704 int probnumber, /**< the subproblem number */
6705 SCIP_Bool isindep /**< flag to indicate whether the subproblem is independent */
6706 )
6707{
6708 assert(benders != NULL);
6709 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6710
6711 /* if the user has defined solving or freeing functions, then it is not possible to declare a subproblem as
6712 * independent. This is because declaring a subproblem as independent changes the solving loop, so it would change
6713 * the expected behaviour of the user defined plugin. If a user calls this function, then an error will be returned.
6714 */
6715 if( benders->benderssolvesubconvex != NULL || benders->benderssolvesub != NULL || benders->bendersfreesub != NULL )
6716 {
6717 SCIPerrorMessage("The user has defined either bendersSolvesubconvex%s, bendersSolvesub%s or bendersFreesub%s. "
6718 "Thus, it is not possible to declare the independence of a subproblem.\n", benders->name, benders->name,
6719 benders->name);
6720 SCIPABORT();
6721 }
6722 else
6723 {
6724 SCIP_Bool activesubprob;
6725
6726 /* if the active status of the subproblem changes, then we must update the activesubprobs counter */
6727 activesubprob = subproblemIsActive(benders, probnumber);
6728
6729 benders->indepsubprob[probnumber] = isindep;
6730
6731 /* updating the activesubprobs counter */
6732 if( activesubprob && !subproblemIsActive(benders, probnumber) )
6733 benders->nactivesubprobs--;
6734 else if( !activesubprob && subproblemIsActive(benders, probnumber) )
6735 benders->nactivesubprobs++;
6736
6737 assert(benders->nactivesubprobs >= 0 && benders->nactivesubprobs <= SCIPbendersGetNSubproblems(benders));
6738 }
6739}
6741/** returns whether the subproblem is independent */
6743 SCIP_BENDERS* benders, /**< Benders' decomposition */
6744 int probnumber /**< the subproblem number */
6745 )
6746{
6747 assert(benders != NULL);
6748 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6749
6750 return benders->indepsubprob[probnumber];
6751}
6752
6753/** Sets whether the subproblem is enabled or disabled. A subproblem is disabled if it has been merged into the master
6754 * problem.
6755 */
6757 SCIP_BENDERS* benders, /**< Benders' decomposition */
6758 int probnumber, /**< the subproblem number */
6759 SCIP_Bool enabled /**< flag to indicate whether the subproblem is enabled */
6760 )
6761{
6762 SCIP_Bool activesubprob;
6763
6764 assert(benders != NULL);
6765 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6766
6767 /* if the active status of the subproblem changes, then we must update the activesubprobs counter */
6768 activesubprob = subproblemIsActive(benders, probnumber);
6769
6770 benders->subprobenabled[probnumber] = enabled;
6771
6772 /* updating the activesubprobs counter */
6773 if( activesubprob && !subproblemIsActive(benders, probnumber) )
6774 benders->nactivesubprobs--;
6775 else if( !activesubprob && subproblemIsActive(benders, probnumber) )
6776 benders->nactivesubprobs++;
6777
6778 assert(benders->nactivesubprobs >= 0 && benders->nactivesubprobs <= SCIPbendersGetNSubproblems(benders));
6779}
6781/** returns whether the subproblem is enabled, i.e. the subproblem is still solved in the solving loop. */
6783 SCIP_BENDERS* benders, /**< Benders' decomposition */
6784 int probnumber /**< the subproblem number */
6785 )
6786{
6787 assert(benders != NULL);
6788 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6789
6790 return benders->subprobenabled[probnumber];
6791}
6793/** sets a flag to indicate whether the master variables are all set to continuous */
6795 SCIP_BENDERS* benders, /**< Benders' decomposition */
6796 int probnumber, /**< the subproblem number */
6797 SCIP_Bool arecont /**< flag to indicate whether the master problem variables are continuous */
6798 )
6799{
6800 assert(benders != NULL);
6801 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6802
6803 /* if the master variables were all continuous and now are not, then the subproblem must exit probing mode and be
6804 * changed to non-LP subproblem */
6805 if( benders->mastervarscont[probnumber] && !arecont )
6806 {
6807 SCIP_BENDERSSUBTYPE subtype;
6808
6809 if( SCIPinProbing(SCIPbendersSubproblem(benders, probnumber)) )
6810 {
6811 SCIP_CALL( SCIPendProbing(SCIPbendersSubproblem(benders, probnumber)) );
6812 }
6813
6814 subtype = SCIPbendersGetSubproblemType(benders, probnumber);
6816
6817 if( subtype == SCIP_BENDERSSUBTYPE_CONVEXCONT )
6819 else if( subtype == SCIP_BENDERSSUBTYPE_NONCONVEXCONT )
6821 }
6822
6823 benders->mastervarscont[probnumber] = arecont;
6824
6825 return SCIP_OKAY;
6826}
6828/** returns whether the master variables are all set to continuous */
6830 SCIP_BENDERS* benders, /**< Benders' decomposition */
6831 int probnumber /**< the subproblem number */
6832 )
6833{
6834 assert(benders != NULL);
6835 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6836
6837 return benders->mastervarscont[probnumber];
6838}
6839
6840/** sets the objective type for the aggregation of the Benders' decomposition subproblem objectives. This is either the
6841 * summation of the objective values or a minimax of the objective values (such as for a makespan objective)
6842 */
6844 SCIP_BENDERS* benders, /**< Benders' decomposition */
6845 SCIP_BENDERSOBJTYPE objectivetype /**< the objective type */
6846 )
6847{
6848 assert(benders != NULL);
6849
6850 benders->objectivetype = objectivetype;
6851}
6853/** returns the objective type for the aggregation of the Benders' decomposition subproblem objectives */
6855 SCIP_BENDERS* benders /**< Benders' decomposition */
6856 )
6857{
6858 assert(benders != NULL);
6859
6860 return benders->objectivetype;
6861}
6863/** returns the number of cuts that have been transferred from sub SCIPs to the master SCIP */
6865 SCIP_BENDERS* benders /**< the Benders' decomposition data structure */
6866 )
6867{
6868 assert(benders != NULL);
6869
6870 return benders->ntransferred;
6871}
6872
6873/** updates the lower bound for the subproblem. If the lower bound is not greater than the previously stored lowerbound,
6874 * then no update occurs.
6875 */
6877 SCIP_BENDERS* benders, /**< Benders' decomposition */
6878 int probnumber, /**< the subproblem number */
6879 SCIP_Real lowerbound /**< the lower bound */
6880 )
6881{
6882 assert(benders != NULL);
6883 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6884
6885 if( EPSGE(lowerbound, benders->subproblowerbound[probnumber], 1e-06) )
6886 benders->subproblowerbound[probnumber] = lowerbound;
6887 else
6888 {
6889 SCIPdebugMessage("The lowerbound %g for subproblem %d is less than the currently stored lower bound %g\n",
6890 lowerbound, probnumber, benders->subproblowerbound[probnumber]);
6891 }
6892}
6894/** returns the stored lower bound for the given subproblem */
6896 SCIP_BENDERS* benders, /**< Benders' decomposition */
6897 int probnumber /**< the subproblem number */
6898 )
6899{
6900 assert(benders != NULL);
6901 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
6902
6903 return benders->subproblowerbound[probnumber];
6904}
6906/** returns the number of cuts that have been added for storage */
6908 SCIP_BENDERS* benders /**< Benders' decomposition */
6909 )
6910{
6911 assert(benders != NULL);
6912
6913 return benders->nstoredcuts;
6914}
6916/** returns the cuts that have been stored for transfer */
6918 SCIP_BENDERS* benders, /**< Benders' decomposition */
6919 int cutidx, /**< the index for the cut data that is requested */
6920 SCIP_VAR*** vars, /**< the variables that have non-zero coefficients in the cut */
6921 SCIP_Real** vals, /**< the coefficients of the variables in the cut */
6922 SCIP_Real* lhs, /**< the left hand side of the cut */
6923 SCIP_Real* rhs, /**< the right hand side of the cut */
6924 int* nvars /**< the number of variables with non-zero coefficients in the cut */
6925 )
6926{
6927 assert(benders != NULL);
6928 assert(vars != NULL);
6929 assert(vals != NULL);
6930 assert(lhs != NULL);
6931 assert(rhs != NULL);
6932 assert(nvars != NULL);
6933 assert(cutidx >= 0 && cutidx < benders->nstoredcuts);
6934
6935 (*vars) = benders->storedcuts[cutidx]->vars;
6936 (*vals) = benders->storedcuts[cutidx]->vals;
6937 (*lhs) = benders->storedcuts[cutidx]->lhs;
6938 (*rhs) = benders->storedcuts[cutidx]->rhs;
6939 (*nvars) = benders->storedcuts[cutidx]->nvars;
6940
6941 return SCIP_OKAY;
6942}
6943
6944/** returns the original problem data for the cuts that have been added by the Benders' cut plugin. The stored
6945 * variables and values will populate the input vars and vals arrays. Thus, memory must be allocated for the vars and
6946 * vals arrays
6947 */
6949 SCIP_BENDERS* benders, /**< Benders' decomposition cut */
6950 int cutidx, /**< the index for the cut data that is requested */
6951 SCIP_VAR*** vars, /**< the variables that have non-zero coefficients in the cut */
6952 SCIP_Real** vals, /**< the coefficients of the variables in the cut */
6953 SCIP_Real* lhs, /**< the left hand side of the cut */
6954 SCIP_Real* rhs, /**< the right hand side of the cut */
6955 int* nvars, /**< the number of variables with non-zero coefficients in the cut */
6956 int varssize /**< the available slots in the array */
6957 )
6958{
6959 SCIP_VAR* origvar;
6960 SCIP_Real scalar;
6961 SCIP_Real constant;
6962 int i;
6963
6964 assert(benders != NULL);
6965 assert(vars != NULL);
6966 assert(vals != NULL);
6967 assert(lhs != NULL);
6968 assert(rhs != NULL);
6969 assert(nvars != NULL);
6970 assert(cutidx >= 0 && cutidx < benders->nstoredcuts);
6971
6972 (*lhs) = benders->storedcuts[cutidx]->lhs;
6973 (*rhs) = benders->storedcuts[cutidx]->rhs;
6974 (*nvars) = benders->storedcuts[cutidx]->nvars;
6975
6976 /* if there are enough slots, then store the cut variables and values */
6977 if( varssize >= *nvars )
6978 {
6979 for( i = 0; i < *nvars; i++ )
6980 {
6981 /* getting the original variable for the transformed variable */
6982 origvar = benders->storedcuts[cutidx]->vars[i];
6983 scalar = 1.0;
6984 constant = 0.0;
6985 SCIP_CALL( SCIPvarGetOrigvarSum(&origvar, &scalar, &constant) );
6986
6987 (*vars)[i] = origvar;
6988 (*vals)[i] = benders->storedcuts[cutidx]->vals[i];
6989 }
6990 }
6991
6992 return SCIP_OKAY;
6993}
6995/** adds the data for the generated cuts to the Benders' cut storage */
6997 SCIP_BENDERS* benders, /**< Benders' decomposition cut */
6998 SCIP_SET* set, /**< global SCIP settings */
6999 SCIP_VAR** vars, /**< the variables that have non-zero coefficients in the cut */
7000 SCIP_Real* vals, /**< the coefficients of the variables in the cut */
7001 SCIP_Real lhs, /**< the left hand side of the cut */
7002 SCIP_Real rhs, /**< the right hand side of the cut */
7003 int nvars /**< the number of variables with non-zero coefficients in the cut */
7004 )
7005{
7006 SCIP_BENDERSCUTCUT* cut;
7007
7008 assert(benders != NULL);
7009 assert(set != NULL);
7010 assert(vars != NULL);
7011 assert(vals != NULL);
7012
7013 /* allocating the block memory for the cut storage */
7014 SCIP_CALL( SCIPallocBlockMemory(set->scip, &cut) );
7015
7016 /* storing the cut data */
7017 SCIP_CALL( SCIPduplicateBlockMemoryArray(set->scip, &cut->vars, vars, nvars) );
7018 SCIP_CALL( SCIPduplicateBlockMemoryArray(set->scip, &cut->vals, vals, nvars) );
7019 cut->lhs = lhs;
7020 cut->rhs = rhs;
7021 cut->nvars = nvars;
7022
7023 /* ensuring the required memory is available for the stored cuts array */
7024 if( benders->storedcutssize < benders->nstoredcuts + 1 )
7025 {
7026 int newsize;
7027
7028 newsize = SCIPsetCalcMemGrowSize(set, benders->nstoredcuts + 1);
7030 benders->storedcutssize, newsize) );
7031
7032 benders->storedcutssize = newsize;
7033 }
7034 assert(benders->storedcutssize >= benders->nstoredcuts + 1);
7035
7036 /* adding the cuts to the Benders' cut storage */
7037 benders->storedcuts[benders->nstoredcuts] = cut;
7038 benders->nstoredcuts++;
7039
7040 return SCIP_OKAY;
7041}
7043/** sets the sorted flags in the Benders' decomposition */
7045 SCIP_BENDERS* benders, /**< Benders' decomposition structure */
7046 SCIP_Bool sorted /**< the value to set the sorted flag to */
7047 )
7048{
7049 assert(benders != NULL);
7050
7051 benders->benderscutssorted = sorted;
7052 benders->benderscutsnamessorted = sorted;
7053}
7055/** inserts a Benders' cut into the Benders' cuts list */
7057 SCIP_BENDERS* benders, /**< Benders' decomposition structure */
7058 SCIP_SET* set, /**< global SCIP settings */
7059 SCIP_BENDERSCUT* benderscut /**< Benders' cut */
7060 )
7061{
7062 assert(benders != NULL);
7063 assert(benderscut != NULL);
7064
7065 if( benders->nbenderscuts >= benders->benderscutssize )
7066 {
7069 }
7070 assert(benders->nbenderscuts < benders->benderscutssize);
7071
7072 benders->benderscuts[benders->nbenderscuts] = benderscut;
7073 benders->nbenderscuts++;
7074 benders->benderscutssorted = FALSE;
7075
7076 return SCIP_OKAY;
7077}
7079/** returns the Benders' cut of the given name, or NULL if not existing */
7081 SCIP_BENDERS* benders, /**< Benders' decomposition */
7082 const char* name /**< name of Benderscut' decomposition */
7083 )
7084{
7085 int i;
7086
7087 assert(benders != NULL);
7088 assert(name != NULL);
7089
7090 for( i = 0; i < benders->nbenderscuts; i++ )
7091 {
7092 if( strcmp(SCIPbenderscutGetName(benders->benderscuts[i]), name) == 0 )
7093 return benders->benderscuts[i];
7094 }
7095
7096 return NULL;
7097}
7098
7099/** returns the array of currently available Benders' cuts; active Benders' decomposition are in the first slots of
7100 * the array
7101 */
7103 SCIP_BENDERS* benders /**< Benders' decomposition */
7104 )
7105{
7106 assert(benders != NULL);
7107
7108 if( !benders->benderscutssorted )
7109 {
7110 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutComp, benders->nbenderscuts);
7111 benders->benderscutssorted = TRUE;
7112 benders->benderscutsnamessorted = FALSE;
7113 }
7114
7115 return benders->benderscuts;
7116}
7118/** returns the number of currently available Benders' cuts */
7120 SCIP_BENDERS* benders /**< Benders' decomposition */
7121 )
7122{
7123 assert(benders != NULL);
7124
7125 return benders->nbenderscuts;
7126}
7128/** sets the priority of a Benders' decomposition */
7130 SCIP_BENDERS* benders, /**< Benders' decomposition */
7131 SCIP_BENDERSCUT* benderscut, /**< Benders' cut */
7132 int priority /**< new priority of the Benders' decomposition */
7133 )
7134{
7135 assert(benders != NULL);
7136 assert(benderscut != NULL);
7137
7138 benderscut->priority = priority;
7139 benders->benderscutssorted = FALSE;
7140
7141 return SCIP_OKAY;
7142}
7144/** sorts Benders' decomposition cuts by priorities */
7146 SCIP_BENDERS* benders /**< Benders' decomposition */
7147 )
7148{
7149 assert(benders != NULL);
7150
7151 if( !benders->benderscutssorted )
7152 {
7153 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutComp, benders->nbenderscuts);
7154 benders->benderscutssorted = TRUE;
7155 benders->benderscutsnamessorted = FALSE;
7156 }
7157}
7159/** sorts Benders' decomposition cuts by name */
7161 SCIP_BENDERS* benders /**< Benders' decomposition */
7162 )
7163{
7164 assert(benders != NULL);
7165
7166 if( !benders->benderscutsnamessorted )
7167 {
7168 SCIPsortPtr((void**)benders->benderscuts, SCIPbenderscutCompName, benders->nbenderscuts);
7169 benders->benderscutssorted = FALSE;
7170 benders->benderscutsnamessorted = TRUE;
7171 }
7172}
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:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define EPSGE(x, y, eps)
Definition: def.h:187
#define SCIP_Longint
Definition: def.h:141
#define SCIP_MAXTREEDEPTH
Definition: def.h:297
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_ALLOC(x)
Definition: def.h:366
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIPABORT()
Definition: def.h:327
#define SCIP_CALL(x)
Definition: def.h:355
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:397
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)
Definition: scip_general.c:759
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:402
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:562
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
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,...)
Definition: scip_message.c:208
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
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)
Definition: scip_param.c:1033
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
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
SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), SCIP_DECL_PQUEUEELEMCHGPOS((*elemchgpos)))
Definition: misc.c:1297
void * SCIPpqueueRemove(SCIP_PQUEUE *pqueue)
Definition: misc.c:1495
SCIP_BENDERSOBJTYPE SCIPbendersGetObjectiveType(SCIP_BENDERS *benders)
Definition: benders.c:6852
SCIP_Real SCIPbendersGetSetupTime(SCIP_BENDERS *benders)
Definition: benders.c:6083
void SCIPbendersSetSubproblemObjval(SCIP_BENDERS *benders, int probnumber, SCIP_Real objval)
Definition: benders.c:6285
SCIP_RETCODE SCIPbendersSolSlackVarsActive(SCIP_BENDERS *benders, SCIP_Bool *activeslack)
Definition: benders.c:6314
SCIP_Bool SCIPbendersCutRelaxation(SCIP_BENDERS *benders)
Definition: benders.c:6145
int SCIPbendersGetNTransferredCuts(SCIP_BENDERS *benders)
Definition: benders.c:6862
SCIP_Bool SCIPbendersSubproblemIsConvex(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6465
int SCIPbendersGetNStrengthenFails(SCIP_BENDERS *benders)
Definition: benders.c:6073
int SCIPgetBendersNSubproblems(SCIP *scip, SCIP_BENDERS *benders)
Definition: scip_benders.c:747
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:6946
SCIP_BENDERS ** SCIPgetBenders(SCIP *scip)
Definition: scip_benders.c:508
void SCIPbendersSetSubproblemIsNonlinear(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isnonlinear)
Definition: benders.c:6487
void SCIPbendersSetMasterIsNonlinear(SCIP_BENDERS *benders, SCIP_Bool isnonlinear)
Definition: benders.c:6529
SCIP_BENDERS * SCIPfindBenders(SCIP *scip, const char *name)
Definition: scip_benders.c:493
void SCIPbendersSetData(SCIP_BENDERS *benders, SCIP_BENDERSDATA *bendersdata)
Definition: benders.c:5802
SCIP_Bool SCIPbendersOnlyCheckConvexRelax(SCIP_BENDERS *benders, SCIP_Bool subscipsoff)
Definition: benders.c:3301
SCIP_Bool SCIPbendersSubproblemIsNonlinear(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6507
int SCIPbendersGetPriority(SCIP_BENDERS *benders)
Definition: benders.c:5987
SCIP_VAR * SCIPbendersGetAuxiliaryVar(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6213
SCIP_BENDERSCUT * SCIPfindBenderscut(SCIP_BENDERS *benders, const char *name)
Definition: benders.c:7078
const char * SCIPbendersGetDesc(SCIP_BENDERS *benders)
Definition: benders.c:5977
int SCIPbendersGetNConvexSubproblems(SCIP_BENDERS *benders)
Definition: benders.c:6477
SCIP_BENDERSSUBTYPE SCIPbendersGetSubproblemType(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6424
SCIP_VAR ** SCIPbendersGetSubproblemMasterVars(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6235
SCIP_RETCODE SCIPbendersSolveSubproblemCIP(SCIP *scip, SCIP_BENDERS *benders, int probnumber, SCIP_STATUS *solvestatus, SCIP_Bool solvecip)
Definition: benders.c:5230
int SCIPbendersGetNNonlinearSubproblems(SCIP_BENDERS *benders)
Definition: benders.c:6519
void SCIPsetBendersPriority(SCIP *scip, SCIP_BENDERS *benders, int priority)
Definition: scip_benders.c:590
SCIP_NLPPARAM SCIPbendersGetNLPParam(SCIP_BENDERS *benders)
Definition: benders.c:5047
SCIP_Bool SCIPbendersSubproblemIsEnabled(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6780
SCIP_RETCODE SCIPgetBendersMasterVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar)
Definition: scip_benders.c:685
int SCIPbendersGetNStrengthenCalls(SCIP_BENDERS *benders)
Definition: benders.c:6063
SCIP_RETCODE SCIPgetBendersSubproblemVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar, int probnumber)
Definition: scip_benders.c:721
int SCIPbendersGetNStoredCuts(SCIP_BENDERS *benders)
Definition: benders.c:6905
SCIP_RETCODE SCIPbendersSolveSubproblemLP(SCIP *scip, SCIP_BENDERS *benders, int probnumber, SCIP_STATUS *solvestatus, SCIP_Real *objective)
Definition: benders.c:5060
int SCIPbendersGetNBenderscuts(SCIP_BENDERS *benders)
Definition: benders.c:7117
void SCIPbendersSetSubproblemIsConvex(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isconvex)
Definition: benders.c:6442
SCIP_Bool SCIPbendersIsActive(SCIP_BENDERS *benders)
Definition: benders.c:2988
SCIP_Bool SCIPbendersSubproblemsAreInfeasible(SCIP_BENDERS *benders)
Definition: benders.c:6577
void SCIPbendersSetSubproblemIsSetup(SCIP_BENDERS *benders, int probnumber, SCIP_Bool issetup)
Definition: benders.c:6675
SCIP_BENDERSDATA * SCIPbendersGetData(SCIP_BENDERS *benders)
Definition: benders.c:5792
const char * SCIPbendersGetName(SCIP_BENDERS *benders)
Definition: benders.c:5967
SCIP_Bool SCIPbendersCutPseudo(SCIP_BENDERS *benders)
Definition: benders.c:6135
SCIP_VAR ** SCIPbendersGetAuxiliaryVars(SCIP_BENDERS *benders)
Definition: benders.c:6225
int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
Definition: benders.c:6011
void SCIPbendersSetSubproblemType(SCIP_BENDERS *benders, int probnumber, SCIP_BENDERSSUBTYPE subprobtype)
Definition: benders.c:6399
int SCIPbendersGetNStrengthenCutsFound(SCIP_BENDERS *benders)
Definition: benders.c:6053
void SCIPbendersUpdateSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber, SCIP_Real lowerbound)
Definition: benders.c:6874
SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6021
void SCIPbendersGetSubproblemMasterVarsData(SCIP_BENDERS *benders, int probnumber, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars)
Definition: benders.c:6259
SCIP_Bool SCIPbendersMasterIsNonlinear(SCIP_BENDERS *benders)
Definition: benders.c:6540
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:6915
int SCIPbendersGetNCalls(SCIP_BENDERS *benders)
Definition: benders.c:6033
SCIP_Bool SCIPbendersIsInitialized(SCIP_BENDERS *benders)
Definition: benders.c:6115
int SCIPbendersGetNCutsFound(SCIP_BENDERS *benders)
Definition: benders.c:6043
SCIP_Bool SCIPbendersShareAuxVars(SCIP_BENDERS *benders)
Definition: benders.c:6155
SCIP_Bool SCIPbendersCutLP(SCIP_BENDERS *benders)
Definition: benders.c:6125
SCIP_RETCODE SCIPbendersSetBenderscutPriority(SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, int priority)
Definition: benders.c:7127
SCIP_Real SCIPbendersGetTime(SCIP_BENDERS *benders)
Definition: benders.c:6093
SCIP_Bool SCIPbendersSubproblemIsIndependent(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6740
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)
Definition: scip_benders.c:647
SCIP_BENDERSCUT ** SCIPbendersGetBenderscuts(SCIP_BENDERS *benders)
Definition: benders.c:7100
SCIP_VAR * SCIPbenderGetMasterAuxiliaryVar(SCIP_BENDERS *benders)
Definition: benders.c:6203
SCIP_Real SCIPbendersGetSubproblemObjval(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6302
void SCIPbendersSetSubproblemIsIndependent(SCIP_BENDERS *benders, int probnumber, SCIP_Bool isindep)
Definition: benders.c:6700
SCIP_Bool SCIPbendersInStrengthenRound(SCIP_BENDERS *benders)
Definition: benders.c:6550
SCIP_Bool SCIPbendersSubproblemIsSetup(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6688
SCIP_Real SCIPbendersGetSubproblemLowerbound(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6893
int SCIPbendersGetNSubproblemMasterVars(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6247
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 SCIPsetEventhdlrInitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTINITSOL((*eventinitsol)))
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_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip_event.c:241
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:396
SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:406
SCIP_RETCODE SCIPsetEventhdlrExitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTEXITSOL((*eventexitsol)))
Definition: scip_event.c:213
void SCIPeventhdlrSetData(SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: event.c:416
SCIP_RETCODE SCIPsetEventhdlrFree(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTFREE((*eventfree)))
Definition: scip_event.c:157
SCIP_RETCODE SCIPsetEventhdlrExit(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTEXIT((*eventexit)))
Definition: scip_event.c:185
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)
Definition: scip_probing.c:346
SCIP_RETCODE SCIPchgVarObjProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
Definition: scip_probing.c:475
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:98
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
Definition: scip_probing.c:120
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_probing.c:825
SCIP_RETCODE SCIPendProbing(SCIP *scip)
Definition: scip_probing.c:261
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:2981
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:516
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip_sol.c:884
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:2349
SCIP_RETCODE 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:2132
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3603
SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
Definition: scip_solve.c:3462
SCIP_RETCODE SCIPinterruptSolve(SCIP *scip)
Definition: scip_solve.c:3548
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2635
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)
Definition: scip_timing.c:378
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
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)
Definition: misc_linear.c:112
SCIP_RETCODE SCIPconsAddCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
Definition: misc_linear.c:675
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:5766
void SCIPbendersSetSolvesubconvex(SCIP_BENDERS *benders, SCIP_DECL_BENDERSSOLVESUBCONVEX((*benderssolvesubconvex)))
Definition: benders.c:5912
static void createSolveSubproblemIndexList(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSENFOTYPE type, int **solveidx, int *nsolveidx)
Definition: benders.c:3337
#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:5371
void SCIPbendersSetPresubsolve(SCIP_BENDERS *benders, SCIP_DECL_BENDERSPRESUBSOLVE((*benderspresubsolve)))
Definition: benders.c:5901
#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:6841
SCIP_RETCODE SCIPbendersActivate(SCIP_BENDERS *benders, SCIP_SET *set, int nsubproblems)
Definition: benders.c:2790
SCIP_RETCODE SCIPbendersComputeSubproblemLowerbound(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber, SCIP_Real *lowerbound, SCIP_Bool *infeasible)
Definition: benders.c:5421
void SCIPbendersRemoveSubproblems(SCIP_BENDERS *benders)
Definition: benders.c:6191
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:4401
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:1503
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:3142
void SCIPbendersSetExit(SCIP_BENDERS *benders, SCIP_DECL_BENDERSEXIT((*bendersexit)))
Definition: benders.c:5846
#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:5321
#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:5997
static SCIP_DECL_SORTPTRCOMP(benderssubcompdefault)
Definition: benders.c:609
static SCIP_Bool subproblemIsActive(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:3326
static SCIP_RETCODE addSlackVars(SCIP *scip, SCIP_BENDERS *benders, SCIP_CONS *cons, SCIP_CONSHDLR **linearconshdlrs, SCIP_CONSHDLR *nlconshdlr, int nlinearconshdlrs)
Definition: benders.c:1541
SCIP_RETCODE SCIPbendersExit(SCIP_BENDERS *benders, SCIP_SET *set)
Definition: benders.c:2451
void SCIPbendersSetInitsol(SCIP_BENDERS *benders, SCIP_DECL_BENDERSINITSOL((*bendersinitsol)))
Definition: benders.c:5879
static SCIP_DECL_EVENTINITSOL(eventInitsolBendersNodefocus)
Definition: benders.c:249
SCIP_RETCODE SCIPbendersChgMastervarsToCont(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
Definition: benders.c:6587
#define SCIP_DEFAULT_NLPITERLIMIT
Definition: benders.c:81
void SCIPbendersSortBenderscuts(SCIP_BENDERS *benders)
Definition: benders.c:7143
SCIP_RETCODE SCIPbendersSetupSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber, SCIP_BENDERSENFOTYPE type)
Definition: benders.c:4641
static SCIP_RETCODE setAndUpdateCorePoint(SCIP *scip, SCIP_BENDERS *benders)
Definition: benders.c:3056
#define SCIP_DEFAULT_STRENGTHENMULT
Definition: benders.c:69
static SCIP_RETCODE createSubproblems(SCIP_BENDERS *benders, SCIP_SET *set)
Definition: benders.c:2000
SCIP_RETCODE SCIPbendersSetMastervarsCont(SCIP_BENDERS *benders, int probnumber, SCIP_Bool arecont)
Definition: benders.c:6792
static SCIP_RETCODE freeEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr)
Definition: benders.c:201
#define SCIP_DEFAULT_STRENGTHENINTPOINT
Definition: benders.c:73
void SCIPbendersSetSolvesub(SCIP_BENDERS *benders, SCIP_DECL_BENDERSSOLVESUB((*benderssolvesub)))
Definition: benders.c:5923
void SCIPbendersSetSubproblemsAreInfeasible(SCIP_BENDERS *benders, SCIP_SET *set)
Definition: benders.c:6562
void SCIPbendersSetExitsol(SCIP_BENDERS *benders, SCIP_DECL_BENDERSEXITSOL((*bendersexitsol)))
Definition: benders.c:5890
void SCIPbendersSortBenderscutsName(SCIP_BENDERS *benders)
Definition: benders.c:7158
static SCIP_RETCODE resetOrigSubproblemParams(SCIP *subproblem, SCIP_SUBPROBPARAMS *origparams)
Definition: benders.c:5021
#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:1653
static SCIP_RETCODE updateAuxiliaryVarLowerbound(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_RESULT *result)
Definition: benders.c:2999
#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:3666
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:3426
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
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:2287
SCIP_RETCODE SCIPbendersMergeSubproblemIntoMaster(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, int probnumber)
Definition: benders.c:5583
#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_DECL_EVENTEXITSOL(eventExitsolBendersNodefocus)
Definition: benders.c:262
static SCIP_RETCODE initialiseSubproblem(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber, SCIP_Bool *infeasible, SCIP_Bool *success)
Definition: benders.c:1699
#define SCIP_DEFAULT_AUXVARSIMPLINT
Definition: benders.c:67
static SCIP_RETCODE copyMemoryAndTimeLimits(SCIP *scip, SCIP *subproblem)
Definition: benders.c:4910
static SCIP_RETCODE transferBendersCuts(SCIP *sourcescip, SCIP *subscip, SCIP_BENDERS *benders)
Definition: benders.c:2405
void SCIPbendersSetBenderscutsSorted(SCIP_BENDERS *benders, SCIP_Bool sorted)
Definition: benders.c:7042
#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
SCIP_RETCODE SCIPbendersFree(SCIP_BENDERS **benders, SCIP_SET *set)
Definition: benders.c:1420
void SCIPbendersSetSubproblemComp(SCIP_BENDERS *benders, SCIP_DECL_SORTPTRCOMP((*benderssubcomp)))
Definition: benders.c:5945
#define SLACKVAR_NAME
Definition: benders.c:88
SCIP_RETCODE SCIPbendersInitsol(SCIP_BENDERS *benders, SCIP_SET *set)
Definition: benders.c:2701
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:4472
void SCIPbendersSetFreesub(SCIP_BENDERS *benders, SCIP_DECL_BENDERSFREESUB((*bendersfreesub)))
Definition: benders.c:5956
#define MIPNODEFOCUS_EVENTHDLR_DESC
Definition: benders.c:96
static SCIP_DECL_EVENTFREE(eventFreeBendersNodefocus)
Definition: benders.c:288
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
#define SCIP_DEFAULT_NOIMPROVELIMIT
Definition: benders.c:70
static SCIP_DECL_EVENTEXIT(eventExitBendersNodefocus)
Definition: benders.c:275
static SCIP_DECL_EVENTEXEC(eventExecBendersNodefocus)
Definition: benders.c:227
static SCIP_RETCODE setSubproblemParams(SCIP *scip, SCIP *subproblem)
Definition: benders.c:4970
void SCIPbendersSetInit(SCIP_BENDERS *benders, SCIP_DECL_BENDERSINIT((*bendersinit)))
Definition: benders.c:5835
#define NLINEARCONSHDLRS
Definition: benders.c:89
SCIP_RETCODE SCIPbendersDeactivate(SCIP_BENDERS *benders, SCIP_SET *set)
Definition: benders.c:2890
static SCIP_DECL_PARAMCHGD(paramChgdBendersPriority)
Definition: benders.c:1003
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:6994
void SCIPbendersSetCopy(SCIP_BENDERS *benders, SCIP_DECL_BENDERSCOPY((*benderscopy)))
Definition: benders.c:5813
SCIP_RETCODE SCIPbendersAddSubproblem(SCIP_BENDERS *benders, SCIP *subproblem)
Definition: benders.c:6167
#define SCIP_DEFAULT_TRANSFERCUTS
Definition: benders.c:59
SCIP_Real SCIPbendersGetAuxiliaryVarVal(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_SOL *sol, int probnumber)
Definition: benders.c:5400
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:3864
SCIP_Bool SCIPbendersGetMastervarsCont(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6827
static SCIP_RETCODE exitsolEventhandler(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTTYPE eventtype)
Definition: benders.c:157
void SCIPbendersSetFree(SCIP_BENDERS *benders, SCIP_DECL_BENDERSFREE((*bendersfree)))
Definition: benders.c:5824
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:4943
#define MIPNODEFOCUS_EVENTHDLR_NAME
Definition: benders.c:95
#define SCIP_DEFAULT_SUBPROBFRAC
Definition: benders.c:65
#define SCIP_DEFAULT_EXECFEASPHASE
Definition: benders.c:77
#define NODEFOCUS_EVENTHDLR_NAME
Definition: benders.c:92
SCIP_RETCODE SCIPbendersInitpre(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_STAT *stat)
Definition: benders.c:2617
void SCIPbendersEnableOrDisableClocks(SCIP_BENDERS *benders, SCIP_Bool enable)
Definition: benders.c:6103
void SCIPbendersSetExitpre(SCIP_BENDERS *benders, SCIP_DECL_BENDERSEXITPRE((*bendersexitpre)))
Definition: benders.c:5868
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:3377
static SCIP_RETCODE checkSubproblemConvexity(SCIP_BENDERS *benders, SCIP_SET *set, int probnumber)
Definition: benders.c:1792
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 SCIPbendersSetInitpre(SCIP_BENDERS *benders, SCIP_DECL_BENDERSINITPRE((*bendersinitpre)))
Definition: benders.c:5857
void SCIPbendersSetSubproblemEnabled(SCIP_BENDERS *benders, int probnumber, SCIP_Bool enabled)
Definition: benders.c:6754
void SCIPbendersSetPostsolve(SCIP_BENDERS *benders, SCIP_DECL_BENDERSPOSTSOLVE((*benderspostsolve)))
Definition: benders.c:5934
SCIP_RETCODE SCIPbendersIncludeBenderscut(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSCUT *benderscut)
Definition: benders.c:7054
SCIP_RETCODE SCIPbendersExitpre(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_STAT *stat)
Definition: benders.c:2675
static int numSubproblemsToCheck(SCIP_BENDERS *benders, SCIP_SET *set, SCIP_BENDERSENFOTYPE type)
Definition: benders.c:3311
SCIP_RETCODE SCIPbendersExitsol(SCIP_BENDERS *benders, SCIP_SET *set)
Definition: benders.c:2734
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:4801
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:1742
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
static SCIP_RETCODE checkSubproblemIndependence(SCIP *scip, SCIP_BENDERS *benders)
Definition: benders.c:2563
SCIP_RETCODE SCIPbendersInit(SCIP_BENDERS *benders, SCIP_SET *set)
Definition: benders.c:2207
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
int * nsubmastervars
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
char strengthenintpoint
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
datastructures for Benders' decomposition cuts techniques
Definition: heur_padm.c:135
#define SCIP_DECL_BENDERSFREESUB(x)
Definition: type_benders.h:362
#define SCIP_DECL_BENDERSCREATESUB(x)
Definition: type_benders.h:206
#define SCIP_DECL_BENDERSCOPY(x)
Definition: type_benders.h:107
@ SCIP_BENDERSENFOTYPE_LP
Definition: type_benders.h:51
@ SCIP_BENDERSENFOTYPE_CHECK
Definition: type_benders.h:54
@ SCIP_BENDERSENFOTYPE_PSEUDO
Definition: type_benders.h:53
#define SCIP_DECL_BENDERSSOLVESUB(x)
Definition: type_benders.h:304
enum SCIP_BendersObjectiveType SCIP_BENDERSOBJTYPE
Definition: type_benders.h:91
#define SCIP_DECL_BENDERSEXITPRE(x)
Definition: type_benders.h:152
@ SCIP_BENDERSSUBSTATUS_AUXVIOL
Definition: type_benders.h:71
@ SCIP_BENDERSSUBSTATUS_UNKNOWN
Definition: type_benders.h:69
@ SCIP_BENDERSSUBSTATUS_INFEAS
Definition: type_benders.h:72
@ SCIP_BENDERSSUBSTATUS_OPTIMAL
Definition: type_benders.h:70
#define SCIP_DECL_BENDERSSOLVESUBCONVEX(x)
Definition: type_benders.h:271
#define SCIP_DECL_BENDERSINIT(x)
Definition: type_benders.h:124
#define SCIP_DECL_BENDERSFREE(x)
Definition: type_benders.h:115
#define SCIP_DECL_BENDERSEXITSOL(x)
Definition: type_benders.h:174
@ SCIP_BENDERSOBJTYPE_SUM
Definition: type_benders.h:88
@ SCIP_BENDERSOBJTYPE_MAX
Definition: type_benders.h:89
#define SCIP_DECL_BENDERSPRESUBSOLVE(x)
Definition: type_benders.h:230
@ SCIP_BENDERSSUBTYPE_NONCONVEXDIS
Definition: type_benders.h:81
@ SCIP_BENDERSSUBTYPE_CONVEXCONT
Definition: type_benders.h:78
@ SCIP_BENDERSSUBTYPE_NONCONVEXCONT
Definition: type_benders.h:80
@ SCIP_BENDERSSUBTYPE_CONVEXDIS
Definition: type_benders.h:79
@ SCIP_BENDERSSUBTYPE_UNKNOWN
Definition: type_benders.h:82
enum SCIP_BendersSubType SCIP_BENDERSSUBTYPE
Definition: type_benders.h:84
@ SCIP_BENDERSSOLVELOOP_CIP
Definition: type_benders.h:61
@ SCIP_BENDERSSOLVELOOP_CONVEX
Definition: type_benders.h:60
@ SCIP_BENDERSSOLVELOOP_USERCONVEX
Definition: type_benders.h:62
@ SCIP_BENDERSSOLVELOOP_USERCIP
Definition: type_benders.h:63
enum SCIP_BendersSolveLoop SCIP_BENDERSSOLVELOOP
Definition: type_benders.h:65
enum SCIP_BendersEnfoType SCIP_BENDERSENFOTYPE
Definition: type_benders.h:56
#define SCIP_DECL_BENDERSGETVAR(x)
Definition: type_benders.h:378
enum SCIP_BendersSubStatus SCIP_BENDERSSUBSTATUS
Definition: type_benders.h:74
#define SCIP_DECL_BENDERSPOSTSOLVE(x)
Definition: type_benders.h:340
#define SCIP_DECL_BENDERSINITPRE(x)
Definition: type_benders.h:144
#define SCIP_DECL_BENDERSEXIT(x)
Definition: type_benders.h:133
#define SCIP_DECL_BENDERSINITSOL(x)
Definition: type_benders.h:163
struct SCIP_BendersData SCIP_BENDERSDATA
Definition: type_benders.h:94
@ SCIP_CLOCKTYPE_DEFAULT
Definition: type_clock.h:43
#define SCIP_EVENTTYPE_NODEFOCUSED
Definition: type_event.h:93
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:160
#define SCIP_EVENTTYPE_NODESOLVED
Definition: type_event.h:138
#define SCIP_EVENTTYPE_BESTSOLFOUND
Definition: type_event.h:106
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:156
SCIP_EXPRCURV
Definition: type_expr.h:61
@ SCIP_EXPRCURV_CONVEX
Definition: type_expr.h:63
@ SCIP_EXPRCURV_CONCAVE
Definition: type_expr.h:64
@ 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
@ SCIP_VERBLEVEL_NONE
Definition: type_message.h:57
@ SCIP_VERBLEVEL_MINIMAL
Definition: type_message.h:59
@ SCIP_VERBLEVEL_HIGH
Definition: type_message.h:61
@ SCIP_VERBLEVEL_FULL
Definition: type_message.h:62
#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
enum SCIP_NlpTermStat SCIP_NLPTERMSTAT
Definition: type_nlpi.h:184
@ SCIP_PARAMSETTING_OFF
Definition: type_paramset.h:63
struct SCIP_ParamData SCIP_PARAMDATA
Definition: type_paramset.h:87
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_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
Definition: type_retcode.h:53
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ 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
@ 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_VarData SCIP_VARDATA
Definition: type_var.h:167
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