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