Scippy

SCIP

Solving Constraint Integer Programs

benderscut_opt.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 benderscut_opt.c
26 * @ingroup OTHER_CFILES
27 * @brief Generates a standard Benders' decomposition optimality cut
28 * @author Stephen J. Maher
29 */
30
31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32
33#include "scip/pub_expr.h"
34#include "scip/benderscut_opt.h"
35#include "scip/cons_linear.h"
36#include "scip/pub_benderscut.h"
37#include "scip/pub_benders.h"
38#include "scip/pub_lp.h"
39#include "scip/pub_nlp.h"
40#include "scip/pub_message.h"
41#include "scip/pub_misc.h"
43#include "scip/pub_var.h"
44#include "scip/scip.h"
45#include <string.h>
46
47#define BENDERSCUT_NAME "optimality"
48#define BENDERSCUT_DESC "Standard Benders' decomposition optimality cut"
49#define BENDERSCUT_PRIORITY 5000
50#define BENDERSCUT_LPCUT TRUE
51
52#define SCIP_DEFAULT_ADDCUTS FALSE /** Should cuts be generated, instead of constraints */
53#define SCIP_DEFAULT_CALCMIR TRUE /** Should the mixed integer rounding procedure be used for the cut */
54
55/*
56 * Data structures
57 */
58
59/** Benders' decomposition cuts data */
60struct SCIP_BenderscutData
61{
62 SCIP_Bool addcuts; /**< should cuts be generated instead of constraints */
63 SCIP_Bool calcmir; /**< should the mixed integer rounding procedure be applied to cuts */
64};
65
66
67/*
68 * Local methods
69 */
70
71/** in the case of numerical troubles, the LP is resolved with solution polishing activated */
72static
74 SCIP* subproblem, /**< the SCIP data structure */
75 SCIP_Bool* success /**< TRUE is the resolving of the LP was successful */
76 )
77{
78 int oldpolishing;
79 SCIP_Bool lperror;
80 SCIP_Bool cutoff;
81
82 assert(subproblem != NULL);
83 assert(SCIPinProbing(subproblem));
84
85 (*success) = FALSE;
86
87 /* setting the solution polishing parameter */
88 SCIP_CALL( SCIPgetIntParam(subproblem, "lp/solutionpolishing", &oldpolishing) );
89 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/solutionpolishing", 2) );
90
91 /* resolving the probing LP */
92 SCIP_CALL( SCIPsolveProbingLP(subproblem, -1, &lperror, &cutoff) );
93
94 if( SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_OPTIMAL )
95 (*success) = TRUE;
96
97 /* resetting the solution polishing parameter */
98 SCIP_CALL( SCIPsetIntParam(subproblem, "lp/solutionpolishing", oldpolishing) );
99
100 return SCIP_OKAY;
101}
102
103/** verifying the activity of the cut when master variables are within epsilon of their upper or lower bounds
104 *
105 * When setting up the Benders' decomposition subproblem, master variables taking values that are within epsilon
106 * greater than their upper bound or less than their lower bound are set to their upper and lower bounds respectively.
107 * As such, there can be a difference between the subproblem dual solution objective and the optimality cut activity,
108 * when computed using the master problem solution directly. This check is to verify whether this difference is an
109 * actual error or due to the violation of the upper and lower bounds when setting up the Benders' decomposition
110 * subproblem.
111 */
112static
114 SCIP* masterprob, /**< the SCIP data structure */
115 SCIP_SOL* sol, /**< the master problem solution */
116 SCIP_VAR** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
117 SCIP_Real* vals, /**< pointer to array of coefficients of the variables in the generated cut */
118 SCIP_Real lhs, /**< the left hand side of the cut */
119 SCIP_Real checkobj, /**< the objective of the subproblem computed from the dual solution */
120 int nvars, /**< the number of variables in the cut */
121 SCIP_Bool* valid /**< returns true is the cut is valid */
122 )
123{
124 SCIP_Real verifyobj;
125 int i;
126
127 assert(masterprob != NULL);
128 assert(vars != NULL);
129 assert(vals != NULL);
130
131 /* initialising the verify objective with the left hand side of the optimality cut */
132 verifyobj = lhs;
133
134 /* computing the activity of the cut from the master solution and the constraint values */
135 for( i = 0; i < nvars; i++ )
136 {
137 SCIP_Real solval;
138
139 solval = SCIPgetSolVal(masterprob, sol, vars[i]);
140
141 /* checking whether the solution value is less than or greater than the variable bounds */
142 if( !SCIPisLT(masterprob, solval, SCIPvarGetUbLocal(vars[i])) )
143 solval = SCIPvarGetUbLocal(vars[i]);
144 else if( !SCIPisGT(masterprob, solval, SCIPvarGetLbLocal(vars[i])) )
145 solval = SCIPvarGetLbLocal(vars[i]);
146
147 verifyobj -= solval*vals[i];
148 }
149
150 (*valid) = SCIPisFeasEQ(masterprob, checkobj, verifyobj);
151
152 return SCIP_OKAY;
153}
154
155/** when solving NLP subproblems, numerical issues are addressed by tightening the feasibility tolerance */
156static
158 SCIP* subproblem, /**< the SCIP data structure */
159 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
160 SCIP_Real multiplier, /**< the amount by which to decrease the tolerance */
161 SCIP_Bool* success /**< TRUE is the resolving of the LP was successful */
162 )
163{
164 SCIP_NLPSOLSTAT nlpsolstat;
165#ifdef SCIP_DEBUG
166 SCIP_NLPTERMSTAT nlptermstat;
167#endif
168 SCIP_NLPPARAM nlpparam = SCIPbendersGetNLPParam(benders);
169#ifdef SCIP_MOREDEBUG
170 SCIP_SOL* nlpsol;
171#endif
172
173 assert(subproblem != NULL);
174 assert(SCIPinProbing(subproblem));
175
176 (*success) = FALSE;
177
178 /* reduce the default feasibility and optimality tolerance by given factor (typically 0.01) */
179 nlpparam.feastol *= multiplier;
180 nlpparam.opttol *= multiplier;
181
182 SCIP_CALL( SCIPsolveNLPParam(subproblem, nlpparam) );
183
184 nlpsolstat = SCIPgetNLPSolstat(subproblem);
185#ifdef SCIP_DEBUG
186 nlptermstat = SCIPgetNLPTermstat(subproblem);
187 SCIPdebugMsg(subproblem, "NLP solstat %d termstat %d\n", nlpsolstat, nlptermstat);
188#endif
189
190 if( nlpsolstat == SCIP_NLPSOLSTAT_LOCOPT || nlpsolstat == SCIP_NLPSOLSTAT_GLOBOPT
191 || nlpsolstat == SCIP_NLPSOLSTAT_FEASIBLE )
192 {
193#ifdef SCIP_MOREDEBUG
194 SCIP_CALL( SCIPcreateNLPSol(subproblem, &nlpsol, NULL) );
195 SCIP_CALL( SCIPprintSol(subproblem, nlpsol, NULL, FALSE) );
196 SCIP_CALL( SCIPfreeSol(subproblem, &nlpsol) );
197#endif
198
199 (*success) = TRUE;
200 }
201
202 return SCIP_OKAY;
203}
204
205/** adds a variable and value to the constraint/row arrays */
206static
208 SCIP* masterprob, /**< the SCIP instance of the master problem */
209 SCIP_VAR*** vars, /**< pointer to the array of variables in the generated cut with non-zero coefficient */
210 SCIP_Real** vals, /**< pointer to the array of coefficients of the variables in the generated cut */
211 SCIP_VAR* addvar, /**< the variable that will be added to the array */
212 SCIP_Real addval, /**< the value that will be added to the array */
213 int* nvars, /**< the number of variables in the variable array */
214 int* varssize /**< the length of the variable size */
215 )
216{
217 assert(masterprob != NULL);
218 assert(vars != NULL);
219 assert(*vars != NULL);
220 assert(vals != NULL);
221 assert(*vals != NULL);
222 assert(addvar != NULL);
223 assert(nvars != NULL);
224 assert(varssize != NULL);
225
226 if( *nvars >= *varssize )
227 {
228 *varssize = SCIPcalcMemGrowSize(masterprob, *varssize + 1);
229 SCIP_CALL( SCIPreallocBufferArray(masterprob, vars, *varssize) );
230 SCIP_CALL( SCIPreallocBufferArray(masterprob, vals, *varssize) );
231 }
232 assert(*nvars < *varssize);
233
234 (*vars)[*nvars] = addvar;
235 (*vals)[*nvars] = addval;
236 (*nvars)++;
237
238 return SCIP_OKAY;
239}
240
241/** returns the variable solution either from the NLP or from the primal vals array */
242static
244 SCIP_VAR* var, /**< the variable for which the solution is requested */
245 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
246 SCIP_HASHMAP* var2idx /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
247 )
248{
249 SCIP_Real varsol;
250 int idx;
251
252 assert(var != NULL);
253 assert((primalvals == NULL && var2idx == NULL) || (primalvals != NULL && var2idx != NULL));
254
255 if( var2idx != NULL && primalvals != NULL )
256 {
257 assert(SCIPhashmapExists(var2idx, (void*)var) );
258 idx = SCIPhashmapGetImageInt(var2idx, (void*)var);
259 varsol = primalvals[idx];
260 }
261 else
262 varsol = SCIPvarGetNLPSol(var);
263
264 return varsol;
265}
266
267/** calculates a MIR cut from the coefficients of the standard optimality cut */
268static
270 SCIP* masterprob, /**< the SCIP instance of the master problem */
271 SCIP_SOL* sol, /**< primal CIP solution */
272 SCIP_VAR** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
273 SCIP_Real* vals, /**< pointer to array of coefficients of the variables in the generated cut */
274 SCIP_Real lhs, /**< the left hand side of the cut */
275 SCIP_Real rhs, /**< the right hand side of the cut */
276 int nvars, /**< the number of variables in the cut */
277 SCIP_Real* cutcoefs, /**< the coefficients of the MIR cut */
278 int* cutinds, /**< the variable indices of the MIR cut */
279 SCIP_Real* cutrhs, /**< the RHS of the MIR cut */
280 int* cutnnz, /**< the number of non-zeros in the cut */
281 SCIP_Bool* success /**< was the MIR cut successfully computed? */
282 )
283{
284 SCIP_AGGRROW* aggrrow;
285 SCIP_Real* rowvals;
286 int* rowinds;
287
288 SCIP_Real cutefficacy;
289 int cutrank;
290 SCIP_Bool cutislocal;
291
292 SCIP_Bool cutsuccess;
293
294 int i;
295
296 /* creating the aggregation row. There will be only a single row in this aggregation, since it is only used to
297 * compute the MIR coefficients
298 */
299 SCIP_CALL( SCIPaggrRowCreate(masterprob, &aggrrow) );
300
301 /* retrieving the indices for the variables in the optimality cut. All of the values must be negated, since the
302 * aggregation row requires a RHS, where the optimality cut is computed with an LHS
303 */
304 SCIP_CALL( SCIPallocBufferArray(masterprob, &rowvals, nvars) );
305 SCIP_CALL( SCIPallocBufferArray(masterprob, &rowinds, nvars) );
306
307 assert(SCIPisInfinity(masterprob, rhs));
308 assert(!SCIPisInfinity(masterprob, lhs));
309 for( i = 0; i < nvars; i++ )
310 {
311 rowinds[i] = SCIPvarGetProbindex(vars[i]);
312 assert(rowinds[i] >= 0);
313 rowvals[i] = -vals[i];
314 }
315
316 /* adding the optimality cut to the aggregation row */
317 SCIP_CALL( SCIPaggrRowAddCustomCons(masterprob, aggrrow, rowinds, rowvals, nvars, -lhs, 1.0, 1, FALSE) );
318
319 /* calculating a flow cover for the optimality cut */
320 cutefficacy = 0.0;
321 SCIP_CALL( SCIPcalcFlowCover(masterprob, sol, TRUE, 0.9999, FALSE, aggrrow, cutcoefs, cutrhs, cutinds, cutnnz,
322 &cutefficacy, NULL, &cutislocal, &cutsuccess) );
323 (*success) = cutsuccess;
324
325 /* calculating the MIR coefficients for the optimality cut */
326 SCIP_CALL( SCIPcalcMIR(masterprob, sol, TRUE, 0.9999, 1, FALSE, FALSE, NULL, NULL, 0.001, 0.999, 1.0, aggrrow,
327 cutcoefs, cutrhs, cutinds, cutnnz, &cutefficacy, &cutrank, &cutislocal, &cutsuccess) );
328 (*success) = ((*success) || cutsuccess);
329
330 /* the cut is only successful if the efficacy is high enough */
331 (*success) = (*success) && SCIPisEfficacious(masterprob, cutefficacy);
332
333 /* try to tighten the coefficients of the cut */
334 if( (*success) )
335 {
336 SCIP_Bool redundant;
337 int nchgcoefs;
338
339 redundant = SCIPcutsTightenCoefficients(masterprob, FALSE, cutcoefs, cutrhs, cutinds, cutnnz, &nchgcoefs);
340
341 (*success) = !redundant;
342 }
343
344 /* freeing the local memory */
345 SCIPfreeBufferArray(masterprob, &rowinds);
346 SCIPfreeBufferArray(masterprob, &rowvals);
347 SCIPaggrRowFree(masterprob, &aggrrow);
348
349 return SCIP_OKAY;
350}
351
352/** computes a standard Benders' optimality cut from the dual solutions of the LP */
353static
355 SCIP* masterprob, /**< the SCIP instance of the master problem */
356 SCIP* subproblem, /**< the SCIP instance of the subproblem */
357 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
358 SCIP_VAR*** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
359 SCIP_Real** vals, /**< pointer to array of coefficients of the variables in the generated cut */
360 SCIP_Real* lhs, /**< the left hand side of the cut */
361 SCIP_Real* rhs, /**< the right hand side of the cut */
362 int* nvars, /**< the number of variables in the cut */
363 int* varssize, /**< the number of variables in the array */
364 SCIP_Real* checkobj, /**< stores the objective function computed from the dual solution */
365 SCIP_Bool* success /**< was the cut generation successful? */
366 )
367{
368 SCIP_VAR** subvars;
369 SCIP_VAR** fixedvars;
370 int nsubvars;
371 int nfixedvars;
372 SCIP_Real dualsol;
373 SCIP_Real addval;
374 int nrows;
375 int i;
376
377 (*checkobj) = 0;
378
379 assert(masterprob != NULL);
380 assert(subproblem != NULL);
381 assert(benders != NULL);
382 assert(vars != NULL);
383 assert(*vars != NULL);
384 assert(vals != NULL);
385 assert(*vals != NULL);
386
387 (*success) = FALSE;
388
389 /* looping over all LP rows and setting the coefficients of the cut */
390 nrows = SCIPgetNLPRows(subproblem);
391 for( i = 0; i < nrows; i++ )
392 {
393 SCIP_ROW* lprow;
394
395 lprow = SCIPgetLPRows(subproblem)[i];
396 assert(lprow != NULL);
397
398 dualsol = SCIProwGetDualsol(lprow);
399 assert( !SCIPisInfinity(subproblem, dualsol) && !SCIPisInfinity(subproblem, -dualsol) );
400
401 if( SCIPisZero(subproblem, dualsol) )
402 continue;
403
404 if( dualsol > 0.0 )
405 addval = dualsol*SCIProwGetLhs(lprow);
406 else
407 addval = dualsol*SCIProwGetRhs(lprow);
408
409 (*lhs) += addval;
410
411 /* if the bound becomes infinite, then the cut generation terminates. */
412 if( SCIPisInfinity(masterprob, (*lhs)) || SCIPisInfinity(masterprob, -(*lhs))
413 || SCIPisInfinity(masterprob, addval) || SCIPisInfinity(masterprob, -addval))
414 {
415 (*success) = FALSE;
416 SCIPdebugMsg(masterprob, "Infinite bound when generating optimality cut. lhs = %g addval = %g.\n", (*lhs), addval);
417 return SCIP_OKAY;
418 }
419 }
420
421 nsubvars = SCIPgetNVars(subproblem);
422 subvars = SCIPgetVars(subproblem);
423 nfixedvars = SCIPgetNFixedVars(subproblem);
424 fixedvars = SCIPgetFixedVars(subproblem);
425
426 /* looping over all variables to update the coefficients in the computed cut. */
427 for( i = 0; i < nsubvars + nfixedvars; i++ )
428 {
429 SCIP_VAR* var;
430 SCIP_VAR* mastervar;
431 SCIP_Real redcost;
432
433 if( i < nsubvars )
434 var = subvars[i];
435 else
436 var = fixedvars[i - nsubvars];
437
438 /* retrieving the master problem variable for the given subproblem variable. */
439 SCIP_CALL( SCIPgetBendersMasterVar(masterprob, benders, var, &mastervar) );
440
441 redcost = SCIPgetVarRedcost(subproblem, var);
442
443 (*checkobj) += SCIPvarGetUnchangedObj(var)*SCIPvarGetSol(var, TRUE);
444
445 /* checking whether the subproblem variable has a corresponding master variable. */
446 if( mastervar != NULL )
447 {
448 SCIP_Real coef;
449
450 coef = -1.0*(SCIPvarGetObj(var) + redcost);
451
452 if( !SCIPisZero(masterprob, coef) )
453 {
454 /* adding the variable to the storage */
455 SCIP_CALL( addVariableToArray(masterprob, vars, vals, mastervar, coef, nvars, varssize) );
456 }
457 }
458 else
459 {
460 if( !SCIPisZero(subproblem, redcost) )
461 {
462 addval = 0;
463
464 if( SCIPisPositive(subproblem, redcost) )
465 addval = redcost*SCIPvarGetLbLocal(var);
466 else if( SCIPisNegative(subproblem, redcost) )
467 addval = redcost*SCIPvarGetUbLocal(var);
468
469 (*lhs) += addval;
470
471 /* if the bound becomes infinite, then the cut generation terminates. */
472 if( SCIPisInfinity(masterprob, (*lhs)) || SCIPisInfinity(masterprob, -(*lhs))
473 || SCIPisInfinity(masterprob, addval) || SCIPisInfinity(masterprob, -addval))
474 {
475 (*success) = FALSE;
476 SCIPdebugMsg(masterprob, "Infinite bound when generating optimality cut.\n");
477 return SCIP_OKAY;
478 }
479 }
480 }
481 }
482
483 assert(SCIPisInfinity(masterprob, (*rhs)));
484 /* the rhs should be infinite. If it changes, then there is an error */
485 if( !SCIPisInfinity(masterprob, (*rhs)) )
486 {
487 (*success) = FALSE;
488 SCIPdebugMsg(masterprob, "RHS is not infinite. rhs = %g.\n", (*rhs));
489 return SCIP_OKAY;
490 }
491
492 (*success) = TRUE;
493
494 return SCIP_OKAY;
495}
496
497/** computes a standard Benders' optimality cut from the dual solutions of the NLP */
498static
500 SCIP* masterprob, /**< the SCIP instance of the master problem */
501 SCIP* subproblem, /**< the SCIP instance of the subproblem */
502 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
503 SCIP_VAR*** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
504 SCIP_Real** vals, /**< pointer to array of coefficients of the variables in the generated cut */
505 SCIP_Real* lhs, /**< the left hand side of the cut */
506 SCIP_Real* rhs, /**< the right hand side of the cut */
507 int* nvars, /**< the number of variables in the cut */
508 int* varssize, /**< the number of variables in the array */
509 SCIP_Real objective, /**< the objective function of the subproblem */
510 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
511 SCIP_Real* consdualvals, /**< dual variables for the constraints, can be NULL */
512 SCIP_Real* varlbdualvals, /**< the dual variables for the variable lower bounds, can be NULL */
513 SCIP_Real* varubdualvals, /**< the dual variables for the variable upper bounds, can be NULL */
514 SCIP_HASHMAP* row2idx, /**< mapping between the row in the subproblem to the index in the dual array, can be NULL */
515 SCIP_HASHMAP* var2idx, /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
516 SCIP_Real* checkobj, /**< stores the objective function computed from the dual solution */
517 SCIP_Bool* success /**< was the cut generation successful? */
518 )
519{
520 SCIP_VAR** subvars;
521 SCIP_VAR** fixedvars;
522 int nsubvars;
523 int nfixedvars;
524 SCIP_Real dirderiv;
525 SCIP_Real dualsol;
526 int nrows;
527 int idx;
528 int i;
529
530 (*checkobj) = 0;
531
532 assert(masterprob != NULL);
533 assert(subproblem != NULL);
534 assert(benders != NULL);
535 assert(SCIPisNLPConstructed(subproblem));
536 assert(SCIPgetNLPSolstat(subproblem) <= SCIP_NLPSOLSTAT_FEASIBLE || consdualvals != NULL);
537 assert(SCIPhasNLPSolution(subproblem) || consdualvals != NULL);
538
539 (*success) = FALSE;
540
541 if( !(primalvals == NULL && consdualvals == NULL && varlbdualvals == NULL && varubdualvals == NULL && row2idx == NULL && var2idx == NULL)
542 && !(primalvals != NULL && consdualvals != NULL && varlbdualvals != NULL && varubdualvals != NULL && row2idx != NULL && var2idx != NULL) ) /*lint !e845*/
543 {
544 SCIPerrorMessage("The optimality cut must generated from either a SCIP instance or all of the dual solutions and indices must be supplied");
545 (*success) = FALSE;
546
547 return SCIP_ERROR;
548 }
549
550 nsubvars = SCIPgetNNLPVars(subproblem);
551 subvars = SCIPgetNLPVars(subproblem);
552 nfixedvars = SCIPgetNFixedVars(subproblem);
553 fixedvars = SCIPgetFixedVars(subproblem);
554
555 /* our optimality cut implementation assumes that SCIP did not modify the objective function and sense,
556 * that is, that the objective function value of the NLP corresponds to the value of the auxiliary variable
557 * if that wouldn't be the case, then the scaling and offset may have to be considered when adding the
558 * auxiliary variable to the cut (cons/row)?
559 */
560 assert(SCIPgetTransObjoffset(subproblem) == 0.0);
561 assert(SCIPgetTransObjscale(subproblem) == 1.0);
562 assert(SCIPgetObjsense(subproblem) == SCIP_OBJSENSE_MINIMIZE);
563
564 (*lhs) = objective;
565 assert(!SCIPisInfinity(subproblem, REALABS(*lhs)));
566
567 (*rhs) = SCIPinfinity(masterprob);
568
569 dirderiv = 0.0;
570
571 /* looping over all NLP rows and setting the corresponding coefficients of the cut */
572 nrows = SCIPgetNNLPNlRows(subproblem);
573 for( i = 0; i < nrows; i++ )
574 {
575 SCIP_NLROW* nlrow;
576
577 nlrow = SCIPgetNLPNlRows(subproblem)[i];
578 assert(nlrow != NULL);
579
580 if( row2idx != NULL && consdualvals != NULL )
581 {
582 assert(SCIPhashmapExists(row2idx, (void*)nlrow) );
583 idx = SCIPhashmapGetImageInt(row2idx, (void*)nlrow);
584 dualsol = consdualvals[idx];
585 }
586 else
587 dualsol = SCIPnlrowGetDualsol(nlrow);
588 assert( !SCIPisInfinity(subproblem, dualsol) && !SCIPisInfinity(subproblem, -dualsol) );
589
590 if( SCIPisZero(subproblem, dualsol) )
591 continue;
592
593 SCIP_CALL( SCIPaddNlRowGradientBenderscutOpt(masterprob, subproblem, benders, nlrow,
594 -dualsol, primalvals, var2idx, &dirderiv, vars, vals, nvars, varssize) );
595 }
596
597 /* looping over sub- and fixed variables to compute checkobj */
598 for( i = 0; i < nsubvars; i++ )
599 (*checkobj) += SCIPvarGetObj(subvars[i]) * getNlpVarSol(subvars[i], primalvals, var2idx);
600
601 for( i = 0; i < nfixedvars; i++ )
602 *checkobj += SCIPvarGetUnchangedObj(fixedvars[i]) * getNlpVarSol(fixedvars[i], primalvals, var2idx);
603
604 *lhs += dirderiv;
605
606 /* if the side became infinite or dirderiv was infinite, then the cut generation terminates. */
607 if( SCIPisInfinity(masterprob, *lhs) || SCIPisInfinity(masterprob, -*lhs)
608 || SCIPisInfinity(masterprob, dirderiv) || SCIPisInfinity(masterprob, -dirderiv))
609 {
610 (*success) = FALSE;
611 SCIPdebugMsg(masterprob, "Infinite bound when generating optimality cut. lhs = %g dirderiv = %g.\n", *lhs, dirderiv);
612 return SCIP_OKAY;
613 }
614
615 (*success) = TRUE;
616
617 return SCIP_OKAY;
618}
619
620
621/** Adds the auxiliary variable to the generated cut. If this is the first optimality cut for the subproblem, then the
622 * auxiliary variable is first created and added to the master problem.
623 */
624static
626 SCIP* masterprob, /**< the SCIP instance of the master problem */
627 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
628 SCIP_VAR** vars, /**< the variables in the generated cut with non-zero coefficient */
629 SCIP_Real* vals, /**< the coefficients of the variables in the generated cut */
630 int* nvars, /**< the number of variables in the cut */
631 int probnumber /**< the number of the pricing problem */
632 )
633{
634 SCIP_VAR* auxiliaryvar;
635
636 assert(masterprob != NULL);
637 assert(benders != NULL);
638 assert(vars != NULL);
639 assert(vals != NULL);
640
641 auxiliaryvar = SCIPbendersGetAuxiliaryVar(benders, probnumber);
642
643 vars[(*nvars)] = auxiliaryvar;
644 vals[(*nvars)] = 1.0;
645 (*nvars)++;
646
647 return SCIP_OKAY;
648}
649
650
651/*
652 * Callback methods of Benders' decomposition cuts
653 */
654
655/** destructor of Benders' decomposition cuts to free user data (called when SCIP is exiting) */
656static
657SCIP_DECL_BENDERSCUTFREE(benderscutFreeOpt)
658{ /*lint --e{715}*/
659 SCIP_BENDERSCUTDATA* benderscutdata;
660
661 assert( benderscut != NULL );
662 assert( strcmp(SCIPbenderscutGetName(benderscut), BENDERSCUT_NAME) == 0 );
663
664 /* free Benders' cut data */
665 benderscutdata = SCIPbenderscutGetData(benderscut);
666 assert( benderscutdata != NULL );
667
668 SCIPfreeBlockMemory(scip, &benderscutdata);
669
670 SCIPbenderscutSetData(benderscut, NULL);
671
672 return SCIP_OKAY;
673}
674
675
676/** execution method of Benders' decomposition cuts */
677static
678SCIP_DECL_BENDERSCUTEXEC(benderscutExecOpt)
679{ /*lint --e{715}*/
680 SCIP* subproblem;
681 SCIP_BENDERSCUTDATA* benderscutdata;
682 SCIP_Bool nlprelaxation;
683 SCIP_Bool addcut;
684 char cutname[SCIP_MAXSTRLEN];
685
686 assert(scip != NULL);
687 assert(benders != NULL);
688 assert(benderscut != NULL);
689 assert(result != NULL);
690 assert(probnumber >= 0 && probnumber < SCIPbendersGetNSubproblems(benders));
691
692 /* retrieving the Benders' cut data */
693 benderscutdata = SCIPbenderscutGetData(benderscut);
694
695 /* if the cuts are generated prior to the solving stage, then rows can not be generated. So constraints must be
696 * added to the master problem.
697 */
699 addcut = FALSE;
700 else
701 addcut = benderscutdata->addcuts;
702
703 /* setting the name of the generated cut */
704 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "optimalitycut_%d_%" SCIP_LONGINT_FORMAT, probnumber,
705 SCIPbenderscutGetNFound(benderscut) );
706
707 subproblem = SCIPbendersSubproblem(benders, probnumber);
708
709 if( subproblem == NULL )
710 {
711 SCIPdebugMsg(scip, "The subproblem %d is set to NULL. The <%s> Benders' decomposition cut can not be executed.\n",
712 probnumber, BENDERSCUT_NAME);
713
714 (*result) = SCIP_DIDNOTRUN;
715 return SCIP_OKAY;
716 }
717
718 /* setting a flag to indicate whether the NLP relaxation should be used to generate cuts */
719 nlprelaxation = SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem);
720
721 /* only generate optimality cuts if the subproblem LP or NLP is optimal,
722 * since we use the dual solution of the LP/NLP to construct the optimality cut
723 */
724 if( SCIPgetStage(subproblem) == SCIP_STAGE_SOLVING &&
725 ((!nlprelaxation && SCIPgetLPSolstat(subproblem) == SCIP_LPSOLSTAT_OPTIMAL) ||
726 (nlprelaxation && SCIPgetNLPSolstat(subproblem) <= SCIP_NLPSOLSTAT_FEASIBLE)) )
727 {
728 /* generating a cut for a given subproblem */
729 SCIP_CALL( SCIPgenerateAndApplyBendersOptCut(scip, subproblem, benders, benderscut, sol, probnumber, cutname,
730 SCIPbendersGetSubproblemObjval(benders, probnumber), NULL, NULL, NULL, NULL, NULL, NULL, type, addcut,
731 FALSE, result) );
732
733 /* if it was not possible to generate a cut, this could be due to numerical issues. So the solution to the LP is
734 * resolved and the generation of the cut is reattempted. For NLPs, we do not have such a polishing yet.
735 */
736 if( (*result) == SCIP_DIDNOTFIND )
737 {
738 SCIP_Bool success;
739
740 SCIPdebugMsg(scip, "Numerical trouble generating optimality cut for subproblem %d.\n", probnumber);
741
742 if( !nlprelaxation )
743 {
744 SCIPdebugMsg(scip, "Attempting to polish the LP solution to find an alternative dual extreme point.\n");
745
746 SCIP_CALL( polishSolution(subproblem, &success) );
747
748 /* only attempt to generate a cut if the solution polishing was successful */
749 if( success )
750 {
751 SCIP_CALL( SCIPgenerateAndApplyBendersOptCut(scip, subproblem, benders, benderscut, sol, probnumber, cutname,
752 SCIPbendersGetSubproblemObjval(benders, probnumber), NULL, NULL, NULL, NULL, NULL, NULL, type, addcut,
753 FALSE, result) );
754 }
755 }
756 else
757 {
758 SCIP_Real multiplier = 0.01;
759
760 SCIPdebugMsg(scip, "Attempting to resolve the NLP with a tighter feasibility tolerance to find an "
761 "alternative dual extreme point.\n");
762
763 while( multiplier > 1e-06 && (*result) == SCIP_DIDNOTFIND )
764 {
765 SCIP_CALL( resolveNLPWithTighterFeastol(subproblem, benders, multiplier, &success) );
766
767 if( success )
768 {
769 SCIP_CALL( SCIPgenerateAndApplyBendersOptCut(scip, subproblem, benders, benderscut, sol, probnumber, cutname,
770 SCIPbendersGetSubproblemObjval(benders, probnumber), NULL, NULL, NULL, NULL, NULL, NULL, type, addcut,
771 FALSE, result) );
772 }
773
774 multiplier *= 0.1;
775 }
776 }
777 }
778 }
779
780 return SCIP_OKAY;
781}
782
783
784/*
785 * Benders' decomposition cuts specific interface methods
786 */
787
788/** creates the opt Benders' decomposition cuts and includes it in SCIP */
790 SCIP* scip, /**< SCIP data structure */
791 SCIP_BENDERS* benders /**< Benders' decomposition */
792 )
793{
794 SCIP_BENDERSCUTDATA* benderscutdata;
795 SCIP_BENDERSCUT* benderscut;
797
798 assert(benders != NULL);
799
800 /* create opt Benders' decomposition cuts data */
801 SCIP_CALL( SCIPallocBlockMemory(scip, &benderscutdata) );
802
803 benderscut = NULL;
804
805 /* include Benders' decomposition cuts */
807 BENDERSCUT_PRIORITY, BENDERSCUT_LPCUT, benderscutExecOpt, benderscutdata) );
808
809 assert(benderscut != NULL);
810
811 /* setting the non fundamental callbacks via setter functions */
812 SCIP_CALL( SCIPsetBenderscutFree(scip, benderscut, benderscutFreeOpt) );
813
814 /* add opt Benders' decomposition cuts parameters */
815 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/addcuts",
818 "should cuts be generated and added to the cutpool instead of global constraints directly added to the problem.",
819 &benderscutdata->addcuts, FALSE, SCIP_DEFAULT_ADDCUTS, NULL, NULL) );
820
821 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "benders/%s/benderscut/%s/mir",
824 "should the mixed integer rounding procedure be applied to cuts",
825 &benderscutdata->calcmir, FALSE, SCIP_DEFAULT_CALCMIR, NULL, NULL) );
826
827 return SCIP_OKAY;
828}
829
830/** Generates a classical Benders' optimality cut using the dual solutions from the subproblem or the input arrays. If
831 * the dual solutions are input as arrays, then a mapping between the array indices and the rows/variables is required.
832 * As a cut strengthening approach, when an optimality cut is being generated (i.e. not for feasibility cuts) a MIR
833 * procedure is performed on the row. This procedure attempts to find a stronger constraint, if this doesn't happen,
834 * then the original constraint is added to SCIP.
835 *
836 * This method can also be used to generate a feasibility cut, if a problem to minimise the infeasibilities has been solved
837 * to generate the dual solutions
838 */
840 SCIP* masterprob, /**< the SCIP instance of the master problem */
841 SCIP* subproblem, /**< the SCIP instance of the pricing problem */
842 SCIP_BENDERS* benders, /**< the benders' decomposition */
843 SCIP_BENDERSCUT* benderscut, /**< the benders' decomposition cut method */
844 SCIP_SOL* sol, /**< primal CIP solution */
845 int probnumber, /**< the number of the pricing problem */
846 char* cutname, /**< the name for the cut to be generated */
847 SCIP_Real objective, /**< the objective function of the subproblem */
848 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
849 SCIP_Real* consdualvals, /**< dual variables for the constraints, can be NULL */
850 SCIP_Real* varlbdualvals, /**< the dual variables for the variable lower bounds, can be NULL */
851 SCIP_Real* varubdualvals, /**< the dual variables for the variable upper bounds, can be NULL */
852 SCIP_HASHMAP* row2idx, /**< mapping between the row in the subproblem to the index in the dual array, can be NULL */
853 SCIP_HASHMAP* var2idx, /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
854 SCIP_BENDERSENFOTYPE type, /**< the enforcement type calling this function */
855 SCIP_Bool addcut, /**< should the Benders' cut be added as a cut or constraint */
856 SCIP_Bool feasibilitycut, /**< is this called for the generation of a feasibility cut */
857 SCIP_RESULT* result /**< the result from solving the subproblems */
858 )
859{
860 SCIP_CONSHDLR* consbenders;
861 SCIP_CONS* cons;
862 SCIP_ROW* row;
863 SCIP_VAR** vars;
864 SCIP_Real* vals;
865 SCIP_Real lhs;
866 SCIP_Real rhs;
867 int nvars;
868 int varssize;
869 int nmastervars;
870 SCIP_Bool calcmir;
871 SCIP_Bool optimal;
872 SCIP_Bool success;
873 SCIP_Bool mirsuccess;
874
875 SCIP_Real checkobj;
876 SCIP_Real verifyobj;
877
878 assert(masterprob != NULL);
879 assert(subproblem != NULL);
880 assert(benders != NULL);
881 assert(benderscut != NULL);
882 assert(result != NULL);
883 assert((primalvals == NULL && consdualvals == NULL && varlbdualvals == NULL && varubdualvals == NULL
884 && row2idx == NULL && var2idx == NULL)
885 || (primalvals != NULL && consdualvals != NULL && varlbdualvals != NULL && varubdualvals != NULL
886 && row2idx != NULL && var2idx != NULL));
887
888 row = NULL;
889 cons = NULL;
890
891 calcmir = SCIPbenderscutGetData(benderscut)->calcmir && SCIPgetStage(masterprob) >= SCIP_STAGE_INITSOLVE && SCIPgetSubscipDepth(masterprob) == 0;
892 success = FALSE;
893 mirsuccess = FALSE;
894
895 /* retrieving the Benders' decomposition constraint handler */
896 consbenders = SCIPfindConshdlr(masterprob, "benders");
897
898 /* checking the optimality of the original problem with a comparison between the auxiliary variable and the
899 * objective value of the subproblem */
900 if( feasibilitycut )
901 optimal = FALSE;
902 else
903 {
904 SCIP_CALL( SCIPcheckBendersSubproblemOptimality(masterprob, benders, sol, probnumber, &optimal) );
905 }
906
907 if( optimal )
908 {
909 (*result) = SCIP_FEASIBLE;
910 SCIPdebugMsg(masterprob, "No cut added for subproblem %d\n", probnumber);
911 return SCIP_OKAY;
912 }
913
914 /* allocating memory for the variable and values arrays */
915 nmastervars = SCIPgetNVars(masterprob) + SCIPgetNFixedVars(masterprob);
916 SCIP_CALL( SCIPallocClearBufferArray(masterprob, &vars, nmastervars) );
917 SCIP_CALL( SCIPallocClearBufferArray(masterprob, &vals, nmastervars) );
918 lhs = 0.0;
919 rhs = SCIPinfinity(masterprob);
920 nvars = 0;
921 varssize = nmastervars;
922
923 if( SCIPisNLPConstructed(subproblem) && SCIPgetNNlpis(subproblem) )
924 {
925 /* computing the coefficients of the optimality cut */
926 SCIP_CALL( computeStandardNLPOptimalityCut(masterprob, subproblem, benders, &vars, &vals, &lhs, &rhs, &nvars,
927 &varssize, objective, primalvals, consdualvals, varlbdualvals, varubdualvals, row2idx,
928 var2idx, &checkobj, &success) );
929 }
930 else
931 {
932 /* computing the coefficients of the optimality cut */
933 SCIP_CALL( computeStandardLPOptimalityCut(masterprob, subproblem, benders, &vars, &vals, &lhs, &rhs, &nvars,
934 &varssize, &checkobj, &success) );
935 }
936
937 /* if success is FALSE, then there was an error in generating the optimality cut. No cut will be added to the master
938 * problem. Otherwise, the constraint is added to the master problem.
939 */
940 if( !success )
941 {
942 (*result) = SCIP_DIDNOTFIND;
943 SCIPdebugMsg(masterprob, "Error in generating Benders' optimality cut for problem %d.\n", probnumber);
944 }
945 else
946 {
947 /* initially a row/constraint is created for the optimality cut using the master variables and coefficients
948 * computed in computeStandardLPOptimalityCut. At this stage, the auxiliary variable is not added since the
949 * activity of the row/constraint in its current form is used to determine the validity of the optimality cut.
950 */
951 if( addcut )
952 {
953 SCIP_CALL( SCIPcreateEmptyRowConshdlr(masterprob, &row, consbenders, cutname, lhs, rhs, FALSE, FALSE, TRUE) );
954 SCIP_CALL( SCIPaddVarsToRow(masterprob, row, nvars, vars, vals) );
955 }
956 else
957 {
958 SCIP_CALL( SCIPcreateConsBasicLinear(masterprob, &cons, cutname, nvars, vars, vals, lhs, rhs) );
959 SCIP_CALL( SCIPsetConsDynamic(masterprob, cons, TRUE) );
960 SCIP_CALL( SCIPsetConsRemovable(masterprob, cons, TRUE) );
961 }
962
963 /* computing the objective function from the cut activity to verify the accuracy of the constraint */
964 verifyobj = 0.0;
965 if( addcut )
966 {
967 verifyobj += SCIProwGetLhs(row) - SCIPgetRowSolActivity(masterprob, row, sol);
968 }
969 else
970 {
971 verifyobj += SCIPgetLhsLinear(masterprob, cons) - SCIPgetActivityLinear(masterprob, cons, sol);
972 }
973
974 if( feasibilitycut && verifyobj < SCIPfeastol(masterprob) )
975 {
976 success = FALSE;
977 SCIPdebugMsg(masterprob, "The violation of the feasibility cut (%g) is too small. Skipping feasibility cut.\n", verifyobj);
978 }
979
980 /* it is possible that numerics will cause the generated cut to be invalid. This cut should not be added to the
981 * master problem, since its addition could cut off feasible solutions. The success flag is set of false, indicating
982 * that the Benders' cut could not find a valid cut.
983 */
984 if( !feasibilitycut && !SCIPisFeasEQ(masterprob, checkobj, verifyobj) )
985 {
986 SCIP_Bool valid;
987
988 /* the difference in the checkobj and verifyobj could be due to the setup tolerances. This is checked, and if
989 * so, then the generated cut is still valid
990 */
991 SCIP_CALL( checkSetupTolerances(masterprob, sol, vars, vals, lhs, checkobj, nvars, &valid) );
992
993 if( !valid )
994 {
995 success = FALSE;
996 SCIPdebugMsg(masterprob, "The objective function and cut activity are not equal (%g != %g).\n", checkobj,
997 verifyobj);
998
999#ifdef SCIP_DEBUG
1000 /* we only need to abort if cut strengthen is not used. If cut strengthen has been used in this round and the
1001 * cut could not be generated, then another subproblem solving round will be executed
1002 */
1003 if( !SCIPbendersInStrengthenRound(benders) )
1004 {
1005#ifdef SCIP_MOREDEBUG
1006 int i;
1007
1008 for( i = 0; i < nvars; i++ )
1009 printf("<%s> %g %g\n", SCIPvarGetName(vars[i]), vals[i], SCIPgetSolVal(masterprob, sol, vars[i]));
1010#endif
1011 SCIPABORT();
1012 }
1013#endif
1014 }
1015 }
1016
1017 if( success )
1018 {
1019 /* adding the auxiliary variable to the optimality cut. The auxiliary variable is added to the vars and vals
1020 * arrays prior to the execution of the MIR procedure. This is necessary because the MIR procedure must be
1021 * executed on the complete cut, not just the row/constraint without the auxiliary variable.
1022 */
1023 if( !feasibilitycut )
1024 {
1025 SCIP_CALL( addAuxiliaryVariableToCut(masterprob, benders, vars, vals, &nvars, probnumber) );
1026 }
1027
1028 /* performing the MIR procedure. If the procedure is successful, then the vars and vals arrays are no longer
1029 * needed for creating the optimality cut. These are superseeded with the cutcoefs and cutinds arrays. In the
1030 * case that the MIR procedure is successful, the row/constraint that has been created previously is destroyed
1031 * and the MIR cut is added in its place
1032 */
1033 if( calcmir )
1034 {
1035 SCIP_Real* cutcoefs;
1036 int* cutinds;
1037 SCIP_Real cutrhs;
1038 int cutnnz;
1039
1040 /* allocating memory to compute the MIR cut */
1041 SCIP_CALL( SCIPallocBufferArray(masterprob, &cutcoefs, nvars) );
1042 SCIP_CALL( SCIPallocBufferArray(masterprob, &cutinds, nvars) );
1043
1044 SCIP_CALL( computeMIRForOptimalityCut(masterprob, sol, vars, vals, lhs, rhs, nvars, cutcoefs,
1045 cutinds, &cutrhs, &cutnnz, &mirsuccess) );
1046
1047 /* if the MIR cut was computed successfully, then the current row/constraint needs to be destroyed and
1048 * replaced with the updated coefficients
1049 */
1050 if( mirsuccess )
1051 {
1052 SCIP_VAR** mastervars;
1053 int i;
1054
1055 mastervars = SCIPgetVars(masterprob);
1056
1057 if( addcut )
1058 {
1059 SCIP_CALL( SCIPreleaseRow(masterprob, &row) );
1060
1061 SCIP_CALL( SCIPcreateEmptyRowConshdlr(masterprob, &row, consbenders, cutname,
1062 -SCIPinfinity(masterprob), cutrhs, FALSE, FALSE, TRUE) );
1063
1064 for( i = 0; i < cutnnz; i++)
1065 {
1066 SCIP_CALL( SCIPaddVarToRow(masterprob, row, mastervars[cutinds[i]], cutcoefs[i]) );
1067 }
1068 }
1069 else
1070 {
1071 SCIP_CALL( SCIPreleaseCons(masterprob, &cons) );
1072
1073 SCIP_CALL( SCIPcreateConsBasicLinear(masterprob, &cons, cutname, 0, NULL, NULL,
1074 -SCIPinfinity(masterprob), cutrhs) );
1075 SCIP_CALL( SCIPsetConsDynamic(masterprob, cons, TRUE) );
1076 SCIP_CALL( SCIPsetConsRemovable(masterprob, cons, TRUE) );
1077
1078 for( i = 0; i < cutnnz; i++ )
1079 {
1080 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, mastervars[cutinds[i]], cutcoefs[i]) );
1081 }
1082 }
1083 }
1084
1085 /* freeing the memory required to compute the MIR cut */
1086 SCIPfreeBufferArray(masterprob, &cutinds);
1087 SCIPfreeBufferArray(masterprob, &cutcoefs);
1088 }
1089
1090 /* adding the constraint to the master problem */
1091 if( addcut )
1092 {
1093 SCIP_Bool infeasible;
1094
1095 /* adding the auxiliary variable coefficient to the row. This is only added if the MIR procedure is not
1096 * successful. If the MIR procedure was successful, then the auxiliary variable is already included in the
1097 * row
1098 */
1099 if( !feasibilitycut && !mirsuccess )
1100 {
1101 SCIP_CALL( SCIPaddVarToRow(masterprob, row, vars[nvars - 1], vals[nvars - 1]) );
1102 }
1103
1105 {
1106 SCIP_CALL( SCIPaddRow(masterprob, row, FALSE, &infeasible) );
1107 assert(!infeasible);
1108 }
1109 else
1110 {
1112 SCIP_CALL( SCIPaddPoolCut(masterprob, row) );
1113 }
1114
1115 (*result) = SCIP_SEPARATED;
1116 }
1117 else
1118 {
1119 /* adding the auxiliary variable coefficient to the row. This is only added if the MIR procedure is not
1120 * successful. If the MIR procedure was successful, then the auxiliary variable is already included in the
1121 * constraint.
1122 */
1123 if( !feasibilitycut && !mirsuccess )
1124 {
1125 SCIP_CALL( SCIPaddCoefLinear(masterprob, cons, vars[nvars - 1], vals[nvars - 1]) );
1126 }
1127
1128 SCIPdebugPrintCons(masterprob, cons, NULL);
1129
1130 SCIP_CALL( SCIPaddCons(masterprob, cons) );
1131
1132 (*result) = SCIP_CONSADDED;
1133 }
1134
1135 /* storing the data that is used to create the cut */
1136 SCIP_CALL( SCIPstoreBendersCut(masterprob, benders, vars, vals, lhs, rhs, nvars) );
1137 }
1138 else
1139 {
1140 (*result) = SCIP_DIDNOTFIND;
1141 SCIPdebugMsg(masterprob, "Error in generating Benders' %s cut for problem %d.\n", feasibilitycut ? "feasibility" : "optimality", probnumber);
1142 }
1143
1144 /* releasing the row or constraint */
1145 if( addcut )
1146 {
1147 /* release the row */
1148 SCIP_CALL( SCIPreleaseRow(masterprob, &row) );
1149 }
1150 else
1151 {
1152 /* release the constraint */
1153 SCIP_CALL( SCIPreleaseCons(masterprob, &cons) );
1154 }
1155 }
1156
1157 SCIPfreeBufferArray(masterprob, &vals);
1158 SCIPfreeBufferArray(masterprob, &vars);
1159
1160 return SCIP_OKAY;
1161}
1162
1163
1164/** adds the gradient of a nonlinear row in the current NLP solution of a subproblem to a linear row or constraint in the master problem
1165 *
1166 * Only computes gradient w.r.t. master problem variables.
1167 * Computes also the directional derivative, that is, mult times gradient times solution.
1168 */
1170 SCIP* masterprob, /**< the SCIP instance of the master problem */
1171 SCIP* subproblem, /**< the SCIP instance of the subproblem */
1172 SCIP_BENDERS* benders, /**< the benders' decomposition structure */
1173 SCIP_NLROW* nlrow, /**< nonlinear row */
1174 SCIP_Real mult, /**< multiplier */
1175 SCIP_Real* primalvals, /**< the primal solutions for the NLP, can be NULL */
1176 SCIP_HASHMAP* var2idx, /**< mapping from variable of the subproblem to the index in the dual arrays, can be NULL */
1177 SCIP_Real* dirderiv, /**< storage to add directional derivative */
1178 SCIP_VAR*** vars, /**< pointer to array of variables in the generated cut with non-zero coefficient */
1179 SCIP_Real** vals, /**< pointer to array of coefficients of the variables in the generated cut */
1180 int* nvars, /**< the number of variables in the cut */
1181 int* varssize /**< the number of variables in the array */
1182 )
1183{
1184 SCIP_EXPR* expr;
1185 SCIP_VAR* var;
1186 SCIP_VAR* mastervar;
1187 SCIP_Real coef;
1188 int i;
1189
1190 assert(masterprob != NULL);
1191 assert(subproblem != NULL);
1192 assert(benders != NULL);
1193 assert(nlrow != NULL);
1194 assert((primalvals == NULL && var2idx == NULL) || (primalvals != NULL && var2idx != NULL));
1195 assert(mult != 0.0);
1196 assert(dirderiv != NULL);
1197 assert(vars != NULL);
1198 assert(vals != NULL);
1199
1200 /* linear part */
1201 for( i = 0; i < SCIPnlrowGetNLinearVars(nlrow); i++ )
1202 {
1203 var = SCIPnlrowGetLinearVars(nlrow)[i];
1204 assert(var != NULL);
1205
1206 /* retrieving the master problem variable for the given subproblem variable. */
1207 SCIP_CALL( SCIPgetBendersMasterVar(masterprob, benders, var, &mastervar) );
1208 if( mastervar == NULL )
1209 continue;
1210
1211 coef = mult * SCIPnlrowGetLinearCoefs(nlrow)[i];
1212
1213 /* adding the variable to the storage */
1214 SCIP_CALL( addVariableToArray(masterprob, vars, vals, mastervar, coef, nvars, varssize) );
1215
1216 *dirderiv += coef * getNlpVarSol(var, primalvals, var2idx);
1217 }
1218
1219 /* expression part */
1220 expr = SCIPnlrowGetExpr(nlrow);
1221 if( expr != NULL )
1222 {
1223 SCIP_SOL* primalsol;
1224 SCIP_EXPRITER* it;
1225
1226 /* create primalsol, either from primalvals, or pointing to NLP solution */
1227 if( primalvals != NULL )
1228 {
1229 SCIP_CALL( SCIPcreateSol(subproblem, &primalsol, NULL) );
1230
1231 /* TODO would be better to change primalvals to a SCIP_SOL and do this once for the whole NLP instead of repeating it for each expr */
1232 for( i = 0; i < SCIPhashmapGetNEntries(var2idx); ++i )
1233 {
1234 SCIP_HASHMAPENTRY* entry;
1235 entry = SCIPhashmapGetEntry(var2idx, i);
1236 if( entry == NULL )
1237 continue;
1238 SCIP_CALL( SCIPsetSolVal(subproblem, primalsol, (SCIP_VAR*) SCIPhashmapEntryGetOrigin(entry), primalvals[SCIPhashmapEntryGetImageInt(entry)]) );
1239 }
1240 }
1241 else
1242 {
1243 SCIP_CALL( SCIPcreateNLPSol(subproblem, &primalsol, NULL) );
1244 }
1245
1246 /* eval gradient */
1247 SCIP_CALL( SCIPevalExprGradient(subproblem, expr, primalsol, 0L) );
1248
1249 assert(SCIPexprGetDerivative(expr) != SCIP_INVALID); /* TODO this should be a proper check&abort */ /*lint !e777*/
1250
1251 SCIP_CALL( SCIPfreeSol(subproblem, &primalsol) );
1252
1253 /* update corresponding gradient entry */
1254 SCIP_CALL( SCIPcreateExpriter(subproblem, &it) );
1256 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) /*lint !e441*/ /*lint !e440*/
1257 {
1258 if( !SCIPisExprVar(subproblem, expr) )
1259 continue;
1260
1261 var = SCIPgetVarExprVar(expr);
1262 assert(var != NULL);
1263
1264 /* retrieving the master problem variable for the given subproblem variable. */
1265 SCIP_CALL( SCIPgetBendersMasterVar(masterprob, benders, var, &mastervar) );
1266 if( mastervar == NULL )
1267 continue;
1268
1269 assert(SCIPexprGetDerivative(expr) != SCIP_INVALID); /*lint !e777*/
1270 coef = mult * SCIPexprGetDerivative(expr);
1271
1272 /* adding the variable to the storage */
1273 SCIP_CALL( addVariableToArray(masterprob, vars, vals, mastervar, coef, nvars, varssize) );
1274
1275 *dirderiv += coef * getNlpVarSol(var, primalvals, var2idx);
1276 }
1277 SCIPfreeExpriter(&it);
1278 }
1279
1280 return SCIP_OKAY;
1281}
static SCIP_RETCODE checkSetupTolerances(SCIP *masterprob, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real checkobj, int nvars, SCIP_Bool *valid)
#define SCIP_DEFAULT_ADDCUTS
static SCIP_RETCODE addVariableToArray(SCIP *masterprob, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_VAR *addvar, SCIP_Real addval, int *nvars, int *varssize)
static SCIP_RETCODE computeStandardLPOptimalityCut(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, SCIP_Real *rhs, int *nvars, int *varssize, SCIP_Real *checkobj, SCIP_Bool *success)
#define BENDERSCUT_LPCUT
static SCIP_RETCODE addAuxiliaryVariableToCut(SCIP *masterprob, SCIP_BENDERS *benders, SCIP_VAR **vars, SCIP_Real *vals, int *nvars, int probnumber)
#define SCIP_DEFAULT_CALCMIR
static SCIP_RETCODE computeStandardNLPOptimalityCut(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_VAR ***vars, SCIP_Real **vals, SCIP_Real *lhs, SCIP_Real *rhs, int *nvars, int *varssize, SCIP_Real objective, SCIP_Real *primalvals, SCIP_Real *consdualvals, SCIP_Real *varlbdualvals, SCIP_Real *varubdualvals, SCIP_HASHMAP *row2idx, SCIP_HASHMAP *var2idx, SCIP_Real *checkobj, SCIP_Bool *success)
static SCIP_DECL_BENDERSCUTEXEC(benderscutExecOpt)
static SCIP_Real getNlpVarSol(SCIP_VAR *var, SCIP_Real *primalvals, SCIP_HASHMAP *var2idx)
#define BENDERSCUT_PRIORITY
#define BENDERSCUT_DESC
#define BENDERSCUT_NAME
static SCIP_RETCODE computeMIRForOptimalityCut(SCIP *masterprob, SCIP_SOL *sol, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, int nvars, SCIP_Real *cutcoefs, int *cutinds, SCIP_Real *cutrhs, int *cutnnz, SCIP_Bool *success)
static SCIP_RETCODE polishSolution(SCIP *subproblem, SCIP_Bool *success)
static SCIP_RETCODE resolveNLPWithTighterFeastol(SCIP *subproblem, SCIP_BENDERS *benders, SCIP_Real multiplier, SCIP_Bool *success)
static SCIP_DECL_BENDERSCUTFREE(benderscutFreeOpt)
Generates a standard Benders' decomposition optimality cut.
Constraint handler for linear constraints in their most general form, .
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIPABORT()
Definition: def.h:327
#define REALABS(x)
Definition: def.h:182
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPgenerateAndApplyBendersOptCut(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_BENDERSCUT *benderscut, SCIP_SOL *sol, int probnumber, char *cutname, SCIP_Real objective, SCIP_Real *primalvals, SCIP_Real *consdualvals, SCIP_Real *varlbdualvals, SCIP_Real *varubdualvals, SCIP_HASHMAP *row2idx, SCIP_HASHMAP *var2idx, SCIP_BENDERSENFOTYPE type, SCIP_Bool addcut, SCIP_Bool feasibilitycut, SCIP_RESULT *result)
SCIP_RETCODE SCIPaddNlRowGradientBenderscutOpt(SCIP *masterprob, SCIP *subproblem, SCIP_BENDERS *benders, SCIP_NLROW *nlrow, SCIP_Real mult, SCIP_Real *primalvals, SCIP_HASHMAP *var2idx, SCIP_Real *dirderiv, SCIP_VAR ***vars, SCIP_Real **vals, int *nvars, int *varssize)
SCIP_RETCODE SCIPincludeBenderscutOpt(SCIP *scip, SCIP_BENDERS *benders)
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
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_Real SCIPgetActivityLinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip_copy.c:2588
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
SCIP_Real SCIPgetTransObjoffset(SCIP *scip)
Definition: scip_prob.c:1606
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3274
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
Definition: scip_prob.c:1400
int SCIPgetNFixedVars(SCIP *scip)
Definition: scip_prob.c:2705
SCIP_VAR ** SCIPgetFixedVars(SCIP *scip)
Definition: scip_prob.c:2662
SCIP_Real SCIPgetTransObjscale(SCIP *scip)
Definition: scip_prob.c:1629
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3304
int SCIPhashmapEntryGetImageInt(SCIP_HASHMAPENTRY *entry)
Definition: misc.c:3623
int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
Definition: misc.c:3584
SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
Definition: misc.c:3592
void * SCIPhashmapEntryGetOrigin(SCIP_HASHMAPENTRY *entry)
Definition: misc.c:3603
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3466
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:487
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_RETCODE SCIPgetIntParam(SCIP *scip, const char *name, int *value)
Definition: scip_param.c:269
SCIP_VAR * SCIPbendersGetAuxiliaryVar(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6213
SCIP_NLPPARAM SCIPbendersGetNLPParam(SCIP_BENDERS *benders)
Definition: benders.c:5047
SCIP_RETCODE SCIPgetBendersMasterVar(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR *var, SCIP_VAR **mappedvar)
Definition: scip_benders.c:685
const char * SCIPbendersGetName(SCIP_BENDERS *benders)
Definition: benders.c:5967
int SCIPbendersGetNSubproblems(SCIP_BENDERS *benders)
Definition: benders.c:6011
SCIP * SCIPbendersSubproblem(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6021
SCIP_RETCODE SCIPcheckBendersSubproblemOptimality(SCIP *scip, SCIP_BENDERS *benders, SCIP_SOL *sol, int probnumber, SCIP_Bool *optimal)
Definition: scip_benders.c:917
SCIP_Real SCIPbendersGetSubproblemObjval(SCIP_BENDERS *benders, int probnumber)
Definition: benders.c:6302
SCIP_Bool SCIPbendersInStrengthenRound(SCIP_BENDERS *benders)
Definition: benders.c:6550
SCIP_RETCODE SCIPincludeBenderscutBasic(SCIP *scip, SCIP_BENDERS *benders, SCIP_BENDERSCUT **benderscutptr, const char *name, const char *desc, int priority, SCIP_Bool islpcut, SCIP_DECL_BENDERSCUTEXEC((*benderscutexec)), SCIP_BENDERSCUTDATA *benderscutdata)
SCIP_RETCODE SCIPsetBenderscutFree(SCIP *scip, SCIP_BENDERSCUT *benderscut, SCIP_DECL_BENDERSCUTFREE((*benderscutfree)))
void SCIPbenderscutSetData(SCIP_BENDERSCUT *benderscut, SCIP_BENDERSCUTDATA *benderscutdata)
Definition: benderscut.c:413
const char * SCIPbenderscutGetName(SCIP_BENDERSCUT *benderscut)
Definition: benderscut.c:492
SCIP_BENDERSCUTDATA * SCIPbenderscutGetData(SCIP_BENDERSCUT *benderscut)
Definition: benderscut.c:403
SCIP_RETCODE SCIPstoreBendersCut(SCIP *scip, SCIP_BENDERS *benders, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, int nvars)
SCIP_Longint SCIPbenderscutGetNFound(SCIP_BENDERSCUT *benderscut)
Definition: benderscut.c:543
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_RETCODE SCIPsetConsDynamic(SCIP *scip, SCIP_CONS *cons, SCIP_Bool dynamic)
Definition: scip_cons.c:1449
SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable)
Definition: scip_cons.c:1474
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:336
SCIP_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:7923
SCIP_Bool SCIPcutsTightenCoefficients(SCIP *scip, SCIP_Bool cutislocal, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, int *nchgcoefs)
Definition: cuts.c:2466
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:2668
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
SCIP_RETCODE SCIPaggrRowAddCustomCons(SCIP *scip, SCIP_AGGRROW *aggrrow, int *inds, SCIP_Real *vals, int len, SCIP_Real rhs, SCIP_Real weight, int rank, SCIP_Bool local)
Definition: cuts.c:3143
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:2700
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:225
SCIP_RETCODE SCIPcalcFlowCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:11645
SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1692
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition: expriter.c:969
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition: expr.c:3972
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1457
SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2362
SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
Definition: expriter.c:858
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition: expr_var.c:424
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2376
SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
Definition: expriter.c:501
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:611
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:632
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:126
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
#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
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_RETCODE SCIPsolveNLPParam(SCIP *scip, SCIP_NLPPARAM param)
Definition: scip_nlp.c:545
int SCIPgetNNLPVars(SCIP *scip)
Definition: scip_nlp.c:201
int SCIPgetNNLPNlRows(SCIP *scip)
Definition: scip_nlp.c:341
SCIP_VAR ** SCIPgetNLPVars(SCIP *scip)
Definition: scip_nlp.c:179
SCIP_Bool SCIPhasNLPSolution(SCIP *scip)
Definition: scip_nlp.c:671
SCIP_NLROW ** SCIPgetNLPNlRows(SCIP *scip)
Definition: scip_nlp.c:319
SCIP_NLPTERMSTAT SCIPgetNLPTermstat(SCIP *scip)
Definition: scip_nlp.c:596
int SCIPnlrowGetNLinearVars(SCIP_NLROW *nlrow)
Definition: nlp.c:1864
SCIP_VAR ** SCIPnlrowGetLinearVars(SCIP_NLROW *nlrow)
Definition: nlp.c:1874
SCIP_Real SCIPnlrowGetDualsol(SCIP_NLROW *nlrow)
Definition: nlp.c:1966
SCIP_EXPR * SCIPnlrowGetExpr(SCIP_NLROW *nlrow)
Definition: nlp.c:1894
SCIP_Real * SCIPnlrowGetLinearCoefs(SCIP_NLROW *nlrow)
Definition: nlp.c:1884
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:98
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_probing.c:825
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17686
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17696
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1367
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1646
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_lp.c:1672
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17706
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2108
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:516
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:2349
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:664
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1571
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetSol(SCIP_VAR *var, SCIP_Bool getlpval)
Definition: var.c:19007
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:23662
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Real SCIPgetVarRedcost(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:2608
SCIP_Real SCIPvarGetNLPSol(SCIP_VAR *var)
Definition: var.c:24691
SCIP_Real SCIPvarGetUnchangedObj(SCIP_VAR *var)
Definition: var.c:23932
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10827
static const char * paramname[]
Definition: lpi_msk.c:5172
public methods for Benders' decomposition
public methods for Benders' decomposition cuts
public functions to work with algebraic expressions
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
public data structures and miscellaneous methods
internal miscellaneous methods for linear constraints
public methods for NLP management
public methods for problem variables
SCIP callable library.
SCIP_Real feastol
Definition: type_nlpi.h:69
SCIP_Real opttol
Definition: type_nlpi.h:70
@ SCIP_BENDERSENFOTYPE_RELAX
Definition: type_benders.h:52
@ SCIP_BENDERSENFOTYPE_LP
Definition: type_benders.h:51
@ SCIP_BENDERSENFOTYPE_CHECK
Definition: type_benders.h:54
@ SCIP_BENDERSENFOTYPE_PSEUDO
Definition: type_benders.h:53
enum SCIP_BendersEnfoType SCIP_BENDERSENFOTYPE
Definition: type_benders.h:56
struct SCIP_BenderscutData SCIP_BENDERSCUTDATA
@ SCIP_EXPRITER_DFS
Definition: type_expr.h:718
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:168
@ SCIP_NLPSOLSTAT_FEASIBLE
Definition: type_nlpi.h:162
@ SCIP_NLPSOLSTAT_LOCOPT
Definition: type_nlpi.h:161
@ SCIP_NLPSOLSTAT_GLOBOPT
Definition: type_nlpi.h:160
enum SCIP_NlpTermStat SCIP_NLPTERMSTAT
Definition: type_nlpi.h:184
@ SCIP_OBJSENSE_MINIMIZE
Definition: type_prob.h:48
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_CONSADDED
Definition: type_result.h:52
@ SCIP_SEPARATED
Definition: type_result.h:49
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_INITSOLVE
Definition: type_set.h:52
@ SCIP_STAGE_SOLVING
Definition: type_set.h:53