SCIP Doxygen Documentation
Loading...
Searching...
No Matches
sepa_mixing.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file sepa_mixing.c
26 * @ingroup DEFPLUGINS_SEPA
27 * @brief mixing/star inequality separator
28 * @author Weikun Chen
29 * @author Marc Pfetsch
30 *
31 * This separator generates cuts based on the mixing set
32 * \f[
33 * X = \{ (x,y) \in \{0,1\}^{N \cup M} \times \mathbb{R} \, : \, y \geq a_i x_i, \, \textrm{for} \, i \in N, \,
34 * y \leq u - a_i x_i, \, \textrm{for} \, i \in M, \, 0 \leq y \leq u \},
35 * \f]
36 * where \f$0 \leq a_i \leq u\f$ for all \f$i\f$. This information can be obtained directly from the variable bounds data
37 * structure. The separator will generate three classes of cuts.
38 *
39 * VLB: Let \f$T\f$ be a subset of \f$N\f$, wlog, \f$T = \{1,\ldots,r\}\f$ with \f$a_1 \leq a_2 \leq \ldots \leq a_r\f$.
40 * Let \f$a_0 = 0\f$. The mixing/star VLB cut is of the form \f$ y \geq \sum_{i=1}^r (a_i - a_{i-1})x_i \f$.
41 *
42 * VUB: Let \f$T\f$ be a subset of \f$M\f$, wlog, \f$T = \{1,\ldots,r\}\f$ with \f$a_1 \leq a_2 \leq \ldots \leq a_r\f$.
43 * Let \f$a_0 = 0\f$. The mixing/star VUB cut is of the form \f$ y \leq u - \sum_{i=1}^r (a_i - a_{i-1})x_i \f$.
44 *
45 * CONFLICT: Consider \f$i \in N\f$ and \f$j \in M\f$ with \f$a_i + a_j > u\f$. The conflict cut is
46 * \f$x_i + x_j \leq 1\f$.
47 *
48 * A small example is described in the following to see the generated cuts.
49 * \f[
50 * Y = \{ (x,y) \in \{0,1\}^{4} \times \mathbb{R} \, : \, y \geq 2x_1, \, y \geq 3x_2, \, y \leq 4 - x_3, \,
51 * y \leq 4 - 2 x_4, \, 0 \leq y \leq 4 \}.
52 * \f]
53 * In this small example, the mixing/star cuts \f$y \geq 2x_1 + x_2\f$ (VLB) and \f$y \leq 4 - x_3 - x_4\f$ (VUB) will be
54 * considered to be generated. Besides the mixing cuts, we also consider the conflict cut \f$x_1 + x_3 \leq 1\f$ (CONFLICT).
55 *
56 *
57 * For an overview see:
58 * Atamturk, A., Nemhauser, G.L. and Savelsbergh, M.W.,@n
59 * The mixed vertex packing problem.@n
60 * Mathematical Programming, 89(1), 35-53, 2000.
61 *
62 * Some remarks:
63 * - Besides the mixing inequality, we also add the conflict inequality.
64 * - Currently, the performance is bad on the neos-565672 instance.
65 * The reason is that, after adding the separator, SCIP spends a lot of time at the stage of cutting plane generation.
66 * - We do not consider sparsity of the cuts as we aim to find a most violated cut.
67 * - Besides the most violated cut we consider, we also add an additional variable to make the cut be the strongest one,
68 * even the additional variable does not contribute any to the violation.
69 *
70 */
71
72/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
73
75#include "scip/pub_implics.h"
76#include "scip/pub_lp.h"
77#include "scip/pub_message.h"
78#include "scip/pub_misc.h"
79#include "scip/pub_sepa.h"
80#include "scip/pub_var.h"
81#include "scip/scip_branch.h"
82#include "scip/scip_cut.h"
83#include "scip/scip_lp.h"
84#include "scip/scip_mem.h"
85#include "scip/scip_message.h"
86#include "scip/scip_numerics.h"
87#include "scip/scip_param.h"
88#include "scip/scip_prob.h"
89#include "scip/scip_sepa.h"
90#include "scip/scip_sol.h"
92#include "scip/scip_var.h"
93#include "scip/sepa_mixing.h"
94#include "scip/scip_tree.h"
95#include "scip/sepa_mixing.h"
96
97
98#define SEPA_NAME "mixing"
99#define SEPA_DESC "mixing inequality separator"
100#define DEFAULT_MAXROUNDS -1 /**< maximal number of mixing separation rounds per node (-1: unlimited) */
101#define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of mixing separation rounds in the root node (-1: unlimited) */
102#define SEPA_PRIORITY -50
103#define SEPA_FREQ 10
104#define SEPA_MAXBOUNDDIST 1.0
105#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
106#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
107
108#define DEFAULT_USELOCALBOUNDS FALSE /**< should local bounds be used? */
109#define DEFAULT_ISCUTSONINTS FALSE /**< should general/implicit integer variables be used to generate cuts? */
110#define DEFAULT_MAXNUNSUCCESSFUL 10 /**< maximal number of consecutive unsuccessful iterations */
111
112/** separator-specific data for the mixing separator */
113struct SCIP_SepaData
114{
115 SCIP_Bool uselocalbounds; /**< should local bounds be used? */
116 SCIP_Bool iscutsonints; /**< should general/implicit integer variables be used to generate cuts? */
117 int maxrounds; /**< maximal number of mixing separation rounds per node (-1: unlimited) */
118 int maxroundsroot; /**< maximal number of mixing separation rounds in the root node (-1: unlimited) */
119 int nunsuccessful; /**< number of consecutive unsuccessful iterations */
120 int maxnunsuccessful; /**< maximal number of consecutive unsuccessful iterations */
121};
122
123/*
124 * local methods
125 */
126
127/** adds the given cut */
128static
130 SCIP* scip, /**< SCIP data structure */
131 SCIP_SEPA* sepa, /**< separator */
132 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
133 SCIP_Real* cutcoefs, /**< coefficients of active variables in cut */
134 int* cutinds, /**< problem indices of variables in cut */
135 int cutnnz, /**< number of non-zeros in cut */
136 SCIP_Real cutrhs, /**< right hand side of cut */
137 SCIP_Bool cutislocal, /**< Is the cut only locally valid? */
138 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
139 int* ncuts /**< pointer to update number of cuts added */
140 )
141{
142 char cutname[SCIP_MAXSTRLEN];
143 SCIP_VAR** vars;
144 SCIP_ROW* cut;
145 int v;
146
147 assert(cutcoefs != NULL);
148 assert(cutinds != NULL);
149 assert(ncuts != NULL);
150 assert(cutoff != NULL);
151
152 *cutoff = FALSE;
153
154 /* get active problem variables */
156
157 /* construct cut name */
158 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "mix%" SCIP_LONGINT_FORMAT "_x%d", SCIPgetNLPs(scip), *ncuts);
159
160 /* create empty cut */
161 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs,
162 cutislocal, FALSE, TRUE) );
163
164 /* cache the row extension and only flush them if the cut gets added */
166
167 /* collect all non-zero coefficients */
168 for( v = 0; v < cutnnz; ++v )
169 {
170 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[cutinds[v]], cutcoefs[v]) );
171 }
172
173 /* flush all changes before adding the cut */
175
176 if( SCIPisCutEfficacious(scip, sol, cut) )
177 {
178 /* set cut rank */
179 SCIProwChgRank(cut, 1);
180
181#ifdef SCIP_DEBUG
182 SCIPdebugMsg(scip, "-> found cut (eff: %f): ", SCIPgetCutEfficacy(scip, sol, cut));
184#endif
185
186 if( cutislocal )
187 {
188 /* local cuts are added to the sepastore */
190 }
191 else
192 {
194 }
195 (*ncuts)++;
196 }
197
198 /* release the row */
199 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
200
201 return SCIP_OKAY;
202}
203
204/** searches and adds mixing cuts that are violated by the given solution value array
205 *
206 * This function implements a separation heuristic that runs in linear time in comparison to the quadratic exact
207 * algorithm in Atamturk et al.:
208 * - Lower and upper bounds are considered separately. Then possible conflict cuts.
209 * - Variable lower/upper bounds data are collected, i.e., the corresponding binary variables and coefficients.
210 * - These lists are sorted non-increasingly according to the solution values.
211 * - Then binary variables are added in turn as long as their coefficients increase in order to make the coefficients
212 * nonnegative. This clearly makes the cuts heuristic, since it is order dependent, but also sparser.
213 * - The procedure stops as soon as it reaches 0 solution values.
214 * - If the cut is efficious it is added.
215 *
216 * @todo Check whether one wants to sort according to the quotient of solution values and coefficients to increase the
217 * chance of having smaller coefficients in the front.
218 */
219static
221 SCIP* scip, /**< SCIP data structure */
222 SCIP_SEPA* sepa, /**< separator */
223 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
224 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
225 int* ncuts /**< pointer to store the number of generated cuts */
226 )
227{
229 SCIP_VAR* var;
230 SCIP_VAR** vars;
231 SCIP_Real* vlbmixcoefs;
232 SCIP_Real* vlbmixsols;
233 SCIP_Real* vubmixcoefs;
234 SCIP_Real* vubmixsols;
235 SCIP_Real* cutcoefs;
236 SCIP_Real cutrhs;
237 int* vlbmixinds;
238 int* vubmixinds;
239 int* cutinds;
240 int* vlbmixsigns;
241 int* vubmixsigns;
242 int firstvar;
243 int nmaxvars;
244 int nvars;
245 int i;
246 int k;
247
248 assert(sepa != NULL);
249 assert(cutoff != NULL);
250 assert(ncuts != NULL);
251
252 *cutoff = FALSE;
253 *ncuts = 0;
254
255 /* exit if there are no binary variables - ignore integer variables that have 0/1 bounds */
256 nmaxvars = SCIPgetNBinVars(scip);
257 if( nmaxvars <= 0 )
258 return SCIP_OKAY;
259
261 assert(sepadata != NULL);
262
263 /* get the index of the first considered variable */
264 if( sepadata->iscutsonints )
265 {
266 /* generate cuts based on all nonbinary variabels */
267 firstvar = SCIPgetNBinVars(scip);
268 }
269 else
270 {
271 /* only generate cuts based on continuous variables */
273 }
275 if( firstvar == nvars )
276 return SCIP_OKAY;
277
279
280 /* allocate temporary memory */
281 SCIP_CALL( SCIPallocBufferArray(scip, &vlbmixcoefs, nmaxvars) );
282 SCIP_CALL( SCIPallocBufferArray(scip, &vlbmixsols, nmaxvars) );
283 SCIP_CALL( SCIPallocBufferArray(scip, &vlbmixinds, nmaxvars) );
284 SCIP_CALL( SCIPallocBufferArray(scip, &vlbmixsigns, nmaxvars) );
285 SCIP_CALL( SCIPallocBufferArray(scip, &vubmixcoefs, nmaxvars) );
286 SCIP_CALL( SCIPallocBufferArray(scip, &vubmixsols, nmaxvars) );
287 SCIP_CALL( SCIPallocBufferArray(scip, &vubmixinds, nmaxvars) );
288 SCIP_CALL( SCIPallocBufferArray(scip, &vubmixsigns, nmaxvars) );
289 SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nmaxvars + 1) );
290 SCIP_CALL( SCIPallocBufferArray(scip, &cutinds, nmaxvars + 1) );
291
292 for( i = firstvar; i < nvars; i++ )
293 {
294 SCIP_VAR** vlbvars;
295 SCIP_Real* vlbcoefs;
296 SCIP_Real* vlbconsts;
297 SCIP_VAR** vubvars;
298 SCIP_Real* vubcoefs;
299 SCIP_Real* vubconsts;
300 SCIP_Real maxabscoef;
301 SCIP_Real activity;
302 SCIP_Real lastcoef;
303 SCIP_Real varsolval;
306 SCIP_Bool islocallb = FALSE; /* Is it a local lower bound or global lower bound? */
307 SCIP_Bool islocalub = FALSE; /* Is it a local upper bound or global upper bound? */
308 SCIP_Bool cutislocal; /* Is it a local cut or global cut? */
309 int vlbmixsize = 0;
310 int vubmixsize = 0;
311 int cutnnz = 0;
312 int maxabsind;
313 int maxabssign;
314 int nvlb;
315 int nvub;
316 int j;
317
318 var = vars[i];
320
321 if( SCIPvarGetProbindex(var) < 0 )
322 continue;
323
324 nvlb = SCIPvarGetNVlbs(var);
325 nvub = SCIPvarGetNVubs(var);
326
327 if( nvlb == 0 && nvub == 0 )
328 continue;
329
330 /* skip lower bound if the LP solution value is equal to the upper bound of the continuous variable */
331 varsolval = SCIPgetSolVal(scip, sol, var);
332 if( SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), varsolval) )
333 goto VUB;
334
335 if( nvlb == 0 )
336 goto VUB;
337
338 /* get variable lower variable bounds information */
339 vlbvars = SCIPvarGetVlbVars(var);
340 vlbcoefs = SCIPvarGetVlbCoefs(var);
341 vlbconsts = SCIPvarGetVlbConstants(var);
342
343 maxabscoef = 0.0;
344 maxabsind = -1;
345 maxabssign = 0;
346
348 if( sepadata->uselocalbounds && SCIPisLT(scip, lb, SCIPvarGetLbLocal(var)) )
349 {
350 /* this is a lcoal cut */
351 islocallb = TRUE;
353 }
354
355#ifdef SCIP_DEBUG
356 for( j = 0; j < nvlb; j++ )
357 {
358 SCIP_Real tmplb;
359
360 if( SCIPvarIsBinary(vlbvars[j]) && SCIPvarGetProbindex(vlbvars[j]) >= 0 )
361 {
362 tmplb = (vlbcoefs[j] > 0) ? vlbconsts[j] : (vlbconsts[j] + vlbcoefs[j]);
363 assert( SCIPisFeasLE(scip, tmplb, lb) );
364 }
365 }
366#endif
367
369
370 /* extract the useful variable bounds information (binary and nonredundant) */
371 for( j = 0; j < nvlb; j++ )
372 {
373 /* consider only active and binary variables */
374 if( SCIPvarIsBinary(vlbvars[j]) && SCIPvarGetProbindex(vlbvars[j]) >= 0 )
375 {
376 SCIP_Real maxactivity;
377 SCIP_Real coef;
378
379 maxactivity = (vlbcoefs[j] > 0) ? (vlbconsts[j] + vlbcoefs[j]) : vlbconsts[j];
380
381 /* skip redundant variable bound constraints */
382 if( SCIPisFeasLE(scip, maxactivity, lb) )
383 continue;
384
385 if( vlbcoefs[j] > 0 )
386 {
387 coef = maxactivity - lb;
388 vlbmixsigns[vlbmixsize] = 0;
389 }
390 else
391 {
392 coef = lb - maxactivity;
393 vlbmixsigns[vlbmixsize] = 1;
394 }
395 assert(vlbmixsize <= nvars);
396
397 vlbmixcoefs[vlbmixsize] = REALABS(coef);
398 vlbmixinds[vlbmixsize] = SCIPvarGetProbindex(vlbvars[j]);
399 vlbmixsols[vlbmixsize] = (! vlbmixsigns[vlbmixsize]) ? SCIPgetSolVal(scip, sol, vlbvars[j]) : (1.0 - SCIPgetSolVal(scip, sol, vlbvars[j]));
400
401 /* update the maximal coefficient if needed */
402 if( maxabscoef < vlbmixcoefs[vlbmixsize] )
403 {
404 maxabscoef = vlbmixcoefs[vlbmixsize];
405 maxabsind = vlbmixinds[vlbmixsize];
406 maxabssign = vlbmixsigns[vlbmixsize];
407 }
408
409 ++vlbmixsize;
410
411 /* stop if size is exceeded; possibly ignore redundant variable bounds */
412 if( vlbmixsize >= nmaxvars )
413 break;
414 }
415 }
416 assert( vlbmixsize <= nmaxvars );
417
418 /* stop if no variable lower bounds information exists */
419 if( vlbmixsize == 0 )
420 goto VUB;
421
422 /* stop if the current solution value of the transformed continuous variable is larger than the maximal coefficient */
423 if( SCIPisFeasGT(scip, varsolval - lb, maxabscoef) )
424 goto VUB;
425
426 /* sort the solution values in non-increasing order */
427 SCIPsortDownRealRealIntInt(vlbmixsols, vlbmixcoefs, vlbmixinds, vlbmixsigns, vlbmixsize);
428
429 /* add the continuous variable */
430 cutcoefs[cutnnz] = -1;
431 cutinds[cutnnz] = SCIPvarGetProbindex(var);
432 cutrhs = -lb;
433 cutnnz++;
434
435 activity = -(varsolval - lb);
436 lastcoef = 0.0;
437
438 /* loop over the variables and add the variable to the cut if its coefficient is larger than that of the last variable */
439 for( j = 0; j < vlbmixsize; j++ )
440 {
441 SCIP_Real solval;
442
443 solval = vlbmixsols[j];
444
445 /* stop if we can not find a violated cut or we reached 0 solution values */
446 if( activity + solval * (maxabscoef - lastcoef) < 0.0 || SCIPisFeasZero(scip, solval) )
447 break;
448 else
449 {
450 /* skip if we have already added a variable with bigger coefficient */
451 if( SCIPisLE(scip, vlbmixcoefs[j], lastcoef) )
452 continue;
453 else
454 {
455 activity += (vlbmixcoefs[j] - lastcoef) * solval;
456 if( vlbmixsigns[j] )
457 {
458 cutcoefs[cutnnz] = lastcoef - vlbmixcoefs[j];
459 cutrhs -= vlbmixcoefs[j] - lastcoef;
460 }
461 else
462 cutcoefs[cutnnz] = vlbmixcoefs[j] - lastcoef;
463 cutinds[cutnnz++] = vlbmixinds[j];
464 lastcoef = vlbmixcoefs[j];
465 }
466 }
467 }
468
469 /* add the variable with maximal coefficient to make sure the cut is strong enough */
470 if( SCIPisGT(scip, maxabscoef, lastcoef) )
471 {
472 /* do not update activity: either the corresponding solval is 0.0 or the cut will not become efficious */
473 if( maxabssign )
474 {
475 cutcoefs[cutnnz] = lastcoef - maxabscoef;
476 cutrhs -= maxabscoef - lastcoef;
477 }
478 else
479 cutcoefs[cutnnz] = maxabscoef - lastcoef;
480 cutinds[cutnnz++] = maxabsind;
481 }
482 assert( cutnnz <= nmaxvars + 1 );
483
484 /* add the cut if the violtion is good enough and the number of nonzero coefficients is larger than 2 */
485 if( SCIPisEfficacious(scip, activity) && cutnnz > 2 )
486 {
487 SCIP_CALL( addCut(scip, sepa, sol, cutcoefs, cutinds, cutnnz, cutrhs, islocallb, cutoff, ncuts) );
488 }
489
490 VUB:
491 if( nvub == 0 )
492 goto CONFLICT;
493
494 /* get variable upper bounds information */
495 vubvars = SCIPvarGetVubVars(var);
496 vubcoefs = SCIPvarGetVubCoefs(var);
497 vubconsts = SCIPvarGetVubConstants(var);
498
499 maxabscoef = 0.0;
500 maxabsind = -1;
501 maxabssign = 0;
502
503 /* stop if the lower bound is equal to the solution value of the continuous variable */
504 if( SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), varsolval) )
505 goto CONFLICT;
506
508 if( sepadata->uselocalbounds && SCIPisGT(scip, ub, SCIPvarGetUbLocal(var)) )
509 {
510 /* this is a lcoal cut */
511 islocalub = TRUE;
513 }
514
515#ifdef SCIP_DEBUG
516 for( j = 0; j < nvub; j++ )
517 {
518 SCIP_Real tmpub;
519
520 if( SCIPvarIsBinary(vubvars[j]) && SCIPvarGetProbindex(vubvars[j]) >= 0 )
521 {
522 tmpub = (vubcoefs[j] < 0) ? vubconsts[j] : (vubconsts[j] + vubcoefs[j]);
523 assert( SCIPisFeasGE(scip, tmpub, ub) );
524 }
525 }
526#endif
527
529
530 /* extract the useful variable bounds information (binary and nonredundant) */
531 for( j = 0; j < nvub; j++ )
532 {
533 /* consider only active and binary variables */
534 if( SCIPvarIsBinary(vubvars[j]) && SCIPvarGetProbindex(vubvars[j]) >= 0 )
535 {
536 SCIP_Real minactivity;
537 SCIP_Real coef;
538
539 minactivity = (vubcoefs[j] < 0) ? (vubconsts[j] + vubcoefs[j]) : vubconsts[j];
540
541 /* skip redundant variable bound constraints */
542 if( SCIPisFeasLE(scip, ub, minactivity) )
543 continue;
544
545 if( vubcoefs[j] > 0 )
546 {
547 coef = ub - minactivity;
548 vubmixsigns[vubmixsize] = 1;
549 }
550 else
551 {
552 coef = minactivity - ub;
553 vubmixsigns[vubmixsize] = 0;
554 }
555
556 vubmixcoefs[vubmixsize] = REALABS(coef);
557 vubmixinds[vubmixsize] = SCIPvarGetProbindex(vubvars[j]);
558 vubmixsols[vubmixsize] = (! vubmixsigns[vubmixsize]) ? SCIPgetSolVal(scip, sol, vubvars[j]): (1.0 - SCIPgetSolVal(scip, sol, vubvars[j]));
559
560 /* update the maximal coefficient if needed */
561 if( maxabscoef < vubmixcoefs[vubmixsize] )
562 {
563 maxabscoef = vubmixcoefs[vubmixsize];
564 maxabsind = vubmixinds[vubmixsize];
565 maxabssign = vubmixsigns[vubmixsize];
566 }
567
568 ++vubmixsize;
569
570 /* stop if size is exceeded; possibly ignore redundant variable bounds */
571 if( vubmixsize >= nmaxvars )
572 break;
573 }
574 }
575 assert( vubmixsize <= nmaxvars );
576
577 /* stop if no variable upper bounds information exists */
578 if( vubmixsize == 0 )
579 goto CONFLICT;
580
581 /* stop if the current solution value of transformed continuous variable is larger than the maximal coefficient */
582 if( SCIPisFeasGT(scip, ub - varsolval, maxabscoef) )
583 goto CONFLICT;
584
585 /* sort the solution values in non-increasing order */
586 SCIPsortDownRealRealIntInt(vubmixsols, vubmixcoefs, vubmixinds, vubmixsigns, vubmixsize);
587
588 /* add the continuous variables */
589 cutnnz = 0;
590 cutcoefs[cutnnz] = 1;
591 cutinds[cutnnz] = SCIPvarGetProbindex(var);
592 cutrhs = ub;
593 cutnnz++;
594
595 activity = varsolval - ub;
596 lastcoef = 0.0;
597
598 for( j = 0; j < vubmixsize; j++ )
599 {
600 SCIP_Real solval;
601
602 solval = vubmixsols[j];
603
604 /* stop if we can not find a violated cut or we reached 0 solution values */
605 if( activity + solval * (maxabscoef - lastcoef) < 0.0 || SCIPisFeasZero(scip, solval) )
606 break;
607 else
608 {
609 /* skip if we have already added a variable with bigger coefficient */
610 if( SCIPisLE(scip, vubmixcoefs[j], lastcoef) )
611 continue;
612 else
613 {
614 activity += (vubmixcoefs[j] - lastcoef) * solval;
615 if( vubmixsigns[j] )
616 {
617 cutcoefs[cutnnz] = lastcoef - vubmixcoefs[j];
618 cutrhs -= vubmixcoefs[j] - lastcoef;
619 }
620 else
621 cutcoefs[cutnnz] = vubmixcoefs[j] - lastcoef;
622 cutinds[cutnnz++] = vubmixinds[j];
623 lastcoef = vubmixcoefs[j];
624 }
625 }
626 }
627
628 /* add the variable with maximal coefficient if needed */
629 if( SCIPisGT(scip, maxabscoef, lastcoef) )
630 {
631 /* do not update activity: either the corresponding solval is 0.0 or the cut will not become efficious */
632 if( maxabssign )
633 {
634 cutcoefs[cutnnz] = lastcoef - maxabscoef;
635 cutrhs -= maxabscoef - lastcoef;
636 }
637 else
638 cutcoefs[cutnnz] = maxabscoef - lastcoef;
639 cutinds[cutnnz++] = maxabsind;
640 }
641 assert( cutnnz <= nmaxvars + 1 );
642
643 /* add the cut if the violtion is good enough and the number of nonzero coefficients is larger than 2 */
644 if( SCIPisEfficacious(scip, activity) && cutnnz > 2 )
645 {
646 SCIP_CALL( addCut(scip, sepa, sol, cutcoefs, cutinds, cutnnz, cutrhs, islocalub, cutoff, ncuts) );
647 }
648
649 CONFLICT:
650 /* combine the variable lower bounds information and upper bounds information together to generate cuts */
651 /* stop if no useful variable lower (or upper) bounds information exists */
652 if( vlbmixsize == 0 || vubmixsize == 0 )
653 continue;
654
655 assert( lb != SCIP_INVALID ); /*lint !e777*/
656 assert( ub != SCIP_INVALID ); /*lint !e777*/
657
658 cutislocal = islocallb || islocalub;
659 for( j = 0; j < vlbmixsize; j++ )
660 {
661 SCIP_Real solval;
662
663 solval = vlbmixsols[j];
664
665 /* stop if no violated cut exists */
666 if( ! SCIPisEfficacious(scip, solval + vubmixsols[0] - 1.0) )
667 break;
668
669 for( k = 0; k < vubmixsize; k++ )
670 {
671 /* only consider the inequality if its violation is good enough */
672 if( SCIPisEfficacious(scip, solval + vubmixsols[k] - 1.0) )
673 {
674 SCIP_Real tmp;
675
676 tmp = lb + vlbmixcoefs[j] + vubmixcoefs[k] - ub;
677
678 /* add the cut if it is valid */
679 if( SCIPisEfficacious(scip, tmp) )
680 {
681 cutnnz = 2;
682 cutrhs = 1.0;
683 cutcoefs[0] = vlbmixsigns[j] ? -1.0 : 1.0;
684 cutcoefs[1] = vubmixsigns[k] ? -1.0 : 1.0;
685 cutinds[0] = vlbmixinds[j];
686 cutinds[1] = vubmixinds[k];
687 cutrhs = vlbmixsigns[j] ? (cutrhs - 1.0) : cutrhs;
688 cutrhs = vubmixsigns[k] ? (cutrhs - 1.0) : cutrhs;
689 SCIP_CALL( addCut(scip, sepa, sol, cutcoefs, cutinds, cutnnz, cutrhs, cutislocal, cutoff, ncuts) );
690 }
691 }
692 else
693 break;
694 }
695 }
696 }
697
698 /* free temporary memory */
699 SCIPfreeBufferArray(scip, &cutinds);
700 SCIPfreeBufferArray(scip, &cutcoefs);
701 SCIPfreeBufferArray(scip, &vubmixsigns);
702 SCIPfreeBufferArray(scip, &vubmixinds);
703 SCIPfreeBufferArray(scip, &vubmixsols);
704 SCIPfreeBufferArray(scip, &vubmixcoefs);
705 SCIPfreeBufferArray(scip, &vlbmixsigns);
706 SCIPfreeBufferArray(scip, &vlbmixinds);
707 SCIPfreeBufferArray(scip, &vlbmixsols);
708 SCIPfreeBufferArray(scip, &vlbmixcoefs);
709
710 return SCIP_OKAY;
711}
712
713
714/*
715 * Callback methods of separator
716 */
717
718/** copy method for separator plugins (called when SCIP copies plugins) */
719static
720SCIP_DECL_SEPACOPY(sepaCopyMixing)
721{ /*lint --e{715}*/
722 assert(scip != NULL);
723 assert(sepa != NULL);
724
726
727 /* call inclusion method of separator */
729
730 return SCIP_OKAY;
731}
732
733/** destructor of separator to free user data (called when SCIP is exiting) */
734static
735SCIP_DECL_SEPAFREE(sepaFreeMixing)
736{ /*lint --e{715}*/
738
739 assert(scip != NULL);
740 assert(sepa != NULL);
741
743
744 /* get separation data and free it */
746 assert(sepadata != NULL);
748
749 /* reset data pointer to NULL */
750 SCIPsepaSetData(sepa, NULL);
751
752 return SCIP_OKAY;
753}
754
755
756/** LP solution separation method of separator */
757static
758SCIP_DECL_SEPAEXECLP(sepaExeclpMixing)
759{ /*lint --e{715}*/
762 int nbinvars;
763 int nvars;
764 int ncuts;
765 int ncalls;
766
767 assert(sepa != NULL);
768 assert(scip != NULL);
769 assert(result != NULL);
770
774 assert(sepadata != NULL);
775
776 /* only call the mixing cut separator a given number of times at each node */
777 if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
778 || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
779 return SCIP_OKAY;
780
781 /* gets numver of active problem variables and number of binary variables */
782 SCIP_CALL( SCIPgetVarsData(scip, NULL, &nvars, &nbinvars, NULL, NULL, NULL) );
783
784 /* if all the active problem variables are binary, stop */
785 if( nvars == nbinvars )
786 return SCIP_OKAY;
787
788 /* call the cut separation */
789 SCIP_CALL( separateCuts(scip, sepa, NULL, &cutoff, &ncuts) );
790
791 /* adjust result code */
792 if( cutoff )
794 else if( ncuts > 0 )
795 {
796 SCIPdebugMsg(scip, "mixing separator generated %d cuts.\n", ncuts);
798 }
799 else
801
802 return SCIP_OKAY;
803}
804
805/** arbitrary primal solution separation method of separator */
806static
807SCIP_DECL_SEPAEXECSOL(sepaExecSolMixing)
808{ /*lint --e{715}*/
811 int nbinvars;
812 int nvars;
813 int ncuts;
814 int ncalls;
815
816 assert(sepa != NULL);
817 assert(scip != NULL);
818 assert(result != NULL);
819
822 assert(sepadata != NULL);
823
824 /* do not run if we have reached the maximal number of consecutive unsuccessful calls */
825 if( sepadata->nunsuccessful >= sepadata->maxnunsuccessful )
826 return SCIP_OKAY;
827
828 /* only call the mixing cut separator a given number of times at each node */
830 if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
831 || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
832 return SCIP_OKAY;
833
834 /* gets numver of active problem variables and number of binary variables */
836 nbinvars = SCIPgetNBinVars(scip);
837
838 /* if all the active problem variables are binary, stop */
839 if( nvars == nbinvars )
840 return SCIP_OKAY;
841
842 /* call the cut separation */
843 SCIP_CALL( separateCuts(scip, sepa, sol, &cutoff, &ncuts) );
844
845 /* adjust result code */
846 if( cutoff )
847 {
848 sepadata->nunsuccessful = 0;
850 }
851 else if( ncuts > 0 )
852 {
853 SCIPdebugMsg(scip, "mixing separator generated %d cuts.\n", ncuts);
854 sepadata->nunsuccessful = 0;
856 }
857 else
858 {
859 ++sepadata->nunsuccessful;
861 }
862
863 return SCIP_OKAY;
864}
865
866
867/*
868 * separator specific interface methods
869 */
870
871/** creates the mixing separator and includes it in SCIP */
873 SCIP* scip /**< SCIP data structure */
874 )
875{
877 SCIP_SEPA* sepa;
878
879 /* create mixing separator data */
881 assert(sepadata != NULL);
882 sepadata->nunsuccessful = 0;
883
884 /* include separator */
887 sepaExeclpMixing, sepaExecSolMixing,
888 sepadata) );
889 assert(sepa != NULL);
890
891 /* set non-NULL pointers to callback methods */
892 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyMixing) );
893 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeMixing) );
894
895 /* add separator parameters */
896 SCIP_CALL( SCIPaddBoolParam(scip, "separating/mixing/uselocalbounds",
897 "Should local bounds be used?",
898 &sepadata->uselocalbounds, TRUE, DEFAULT_USELOCALBOUNDS, NULL, NULL) );
899
900 SCIP_CALL( SCIPaddBoolParam(scip, "separating/mixing/iscutsonints",
901 "Should general integer variables be used to generate cuts?",
902 &sepadata->iscutsonints, TRUE, DEFAULT_ISCUTSONINTS, NULL, NULL) );
903
904 SCIP_CALL( SCIPaddIntParam(scip, "separating/mixing/maxrounds",
905 "maximal number of mixing separation rounds per node (-1: unlimited)",
906 &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
907
908 SCIP_CALL( SCIPaddIntParam(scip, "separating/mixing/maxroundsroot",
909 "maximal number of mixing separation rounds in the root node (-1: unlimited)",
910 &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
911
912 SCIP_CALL( SCIPaddIntParam(scip, "separating/mixing/maxnunsuccessful",
913 "maximal number of consecutive unsuccessful iterations",
914 &sepadata->maxnunsuccessful, FALSE, DEFAULT_MAXNUNSUCCESSFUL, -1, INT_MAX, NULL, NULL) );
915
916 return SCIP_OKAY;
917}
#define DEFAULT_MAXROUNDSROOT
#define DEFAULT_MAXROUNDS
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_INVALID
Definition def.h:187
#define SCIP_Bool
Definition def.h:100
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define SCIP_LONGINT_FORMAT
Definition def.h:157
#define REALABS(x)
Definition def.h:191
#define SCIP_CALL(x)
Definition def.h:364
int SCIPgetNIntVars(SCIP *scip)
Definition scip_prob.c:2340
int SCIPgetNBinImplVars(SCIP *scip)
Definition scip_prob.c:2432
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition scip_prob.c:2115
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
int SCIPgetNIntImplVars(SCIP *scip)
Definition scip_prob.c:2477
int SCIPgetNBinVars(SCIP *scip)
Definition scip_prob.c:2293
#define SCIPdebugMsg
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, 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 scip_param.c:83
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 SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition scip_cut.c:336
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:94
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:117
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition scip_cut.c:135
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:225
#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
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1429
void SCIProwChgRank(SCIP_ROW *row, int rank)
Definition lp.c:17928
SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
Definition scip_sepa.c:115
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:173
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition sepa.c:746
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition sepa.c:893
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition sepa.c:636
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition sepa.c:646
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:157
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
SCIP_Longint SCIPgetNLPs(SCIP *scip)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition var.c:24514
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition var.c:24536
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23510
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition var.c:23530
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23485
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:23694
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition var.c:24546
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition var.c:24556
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition var.c:24526
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition var.c:24588
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition var.c:24568
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition var.c:24578
SCIP_RETCODE SCIPincludeSepaMixing(SCIP *scip)
void SCIPsortDownRealRealIntInt(SCIP_Real *realarray1, SCIP_Real *realarray2, int *intarray1, int *intarray2, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
return SCIP_OKAY
SCIP_Longint ncalls
int depth
SCIP_Bool cutoff
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_VAR ** vars
memory allocation routines
public methods for implications, variable bounds, and cliques
public methods for LP management
public methods for message output
public data structures and miscellaneous methods
public methods for separators
public methods for problem variables
public methods for branching rule plugins and branching
public methods for cuts and aggregation rows
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for separator plugins
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
#define SEPA_PRIORITY
#define SEPA_DELAY
#define SEPA_DESC
#define SEPA_USESSUBSCIP
#define SEPA_MAXBOUNDDIST
#define SEPA_FREQ
#define SEPA_NAME
static SCIP_RETCODE addCut(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_Real *cutcoefs, int *cutinds, int cutnnz, SCIP_Real cutrhs, SCIP_Bool cutislocal, SCIP_Bool *cutoff, int *ncuts)
#define DEFAULT_MAXNUNSUCCESSFUL
static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
#define DEFAULT_USELOCALBOUNDS
#define DEFAULT_ISCUTSONINTS
mixing cuts separator
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_SepaData SCIP_SEPADATA
Definition type_sepa.h:52
#define SCIP_DECL_SEPAEXECSOL(x)
Definition type_sepa.h:166
#define SCIP_DECL_SEPAEXECLP(x)
Definition type_sepa.h:136
#define SCIP_DECL_SEPAFREE(x)
Definition type_sepa.h:69
struct SCIP_Sepa SCIP_SEPA
Definition type_sepa.h:51
#define SCIP_DECL_SEPACOPY(x)
Definition type_sepa.h:61
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64