Scippy

SCIP

Solving Constraint Integer Programs

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